From ee08f3b14d534520a7b60c1a334815db1c1254da Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Fri, 7 Mar 2025 14:59:32 +0200 Subject: [PATCH 01/15] Remove restaking (#102) * Remove restake vaults * Remove CumulativeMerkleDrop * Remove redundant error --- abi/Errors.json | 10 - abi/ICumulativeMerkleDrop.json | 117 -- abi/IEigenDelayedWithdrawalRouter.json | 15 - abi/IEigenDelegationManager.json | 195 -- abi/IEigenPod.json | 204 -- abi/IEigenPodManager.json | 15 - abi/IEigenPodOwner.json | 394 ---- abi/IEthRestakeBlocklistErc20Vault.json | 1463 -------------- abi/IEthRestakeBlocklistVault.json | 1166 ----------- abi/IEthRestakeErc20Vault.json | 1356 ------------- abi/IEthRestakePrivErc20Vault.json | 1463 -------------- abi/IEthRestakePrivVault.json | 1166 ----------- abi/IEthRestakeVault.json | 1059 ---------- abi/IEthRestakeVaultFactory.json | 101 - abi/IVaultEthRestaking.json | 975 --------- .../interfaces/ICumulativeMerkleDrop.sol | 61 - .../IEigenDelayedWithdrawalRouter.sol | 16 - .../interfaces/IEigenDelegationManager.sol | 126 -- contracts/interfaces/IEigenPod.sol | 91 - contracts/interfaces/IEigenPodManager.sol | 17 - contracts/interfaces/IEigenPodOwner.sol | 137 -- .../IEthRestakeBlocklistErc20Vault.sol | 13 - .../interfaces/IEthRestakeBlocklistVault.sol | 13 - .../interfaces/IEthRestakeErc20Vault.sol | 56 - .../interfaces/IEthRestakePrivErc20Vault.sol | 13 - contracts/interfaces/IEthRestakePrivVault.sol | 13 - contracts/interfaces/IEthRestakeVault.sol | 50 - .../interfaces/IEthRestakeVaultFactory.sol | 55 - contracts/interfaces/IVaultEthRestaking.sol | 67 - contracts/libraries/Errors.sol | 2 - contracts/misc/CumulativeMerkleDrop.sol | 69 - contracts/mocks/EigenPodOwnerV2Mock.sol | 20 - .../vaults/ethereum/restake/EigenPodOwner.sol | 245 --- .../restake/EthRestakeBlocklistErc20Vault.sol | 145 -- .../restake/EthRestakeBlocklistVault.sol | 122 -- .../ethereum/restake/EthRestakeErc20Vault.sol | 210 -- .../restake/EthRestakePrivErc20Vault.sol | 145 -- .../ethereum/restake/EthRestakePrivVault.sol | 125 -- .../ethereum/restake/EthRestakeVault.sol | 179 -- .../restake/EthRestakeVaultFactory.sol | 82 - .../vaults/modules/VaultEthRestaking.sol | 165 -- deployments/holesky.json | 3 +- deployments/mainnet.json | 1 - helpers/constants.ts | 40 - helpers/types.ts | 10 - tasks/eth-full-deploy-local.ts | 72 - tasks/eth-full-deploy.ts | 80 - tasks/eth-upgrade.ts | 2 - test/CumulativeMerkleDrop.spec.ts | 124 -- .../CumulativeMerkleDrop.spec.ts.snap | 15 - test/restake/EigenPodOwner.spec.ts | 273 --- .../EthRestakeBlocklistErc20Vault.spec.ts | 146 -- test/restake/EthRestakeBlocklistVault.spec.ts | 108 - test/restake/EthRestakeErc20Vault.spec.ts | 100 - test/restake/EthRestakePrivErc20Vault.spec.ts | 147 -- test/restake/EthRestakePrivVault.spec.ts | 106 - test/restake/EthRestakeVault.spec.ts | 350 ---- test/restake/EthRestakeVault.upgrade.spec.ts | 149 -- test/restake/EthRestakeVaultFactory.spec.ts | 310 --- .../__snapshots__/EigenPodOwner.spec.ts.snap | 43 - ...EthRestakeBlocklistErc20Vault.spec.ts.snap | 22 - .../EthRestakeBlocklistVault.spec.ts.snap | 15 - .../EthRestakeErc20Vault.spec.ts.snap | 15 - .../EthRestakePrivErc20Vault.spec.ts.snap | 22 - .../EthRestakePrivVault.spec.ts.snap | 15 - .../EthRestakeVault.spec.ts.snap | 36 - .../EthRestakeVault.upgrade.spec.ts.snap | 43 - .../EthRestakeVaultFactory.spec.ts.snap | 57 - .../EigenDelayedWithdrawalRouter.json | 3 - .../artifacts/EigenDelegationManager.json | 3 - test/shared/artifacts/EigenPodManager.json | 3 - .../EthRestakeBlocklistErc20Vault.json | 1779 ----------------- .../artifacts/EthRestakeBlocklistVault.json | 1467 -------------- .../artifacts/EthRestakeErc20Vault.json | 1672 ---------------- .../artifacts/EthRestakePrivErc20Vault.json | 1779 ----------------- .../shared/artifacts/EthRestakePrivVault.json | 1467 -------------- test/shared/artifacts/EthRestakeVault.json | 1360 ------------- test/shared/contracts.ts | 39 - test/shared/fixtures.ts | 33 +- test/shared/restakeFixtures.ts | 423 ---- test/shared/rewards.ts | 4 +- test/shared/types.ts | 28 - test/shared/validators.ts | 23 +- 83 files changed, 12 insertions(+), 24311 deletions(-) delete mode 100644 abi/ICumulativeMerkleDrop.json delete mode 100644 abi/IEigenDelayedWithdrawalRouter.json delete mode 100644 abi/IEigenDelegationManager.json delete mode 100644 abi/IEigenPod.json delete mode 100644 abi/IEigenPodManager.json delete mode 100644 abi/IEigenPodOwner.json delete mode 100644 abi/IEthRestakeBlocklistErc20Vault.json delete mode 100644 abi/IEthRestakeBlocklistVault.json delete mode 100644 abi/IEthRestakeErc20Vault.json delete mode 100644 abi/IEthRestakePrivErc20Vault.json delete mode 100644 abi/IEthRestakePrivVault.json delete mode 100644 abi/IEthRestakeVault.json delete mode 100644 abi/IEthRestakeVaultFactory.json delete mode 100644 abi/IVaultEthRestaking.json delete mode 100644 contracts/interfaces/ICumulativeMerkleDrop.sol delete mode 100644 contracts/interfaces/IEigenDelayedWithdrawalRouter.sol delete mode 100644 contracts/interfaces/IEigenDelegationManager.sol delete mode 100644 contracts/interfaces/IEigenPod.sol delete mode 100644 contracts/interfaces/IEigenPodManager.sol delete mode 100644 contracts/interfaces/IEigenPodOwner.sol delete mode 100644 contracts/interfaces/IEthRestakeBlocklistErc20Vault.sol delete mode 100644 contracts/interfaces/IEthRestakeBlocklistVault.sol delete mode 100644 contracts/interfaces/IEthRestakeErc20Vault.sol delete mode 100644 contracts/interfaces/IEthRestakePrivErc20Vault.sol delete mode 100644 contracts/interfaces/IEthRestakePrivVault.sol delete mode 100644 contracts/interfaces/IEthRestakeVault.sol delete mode 100644 contracts/interfaces/IEthRestakeVaultFactory.sol delete mode 100644 contracts/interfaces/IVaultEthRestaking.sol delete mode 100644 contracts/misc/CumulativeMerkleDrop.sol delete mode 100644 contracts/mocks/EigenPodOwnerV2Mock.sol delete mode 100644 contracts/vaults/ethereum/restake/EigenPodOwner.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakePrivVault.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakeVault.sol delete mode 100644 contracts/vaults/ethereum/restake/EthRestakeVaultFactory.sol delete mode 100644 contracts/vaults/modules/VaultEthRestaking.sol delete mode 100644 test/CumulativeMerkleDrop.spec.ts delete mode 100644 test/__snapshots__/CumulativeMerkleDrop.spec.ts.snap delete mode 100644 test/restake/EigenPodOwner.spec.ts delete mode 100644 test/restake/EthRestakeBlocklistErc20Vault.spec.ts delete mode 100644 test/restake/EthRestakeBlocklistVault.spec.ts delete mode 100644 test/restake/EthRestakeErc20Vault.spec.ts delete mode 100644 test/restake/EthRestakePrivErc20Vault.spec.ts delete mode 100644 test/restake/EthRestakePrivVault.spec.ts delete mode 100644 test/restake/EthRestakeVault.spec.ts delete mode 100644 test/restake/EthRestakeVault.upgrade.spec.ts delete mode 100644 test/restake/EthRestakeVaultFactory.spec.ts delete mode 100644 test/restake/__snapshots__/EigenPodOwner.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakeBlocklistErc20Vault.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakeBlocklistVault.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakeErc20Vault.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakePrivErc20Vault.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakePrivVault.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakeVault.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakeVault.upgrade.spec.ts.snap delete mode 100644 test/restake/__snapshots__/EthRestakeVaultFactory.spec.ts.snap delete mode 100644 test/shared/artifacts/EigenDelayedWithdrawalRouter.json delete mode 100644 test/shared/artifacts/EigenDelegationManager.json delete mode 100644 test/shared/artifacts/EigenPodManager.json delete mode 100644 test/shared/artifacts/EthRestakeBlocklistErc20Vault.json delete mode 100644 test/shared/artifacts/EthRestakeBlocklistVault.json delete mode 100644 test/shared/artifacts/EthRestakeErc20Vault.json delete mode 100644 test/shared/artifacts/EthRestakePrivErc20Vault.json delete mode 100644 test/shared/artifacts/EthRestakePrivVault.json delete mode 100644 test/shared/artifacts/EthRestakeVault.json delete mode 100644 test/shared/restakeFixtures.ts diff --git a/abi/Errors.json b/abi/Errors.json index 2409df37..2519ffee 100644 --- a/abi/Errors.json +++ b/abi/Errors.json @@ -24,11 +24,6 @@ "name": "DeadlineExpired", "type": "error" }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, { "inputs": [], "name": "ExitRequestNotProcessed", @@ -169,11 +164,6 @@ "name": "InvalidVault", "type": "error" }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, { "inputs": [], "name": "LiquidationDisabled", diff --git a/abi/ICumulativeMerkleDrop.json b/abi/ICumulativeMerkleDrop.json deleted file mode 100644 index ae369fb5..00000000 --- a/abi/ICumulativeMerkleDrop.json +++ /dev/null @@ -1,117 +0,0 @@ -[ - { - "inputs": [], - "name": "AlreadyClaimed", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidProof", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "cumulativeAmount", - "type": "uint256" - } - ], - "name": "Claimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "merkleRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "string", - "name": "proofsIpfsHash", - "type": "string" - } - ], - "name": "MerkleRootUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "cumulativeAmount", - "type": "uint256" - }, - { - "internalType": "bytes32[]", - "name": "merkleProof", - "type": "bytes32[]" - } - ], - "name": "claim", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "merkleRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_merkleRoot", - "type": "bytes32" - }, - { - "internalType": "string", - "name": "proofsIpfsHash", - "type": "string" - } - ], - "name": "setMerkleRoot", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "token", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEigenDelayedWithdrawalRouter.json b/abi/IEigenDelayedWithdrawalRouter.json deleted file mode 100644 index 5334062f..00000000 --- a/abi/IEigenDelayedWithdrawalRouter.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxNumberOfWithdrawalsToClaim", - "type": "uint256" - } - ], - "name": "claimDelayedWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEigenDelegationManager.json b/abi/IEigenDelegationManager.json deleted file mode 100644 index 50178320..00000000 --- a/abi/IEigenDelegationManager.json +++ /dev/null @@ -1,195 +0,0 @@ -[ - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "staker", - "type": "address" - }, - { - "internalType": "address", - "name": "delegatedTo", - "type": "address" - }, - { - "internalType": "address", - "name": "withdrawer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "startBlock", - "type": "uint32" - }, - { - "internalType": "address[]", - "name": "strategies", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "shares", - "type": "uint256[]" - } - ], - "internalType": "struct IEigenDelegationManager.Withdrawal", - "name": "withdrawal", - "type": "tuple" - }, - { - "internalType": "address[]", - "name": "tokens", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "middlewareTimesIndex", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "receiveAsTokens", - "type": "bool" - } - ], - "name": "completeQueuedWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - } - ], - "internalType": "struct IEigenDelegationManager.SignatureWithExpiry", - "name": "approverSignatureAndExpiry", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "approverSalt", - "type": "bytes32" - } - ], - "name": "delegateTo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "delegatedTo", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "pendingWithdrawals", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address[]", - "name": "strategies", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "shares", - "type": "uint256[]" - }, - { - "internalType": "address", - "name": "withdrawer", - "type": "address" - } - ], - "internalType": "struct IEigenDelegationManager.QueuedWithdrawalParams[]", - "name": "queuedWithdrawalParams", - "type": "tuple[]" - } - ], - "name": "queueWithdrawals", - "outputs": [ - { - "internalType": "bytes32[]", - "name": "", - "type": "bytes32[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "undelegate", - "outputs": [ - { - "internalType": "bytes32[]", - "name": "withdrawalRoot", - "type": "bytes32[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEigenPod.json b/abi/IEigenPod.json deleted file mode 100644 index 02327939..00000000 --- a/abi/IEigenPod.json +++ /dev/null @@ -1,204 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "oracleTimestamp", - "type": "uint64" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "beaconStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "internalType": "struct IEigenPod.StateRootProof", - "name": "stateRootProof", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes", - "name": "withdrawalProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "slotProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "executionPayloadProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "timestampProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "historicalSummaryBlockRootProof", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "blockRootIndex", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "historicalSummaryIndex", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "withdrawalIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "blockRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "slotRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "timestampRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "executionPayloadRoot", - "type": "bytes32" - } - ], - "internalType": "struct IEigenPod.WithdrawalProof[]", - "name": "withdrawalProofs", - "type": "tuple[]" - }, - { - "internalType": "bytes[]", - "name": "validatorFieldsProofs", - "type": "bytes[]" - }, - { - "internalType": "bytes32[][]", - "name": "validatorFields", - "type": "bytes32[][]" - }, - { - "internalType": "bytes32[][]", - "name": "withdrawalFields", - "type": "bytes32[][]" - } - ], - "name": "verifyAndProcessWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "oracleTimestamp", - "type": "uint64" - }, - { - "internalType": "uint40[]", - "name": "validatorIndices", - "type": "uint40[]" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "beaconStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "internalType": "struct IEigenPod.StateRootProof", - "name": "stateRootProof", - "type": "tuple" - }, - { - "internalType": "bytes[]", - "name": "validatorFieldsProofs", - "type": "bytes[]" - }, - { - "internalType": "bytes32[][]", - "name": "validatorFields", - "type": "bytes32[][]" - } - ], - "name": "verifyBalanceUpdates", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "oracleTimestamp", - "type": "uint64" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "beaconStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "internalType": "struct IEigenPod.StateRootProof", - "name": "stateRootProof", - "type": "tuple" - }, - { - "internalType": "uint40[]", - "name": "validatorIndices", - "type": "uint40[]" - }, - { - "internalType": "bytes[]", - "name": "validatorFieldsProofs", - "type": "bytes[]" - }, - { - "internalType": "bytes32[][]", - "name": "validatorFields", - "type": "bytes32[][]" - } - ], - "name": "verifyWithdrawalCredentials", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEigenPodManager.json b/abi/IEigenPodManager.json deleted file mode 100644 index 63e0d082..00000000 --- a/abi/IEigenPodManager.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "inputs": [], - "name": "createPod", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEigenPodOwner.json b/abi/IEigenPodOwner.json deleted file mode 100644 index 63da66b4..00000000 --- a/abi/IEigenPodOwner.json +++ /dev/null @@ -1,394 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxNumberOfDelayedWithdrawalsToClaim", - "type": "uint256" - } - ], - "name": "claimDelayedWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "delegatedTo", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "startBlock", - "type": "uint32" - }, - { - "internalType": "uint256", - "name": "middlewareTimesIndex", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "receiveAsTokens", - "type": "bool" - } - ], - "name": "completeQueuedWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - } - ], - "internalType": "struct IEigenDelegationManager.SignatureWithExpiry", - "name": "approverSignatureAndExpiry", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "approverSalt", - "type": "bytes32" - } - ], - "name": "delegateTo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "eigenPod", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "queueWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "undelegate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "vault", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "oracleTimestamp", - "type": "uint64" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "beaconStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "internalType": "struct IEigenPod.StateRootProof", - "name": "stateRootProof", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "bytes", - "name": "withdrawalProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "slotProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "executionPayloadProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "timestampProof", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "historicalSummaryBlockRootProof", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "blockRootIndex", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "historicalSummaryIndex", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "withdrawalIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "blockRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "slotRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "timestampRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "executionPayloadRoot", - "type": "bytes32" - } - ], - "internalType": "struct IEigenPod.WithdrawalProof[]", - "name": "withdrawalProofs", - "type": "tuple[]" - }, - { - "internalType": "bytes[]", - "name": "validatorFieldsProofs", - "type": "bytes[]" - }, - { - "internalType": "bytes32[][]", - "name": "validatorFields", - "type": "bytes32[][]" - }, - { - "internalType": "bytes32[][]", - "name": "withdrawalFields", - "type": "bytes32[][]" - } - ], - "name": "verifyAndProcessWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "oracleTimestamp", - "type": "uint64" - }, - { - "internalType": "uint40[]", - "name": "validatorIndices", - "type": "uint40[]" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "beaconStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "internalType": "struct IEigenPod.StateRootProof", - "name": "stateRootProof", - "type": "tuple" - }, - { - "internalType": "bytes[]", - "name": "validatorFieldsProofs", - "type": "bytes[]" - }, - { - "internalType": "bytes32[][]", - "name": "validatorFields", - "type": "bytes32[][]" - } - ], - "name": "verifyBalanceUpdates", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "oracleTimestamp", - "type": "uint64" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "beaconStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "internalType": "struct IEigenPod.StateRootProof", - "name": "stateRootProof", - "type": "tuple" - }, - { - "internalType": "uint40[]", - "name": "validatorIndices", - "type": "uint40[]" - }, - { - "internalType": "bytes[]", - "name": "validatorFieldsProofs", - "type": "bytes[]" - }, - { - "internalType": "bytes32[][]", - "name": "validatorFields", - "type": "bytes32[][]" - } - ], - "name": "verifyWithdrawalCredentials", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEthRestakeBlocklistErc20Vault.json b/abi/IEthRestakeBlocklistErc20Vault.json deleted file mode 100644 index bf782ef9..00000000 --- a/abi/IEthRestakeBlocklistErc20Vault.json +++ /dev/null @@ -1,1463 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthRestakeBlocklistVault.json b/abi/IEthRestakeBlocklistVault.json deleted file mode 100644 index 17d4eb06..00000000 --- a/abi/IEthRestakeBlocklistVault.json +++ /dev/null @@ -1,1166 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthRestakeErc20Vault.json b/abi/IEthRestakeErc20Vault.json deleted file mode 100644 index 6d363125..00000000 --- a/abi/IEthRestakeErc20Vault.json +++ /dev/null @@ -1,1356 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthRestakePrivErc20Vault.json b/abi/IEthRestakePrivErc20Vault.json deleted file mode 100644 index c20313fb..00000000 --- a/abi/IEthRestakePrivErc20Vault.json +++ /dev/null @@ -1,1463 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthRestakePrivVault.json b/abi/IEthRestakePrivVault.json deleted file mode 100644 index 743f3e90..00000000 --- a/abi/IEthRestakePrivVault.json +++ /dev/null @@ -1,1166 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthRestakeVault.json b/abi/IEthRestakeVault.json deleted file mode 100644 index 7524ff0c..00000000 --- a/abi/IEthRestakeVault.json +++ /dev/null @@ -1,1059 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthRestakeVaultFactory.json b/abi/IEthRestakeVaultFactory.json deleted file mode 100644 index 7fda0bbf..00000000 --- a/abi/IEthRestakeVaultFactory.json +++ /dev/null @@ -1,101 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "ownMevEscrow", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "VaultCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "isOwnMevEscrow", - "type": "bool" - } - ], - "name": "createVault", - "outputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ownMevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultEthRestaking.json b/abi/IVaultEthRestaking.json deleted file mode 100644 index 8d6a62b9..00000000 --- a/abi/IVaultEthRestaking.json +++ /dev/null @@ -1,975 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/contracts/interfaces/ICumulativeMerkleDrop.sol b/contracts/interfaces/ICumulativeMerkleDrop.sol deleted file mode 100644 index 5e9273a2..00000000 --- a/contracts/interfaces/ICumulativeMerkleDrop.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -/** - * @title ICumulativeMerkleDrop - * @author StakeWise - * @notice Defines the interface for the CumulativeMerkleDrop contract - */ -interface ICumulativeMerkleDrop { - // Custom errors - error InvalidProof(); - error AlreadyClaimed(); - - /** - * @notice Event emitted when the Merkle root is updated - * @param merkleRoot The new Merkle root hash - * @param proofsIpfsHash The IPFS hash with the Merkle tree proofs - */ - event MerkleRootUpdated(bytes32 indexed merkleRoot, string proofsIpfsHash); - - /** - * @notice Event emitted when tokens are claimed - * @param account The address of the account that claimed tokens - * @param cumulativeAmount The cumulative amount of tokens claimed so far - */ - event Claimed(address indexed account, uint256 cumulativeAmount); - - /** - * @notice The address of the distribution token - * @return The address of the token contract - */ - function token() external returns (IERC20); - - /** - * @notice The current Merkle root - * @return The Merkle root hash - */ - function merkleRoot() external returns (bytes32); - - /** - * @notice Function for updating the Merkle root of the distribution. Can only be called by the owner. - * @param _merkleRoot The new Merkle root hash - * @param proofsIpfsHash The IPFS hash with the Merkle tree proofs - */ - function setMerkleRoot(bytes32 _merkleRoot, string calldata proofsIpfsHash) external; - - /** - * @notice Function for claiming tokens from the distribution - * @param account The address of the account to claim tokens for - * @param cumulativeAmount The cumulative amount of tokens to claim - * @param merkleProof The Merkle proof for the distribution - */ - function claim( - address account, - uint256 cumulativeAmount, - bytes32[] calldata merkleProof - ) external; -} diff --git a/contracts/interfaces/IEigenDelayedWithdrawalRouter.sol b/contracts/interfaces/IEigenDelayedWithdrawalRouter.sol deleted file mode 100644 index 694ca4bf..00000000 --- a/contracts/interfaces/IEigenDelayedWithdrawalRouter.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IEigenDelayedWithdrawalRouter - * @author StakeWise - * @notice Defines the interface for the EigenDelayedWithdrawalRouter contract - */ -interface IEigenDelayedWithdrawalRouter { - /** - * @notice Called in order to withdraw delayed withdrawals made to the caller that have passed the `withdrawalDelayBlocks` period. - * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming. - */ - function claimDelayedWithdrawals(uint256 maxNumberOfWithdrawalsToClaim) external; -} diff --git a/contracts/interfaces/IEigenDelegationManager.sol b/contracts/interfaces/IEigenDelegationManager.sol deleted file mode 100644 index b5eb008d..00000000 --- a/contracts/interfaces/IEigenDelegationManager.sol +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IEigenDelegationManager - * @author StakeWise - * @notice Defines the interface for the EigenDelegationManager contract - */ -interface IEigenDelegationManager { - // @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for stack management. - struct SignatureWithExpiry { - // the signature itself, formatted as a single bytes object - bytes signature; - // the expiration timestamp (UTC) of the signature - uint256 expiry; - } - - /** - * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored. - * In functions that operate on existing queued withdrawals -- e.g. completeQueuedWithdrawal`, the data is resubmitted and the hash of the submitted - * data is computed by `calculateWithdrawalRoot` and checked against the stored hash in order to confirm the integrity of the submitted data. - */ - struct Withdrawal { - // The address that originated the Withdrawal - address staker; - // The address that the staker was delegated to at the time that the Withdrawal was created - address delegatedTo; - // The address that can complete the Withdrawal + will receive funds when completing the withdrawal - address withdrawer; - // Nonce used to guarantee that otherwise identical withdrawals have unique hashes - uint256 nonce; - // Block number when the Withdrawal was created - uint32 startBlock; - // Array of strategies that the Withdrawal contains - address[] strategies; - // Array containing the amount of shares in each Strategy in the `strategies` array - uint256[] shares; - } - - struct QueuedWithdrawalParams { - // Array of strategies that the QueuedWithdrawal contains - address[] strategies; - // Array containing the amount of shares in each Strategy in the `strategies` array - uint256[] shares; - // The address of the withdrawer - address withdrawer; - } - - /** - * @notice Returns the address of the operator that `staker` is delegated to. - * @param staker The address of the staker to check. - * @return The address of the operator that `staker` is delegated to. Returns address(0) if the staker is not delegated to any operator. - */ - function delegatedTo(address staker) external view returns (address); - - /** - * @notice Returns whether a withdrawal is pending. - * @param withdrawalRoot The hash of the withdrawal data. - * @return Whether the withdrawal is pending. - */ - function pendingWithdrawals(bytes32 withdrawalRoot) external view returns (bool); - - /** - * @notice Caller delegates their stake to an operator. - * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer. - * @param approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param approverSalt A unique single use value tied to an individual signature. - * @dev The approverSignatureAndExpiry is used in the event that: - * 1) the operator's `delegationApprover` address is set to a non-zero value. - * AND - * 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator - * or their delegationApprover is the `msg.sender`, then approval is assumed. - * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input - * in this case to save on complexity + gas costs - */ - function delegateTo( - address operator, - SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) external; - - /** - * @notice Undelegates the staker from the operator who they are delegated to. Puts the staker into the "undelegation limbo" mode of the EigenPodManager. - * and queues a withdrawal of all of the staker's shares in the StrategyManager (to the staker), if necessary. - * @param staker The account to be undelegated. - * @return withdrawalRoot The root of the newly queued withdrawal, if a withdrawal was queued. Otherwise just bytes32(0). - * - * @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves. - * @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover" - * @dev Reverts if the `staker` is already undelegated. - */ - function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot); - - /** - * Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed - * from the staker. If the staker is delegated, withdrawn shares/strategies are also removed from - * their operator. - * - * All withdrawn shares/strategies are placed in a queue and can be fully withdrawn after a delay. - */ - function queueWithdrawals( - QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) external returns (bytes32[] memory); - - /** - * @notice Used to complete the specified `withdrawal`. The caller must match `withdrawal.withdrawer` - * @param withdrawal The Withdrawal to complete. - * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array. - * This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused) - * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array - * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified strategies themselves - * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies - * will simply be transferred to the caller directly. - * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw` - * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and `withdrawal.withdrawer != withdrawal.staker`, note that - * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred to the withdrawer, unlike shares in - * any other strategies, which will be transferred to the withdrawer. - */ - function completeQueuedWithdrawal( - Withdrawal calldata withdrawal, - address[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external; -} diff --git a/contracts/interfaces/IEigenPod.sol b/contracts/interfaces/IEigenPod.sol deleted file mode 100644 index 608b6d38..00000000 --- a/contracts/interfaces/IEigenPod.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IEigenPod - * @author StakeWise - * @notice Defines the interface for the EigenPod contract - */ -interface IEigenPod { - /** - * @notice This struct contains the root and proof for verifying the state root against the oracle block root - * @param beaconStateRoot The state root of the beacon chain - * @param proof The proof of the state root against the oracle block root - */ - struct StateRootProof { - bytes32 beaconStateRoot; - bytes proof; - } - - /// @notice This struct contains the merkle proofs and leaves needed to verify a partial/full withdrawal - struct WithdrawalProof { - bytes withdrawalProof; - bytes slotProof; - bytes executionPayloadProof; - bytes timestampProof; - bytes historicalSummaryBlockRootProof; - uint64 blockRootIndex; - uint64 historicalSummaryIndex; - uint64 withdrawalIndex; - bytes32 blockRoot; - bytes32 slotRoot; - bytes32 timestampRoot; - bytes32 executionPayloadRoot; - } - - /** - * @notice This function verifies that the withdrawal credentials of validator(s) owned by the podOwner are pointed to - * this contract. It also verifies the effective balance of the validator. It verifies the provided proof of the ETH validator against the beacon chain state - * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer. - * @param oracleTimestamp is the Beacon Chain timestamp whose state root the `proof` will be proven against. - * @param stateRootProof proves a `beaconStateRoot` against a block root fetched from the oracle - * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs - * @param validatorFieldsProofs proofs against the `beaconStateRoot` for each validator in `validatorFields` - * @param validatorFields are the fields of the "Validator Container", refer to consensus specs - * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator - */ - function verifyWithdrawalCredentials( - uint64 oracleTimestamp, - StateRootProof calldata stateRootProof, - uint40[] calldata validatorIndices, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields - ) external; - - /** - * @notice This function records an update (either increase or decrease) in a validator's balance. - * @param oracleTimestamp The oracleTimestamp whose state root the proof will be proven against. - * Must be within `VERIFY_BALANCE_UPDATE_WINDOW_SECONDS` of the current block. - * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs - * @param stateRootProof proves a `beaconStateRoot` against a block root fetched from the oracle - * @param validatorFieldsProofs proofs against the `beaconStateRoot` for each validator in `validatorFields` - * @param validatorFields are the fields of the "Validator Container", refer to consensus specs - * @dev For more details on the Beacon Chain spec, see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator - */ - function verifyBalanceUpdates( - uint64 oracleTimestamp, - uint40[] calldata validatorIndices, - StateRootProof calldata stateRootProof, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields - ) external; - - /** - * @notice This function records full and partial withdrawals on behalf of one or more of this EigenPod's validators - * @param oracleTimestamp is the timestamp of the oracle slot that the withdrawal is being proven against - * @param stateRootProof proves a `beaconStateRoot` against a block root fetched from the oracle - * @param withdrawalProofs proves several withdrawal-related values against the `beaconStateRoot` - * @param validatorFieldsProofs proves `validatorFields` against the `beaconStateRoot` - * @param withdrawalFields are the fields of the withdrawals being proven - * @param validatorFields are the fields of the validators being proven - */ - function verifyAndProcessWithdrawals( - uint64 oracleTimestamp, - StateRootProof calldata stateRootProof, - WithdrawalProof[] calldata withdrawalProofs, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields, - bytes32[][] calldata withdrawalFields - ) external; -} diff --git a/contracts/interfaces/IEigenPodManager.sol b/contracts/interfaces/IEigenPodManager.sol deleted file mode 100644 index 21d00987..00000000 --- a/contracts/interfaces/IEigenPodManager.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IEigenPodManager - * @author StakeWise - * @notice Defines the interface for the EigenPodManager contract - */ -interface IEigenPodManager { - /** - * @notice Creates a new EigenPod contract. - * The caller of this function becomes the owner of the new EigenPod contract. - * @return The address of the new EigenPod contract - */ - function createPod() external returns (address); -} diff --git a/contracts/interfaces/IEigenPodOwner.sol b/contracts/interfaces/IEigenPodOwner.sol deleted file mode 100644 index fd54bc42..00000000 --- a/contracts/interfaces/IEigenPodOwner.sol +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IERC1822Proxiable} from '@openzeppelin/contracts/interfaces/draft-IERC1822.sol'; -import {IEigenPod} from './IEigenPod.sol'; -import {IEigenDelegationManager} from './IEigenDelegationManager.sol'; -import {IMulticall} from './IMulticall.sol'; - -/** - * @title IEigenPodOwner - * @author StakeWise - * @notice Defines the interface for the EigenPodOwner contract - */ -interface IEigenPodOwner is IERC1822Proxiable, IMulticall { - /** - * @notice Vault - * @return The address of the Vault - */ - function vault() external view returns (address); - - /** - * @notice EigenPod - * @return The address of the EigenPod - */ - function eigenPod() external view returns (address); - - /** - * @notice EigenPodOwner implementation contract - * @return The address of the implementation contract - */ - function implementation() external view returns (address); - - /** - * @notice Initializes the contract - * @param params The initialization parameters - */ - function initialize(bytes calldata params) external; - - /** - * @notice Verifies the withdrawal credentials. Can only be called by the WithdrawalsManager. - * @param oracleTimestamp The timestamp of the oracle - * @param stateRootProof The state root proof - * @param validatorIndices The validator indices - * @param validatorFieldsProofs The validator fields proofs - * @param validatorFields The validator fields - */ - function verifyWithdrawalCredentials( - uint64 oracleTimestamp, - IEigenPod.StateRootProof calldata stateRootProof, - uint40[] calldata validatorIndices, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields - ) external; - - /** - * @notice Delegates to an operator. Can only be called by the OperatorsManager. - * @param operator The operator address - * @param approverSignatureAndExpiry The signature and expiry of the approver - * @param approverSalt The approver salt - */ - function delegateTo( - address operator, - IEigenDelegationManager.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) external; - - /** - * @notice Undelegate. Can only be called by the OperatorsManager. - */ - function undelegate() external; - - /** - * @notice Adds a new withdrawal to the queue. Can only be called by the WithdrawalsManager. - * @param shares The number of shares to withdraw - */ - function queueWithdrawal(uint256 shares) external; - - /** - * @notice Completes a queued withdrawal - * @param delegatedTo The address that the staker was delegated to at the time that the Withdrawal was created - * @param nonce The nonce used to guarantee that otherwise identical withdrawals have unique hashes - * @param shares The amount of shares in the withdrawal - * @param startBlock The block number when the withdrawal was created - * @param middlewareTimesIndex The middleware times index - * @param receiveAsTokens Whether to receive the withdrawal as tokens - * - */ - function completeQueuedWithdrawal( - address delegatedTo, - uint256 nonce, - uint256 shares, - uint32 startBlock, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external; - - /** - * @notice Claims delayed withdrawals - * @param maxNumberOfDelayedWithdrawalsToClaim The maximum number of delayed withdrawals to claim - */ - function claimDelayedWithdrawals(uint256 maxNumberOfDelayedWithdrawalsToClaim) external; - - /** - * @notice Verifies the balance updates - * @param oracleTimestamp The timestamp of the oracle - * @param validatorIndices The validator indices - * @param stateRootProof The state root proof - * @param validatorFieldsProofs The validator fields proofs - * @param validatorFields The validator fields - */ - function verifyBalanceUpdates( - uint64 oracleTimestamp, - uint40[] calldata validatorIndices, - IEigenPod.StateRootProof calldata stateRootProof, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields - ) external; - - /** - * @notice Verifies and processes withdrawals - * @param oracleTimestamp The timestamp of the oracle - * @param stateRootProof The state root proof - * @param withdrawalProofs The withdrawal proofs - * @param validatorFieldsProofs The validator fields proofs - * @param validatorFields The validator fields - * @param withdrawalFields The withdrawal fields - */ - function verifyAndProcessWithdrawals( - uint64 oracleTimestamp, - IEigenPod.StateRootProof calldata stateRootProof, - IEigenPod.WithdrawalProof[] calldata withdrawalProofs, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields, - bytes32[][] calldata withdrawalFields - ) external; -} diff --git a/contracts/interfaces/IEthRestakeBlocklistErc20Vault.sol b/contracts/interfaces/IEthRestakeBlocklistErc20Vault.sol deleted file mode 100644 index e4211103..00000000 --- a/contracts/interfaces/IEthRestakeBlocklistErc20Vault.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IEthRestakeErc20Vault} from './IEthRestakeErc20Vault.sol'; - -/** - * @title IEthRestakeBlocklistErc20Vault - * @author StakeWise - * @notice Defines the interface for the EthRestakeBlocklistErc20Vault contract - */ -interface IEthRestakeBlocklistErc20Vault is IEthRestakeErc20Vault, IVaultBlocklist {} diff --git a/contracts/interfaces/IEthRestakeBlocklistVault.sol b/contracts/interfaces/IEthRestakeBlocklistVault.sol deleted file mode 100644 index 4f546fde..00000000 --- a/contracts/interfaces/IEthRestakeBlocklistVault.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IEthRestakeVault} from './IEthRestakeVault.sol'; - -/** - * @title IEthRestakeBlocklistVault - * @author StakeWise - * @notice Defines the interface for the EthRestakeBlocklistVault contract - */ -interface IEthRestakeBlocklistVault is IEthRestakeVault, IVaultBlocklist {} diff --git a/contracts/interfaces/IEthRestakeErc20Vault.sol b/contracts/interfaces/IEthRestakeErc20Vault.sol deleted file mode 100644 index ccd57b39..00000000 --- a/contracts/interfaces/IEthRestakeErc20Vault.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultEthStaking} from './IVaultEthStaking.sol'; -import {IVaultEthRestaking} from './IVaultEthRestaking.sol'; -import {IMulticall} from './IMulticall.sol'; -import {IVaultToken} from './IVaultToken.sol'; - -/** - * @title IEthRestakeErc20Vault - * @author StakeWise - * @notice Defines the interface for the EthRestakeErc20Vault contract - */ -interface IEthRestakeErc20Vault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultMev, - IVaultToken, - IVaultEthStaking, - IVaultEthRestaking, - IMulticall -{ - /** - * @dev Struct for initializing the EthRestakeErc20Vault contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param name The name of the ERC20 token - * @param symbol The symbol of the ERC20 token - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct EthRestakeErc20VaultInitParams { - uint256 capacity; - uint16 feePercent; - string name; - string symbol; - string metadataIpfsHash; - } - - /** - * @notice Initializes or upgrades the EthRestakeErc20Vault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the EthRestakeErc20Vault contract - */ - function initialize(bytes calldata params) external payable; -} diff --git a/contracts/interfaces/IEthRestakePrivErc20Vault.sol b/contracts/interfaces/IEthRestakePrivErc20Vault.sol deleted file mode 100644 index 4a3f91a5..00000000 --- a/contracts/interfaces/IEthRestakePrivErc20Vault.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultWhitelist} from './IVaultWhitelist.sol'; -import {IEthRestakeErc20Vault} from './IEthRestakeErc20Vault.sol'; - -/** - * @title IEthRestakePrivErc20Vault - * @author StakeWise - * @notice Defines the interface for the EthRestakePrivErc20Vault contract - */ -interface IEthRestakePrivErc20Vault is IEthRestakeErc20Vault, IVaultWhitelist {} diff --git a/contracts/interfaces/IEthRestakePrivVault.sol b/contracts/interfaces/IEthRestakePrivVault.sol deleted file mode 100644 index 6dc6fba8..00000000 --- a/contracts/interfaces/IEthRestakePrivVault.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultWhitelist} from './IVaultWhitelist.sol'; -import {IEthRestakeVault} from './IEthRestakeVault.sol'; - -/** - * @title IEthRestakePrivVault - * @author StakeWise - * @notice Defines the interface for the EthRestakePrivVault contract - */ -interface IEthRestakePrivVault is IEthRestakeVault, IVaultWhitelist {} diff --git a/contracts/interfaces/IEthRestakeVault.sol b/contracts/interfaces/IEthRestakeVault.sol deleted file mode 100644 index e93e9d21..00000000 --- a/contracts/interfaces/IEthRestakeVault.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultEthStaking} from './IVaultEthStaking.sol'; -import {IVaultEthRestaking} from './IVaultEthRestaking.sol'; -import {IMulticall} from './IMulticall.sol'; - -/** - * @title IEthRestakeVault - * @author StakeWise - * @notice Defines the interface for the EthRestakeVault contract - */ -interface IEthRestakeVault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultMev, - IVaultEthStaking, - IVaultEthRestaking, - IMulticall -{ - /** - * @dev Struct for initializing the EthRestakeVault contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct EthRestakeVaultInitParams { - uint256 capacity; - uint16 feePercent; - string metadataIpfsHash; - } - - /** - * @notice Initializes or upgrades the EthRestakeVault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the EthRestakeVault contract - */ - function initialize(bytes calldata params) external payable; -} diff --git a/contracts/interfaces/IEthRestakeVaultFactory.sol b/contracts/interfaces/IEthRestakeVaultFactory.sol deleted file mode 100644 index c0f0c142..00000000 --- a/contracts/interfaces/IEthRestakeVaultFactory.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IEthRestakeVaultFactory - * @author StakeWise - * @notice Defines the interface for the EthRestakeVaultFactory contract - */ -interface IEthRestakeVaultFactory { - /** - * @notice Event emitted on a Vault creation - * @param admin The address of the Vault admin - * @param vault The address of the created Vault - * @param ownMevEscrow The address of the own MEV escrow contract. Zero address if shared MEV escrow is used. - * @param params The encoded parameters for initializing the Vault contract - */ - event VaultCreated( - address indexed admin, - address indexed vault, - address ownMevEscrow, - bytes params - ); - - /** - * @notice The address of the Vault implementation contract used for proxy creation - * @return The address of the Vault implementation contract - */ - function implementation() external view returns (address); - - /** - * @notice The address of the own MEV escrow contract used for Vault creation - * @return The address of the MEV escrow contract - */ - function ownMevEscrow() external view returns (address); - - /** - * @notice The address of the Vault admin used for Vault creation - * @return The address of the Vault admin - */ - function vaultAdmin() external view returns (address); - - /** - * @notice Create Vault. Must transfer security deposit together with a call. - * @param admin The address of the Vault admin - * @param params The encoded parameters for initializing the Vault contract - * @param isOwnMevEscrow Whether to deploy own escrow contract or connect to a smoothing pool for priority fees and MEV rewards - * @return vault The address of the created Vault - */ - function createVault( - address admin, - bytes calldata params, - bool isOwnMevEscrow - ) external payable returns (address vault); -} diff --git a/contracts/interfaces/IVaultEthRestaking.sol b/contracts/interfaces/IVaultEthRestaking.sol deleted file mode 100644 index 3249fb2a..00000000 --- a/contracts/interfaces/IVaultEthRestaking.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultEthStaking} from './IVaultEthStaking.sol'; - -/** - * @title IVaultEthRestaking - * @author StakeWise - * @notice Defines the interface for the VaultEthRestaking contract - */ -interface IVaultEthRestaking is IVaultAdmin, IVaultEthStaking { - /** - * @notice Emitted when a new EigenPod is created - * @param eigenPodOwner The address of the EigenPod owner - * @param eigenPod The address of the EigenPod - */ - event EigenPodCreated(address eigenPodOwner, address eigenPod); - - /* - * @notice Emitted when the restakeOperatorsManager is changed - * @param newRestakeOperatorsManager The address of the new restakeOperatorsManager - */ - event RestakeOperatorsManagerUpdated(address newRestakeOperatorsManager); - - /* - * @notice Emitted when the restakeWithdrawalsManager is changed - * @param newRestakeWithdrawalsManager The address of the new restakeWithdrawalsManager - */ - event RestakeWithdrawalsManagerUpdated(address newRestakeWithdrawalsManager); - - /** - * @notice Getter for the address of the restakeOperatorsManager - * @return The address of the restakeOperatorsManager - */ - function restakeOperatorsManager() external view returns (address); - - /** - * @notice Getter for the address of the restakeWithdrawalsManager - * @return The address of the restakeWithdrawalsManager - */ - function restakeWithdrawalsManager() external view returns (address); - - /** - * @notice Getter for the address of the EigenPods - * @return The list of EigenPods addresses - */ - function getEigenPods() external view returns (address[] memory); - - /** - * @notice Creates a new eigenPod and eigenPod owner contracts. Can only be called by the restakeOperatorsManager. - */ - function createEigenPod() external; - - /** - * @notice Sets the address of the restakeWithdrawalsManager. Can only be called by the admin. - * @param newRestakeWithdrawalsManager The address of the new restakeWithdrawalsManager - */ - function setRestakeWithdrawalsManager(address newRestakeWithdrawalsManager) external; - - /** - * @notice Sets the address of the restakeOperatorsManager. Can only be called by the admin. - * @param newRestakeOperatorsManager The address of the new restakeOperatorsManager - */ - function setRestakeOperatorsManager(address newRestakeOperatorsManager) external; -} diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index 46bb60d6..bc533d2d 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -50,8 +50,6 @@ library Errors { error MaxOraclesExceeded(); error ExitRequestNotProcessed(); error ValueNotChanged(); - error InvalidWithdrawalCredentials(); - error EigenPodNotFound(); error InvalidQueuedShares(); error FlashLoanFailed(); } diff --git a/contracts/misc/CumulativeMerkleDrop.sol b/contracts/misc/CumulativeMerkleDrop.sol deleted file mode 100644 index e668ca3e..00000000 --- a/contracts/misc/CumulativeMerkleDrop.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {ICumulativeMerkleDrop} from '../interfaces/ICumulativeMerkleDrop.sol'; - -contract CumulativeMerkleDrop is Ownable2Step, ICumulativeMerkleDrop { - /// @inheritdoc ICumulativeMerkleDrop - IERC20 public immutable override token; - - /// @inheritdoc ICumulativeMerkleDrop - bytes32 public override merkleRoot; - - mapping(address => uint256) private _cumulativeClaimed; - - /** - * @dev Constructor - * @param _owner The address of the owner of the contract - * @param _token The address of the token contract - */ - constructor(address _owner, address _token) Ownable(_owner) { - token = IERC20(_token); - } - - /// @inheritdoc ICumulativeMerkleDrop - function setMerkleRoot( - bytes32 _merkleRoot, - string calldata proofsIpfsHash - ) external override onlyOwner { - merkleRoot = _merkleRoot; - emit MerkleRootUpdated(_merkleRoot, proofsIpfsHash); - } - - /// @inheritdoc ICumulativeMerkleDrop - function claim( - address account, - uint256 cumulativeAmount, - bytes32[] calldata merkleProof - ) external override { - // verify the merkle proof - if ( - !MerkleProof.verifyCalldata( - merkleProof, - merkleRoot, - keccak256(bytes.concat(keccak256(abi.encode(account, cumulativeAmount)))) - ) - ) { - revert InvalidProof(); - } - - // SLOAD to memory - uint256 amountBefore = _cumulativeClaimed[account]; - - // reverts if less than before - uint256 periodAmount = cumulativeAmount - amountBefore; - if (periodAmount == 0) revert AlreadyClaimed(); - - // update state - _cumulativeClaimed[account] = cumulativeAmount; - - // transfer amount - SafeERC20.safeTransfer(token, account, periodAmount); - emit Claimed(account, cumulativeAmount); - } -} diff --git a/contracts/mocks/EigenPodOwnerV2Mock.sol b/contracts/mocks/EigenPodOwnerV2Mock.sol deleted file mode 100644 index 423230b2..00000000 --- a/contracts/mocks/EigenPodOwnerV2Mock.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EigenPodOwner} from '../vaults/ethereum/restake/EigenPodOwner.sol'; - -contract EigenPodOwnerV2Mock is EigenPodOwner { - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address eigenPodManager, - address eigenDelegationManager, - address eigenDelayedWithdrawalRouter - ) EigenPodOwner(eigenPodManager, eigenDelegationManager, eigenDelayedWithdrawalRouter) {} - - function initialize(bytes calldata data) external virtual override reinitializer(2) {} - - function somethingNew() external pure returns (bool) { - return true; - } -} diff --git a/contracts/vaults/ethereum/restake/EigenPodOwner.sol b/contracts/vaults/ethereum/restake/EigenPodOwner.sol deleted file mode 100644 index 0ef54216..00000000 --- a/contracts/vaults/ethereum/restake/EigenPodOwner.sol +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {ERC1967Utils} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {UUPSUpgradeable} from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; -import {IEigenPod} from '../../../interfaces/IEigenPod.sol'; -import {IEigenDelayedWithdrawalRouter} from '../../../interfaces/IEigenDelayedWithdrawalRouter.sol'; -import {IEigenDelegationManager} from '../../../interfaces/IEigenDelegationManager.sol'; -import {IEigenPodManager} from '../../../interfaces/IEigenPodManager.sol'; -import {IEigenPodOwner} from '../../../interfaces/IEigenPodOwner.sol'; -import {IVaultEthRestaking} from '../../../interfaces/IVaultEthRestaking.sol'; -import {Errors} from '../../../libraries/Errors.sol'; -import {Multicall} from '../../../base/Multicall.sol'; - -/** - * @title EigenPodOwner - * @author StakeWise - * @notice Defines the EigenLayer Pod owner contract functionality - */ -contract EigenPodOwner is Initializable, UUPSUpgradeable, Multicall, IEigenPodOwner { - address private constant _eigenPodStrategy = 0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IEigenPodManager private immutable _eigenPodManager; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IEigenDelegationManager private immutable _eigenDelegationManager; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IEigenDelayedWithdrawalRouter private immutable _eigenDelayedWithdrawalRouter; - - /// @inheritdoc IEigenPodOwner - // slither-disable-next-line uninitialized-state - address public override vault; - - /// @inheritdoc IEigenPodOwner - // slither-disable-next-line uninitialized-state - address public override eigenPod; - - /** - * @dev Modifier to check that the caller is the operators manager - */ - modifier onlyOperatorsManager() { - if (IVaultEthRestaking(vault).restakeOperatorsManager() != msg.sender) { - revert Errors.AccessDenied(); - } - _; - } - - /** - * @dev Modifier to check that the caller is the withdrawals manager - */ - modifier onlyWithdrawalsManager() { - if (IVaultEthRestaking(vault).restakeWithdrawalsManager() != msg.sender) { - revert Errors.AccessDenied(); - } - _; - } - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param eigenPodManager The address of the EigenPodManager contract - * @param eigenDelegationManager The address of the EigenDelegationManager contract - * @param eigenDelayedWithdrawalRouter The address of the EigenDelayedWithdrawalRouter contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address eigenPodManager, - address eigenDelegationManager, - address eigenDelayedWithdrawalRouter - ) { - _eigenPodManager = IEigenPodManager(eigenPodManager); - _eigenDelegationManager = IEigenDelegationManager(eigenDelegationManager); - _eigenDelayedWithdrawalRouter = IEigenDelayedWithdrawalRouter(eigenDelayedWithdrawalRouter); - _disableInitializers(); - } - - /// @inheritdoc IEigenPodOwner - function implementation() external view override returns (address) { - return ERC1967Utils.getImplementation(); - } - - /// @inheritdoc IEigenPodOwner - function initialize(bytes calldata) external virtual override initializer { - vault = msg.sender; - eigenPod = _eigenPodManager.createPod(); - } - - /// @inheritdoc IEigenPodOwner - function verifyWithdrawalCredentials( - uint64 oracleTimestamp, - IEigenPod.StateRootProof calldata stateRootProof, - uint40[] calldata validatorIndices, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields - ) external override onlyWithdrawalsManager { - IEigenPod(eigenPod).verifyWithdrawalCredentials( - oracleTimestamp, - stateRootProof, - validatorIndices, - validatorFieldsProofs, - validatorFields - ); - } - - /// @inheritdoc IEigenPodOwner - function delegateTo( - address operator, - IEigenDelegationManager.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) external override onlyOperatorsManager { - _eigenDelegationManager.delegateTo(operator, approverSignatureAndExpiry, approverSalt); - } - - /// @inheritdoc IEigenPodOwner - function undelegate() external override onlyOperatorsManager { - _eigenDelegationManager.undelegate(address(this)); - } - - /// @inheritdoc IEigenPodOwner - function queueWithdrawal(uint256 shares) external override onlyWithdrawalsManager { - // construct the withdrawal parameters - IEigenDelegationManager.QueuedWithdrawalParams memory withdrawal = IEigenDelegationManager - .QueuedWithdrawalParams({ - withdrawer: address(this), - strategies: new address[](1), - shares: new uint256[](1) - }); - withdrawal.strategies[0] = _eigenPodStrategy; - withdrawal.shares[0] = shares; - - // create the array of withdrawals - IEigenDelegationManager.QueuedWithdrawalParams[] - memory withdrawals = new IEigenDelegationManager.QueuedWithdrawalParams[](1); - withdrawals[0] = withdrawal; - - // queue the withdrawal - _eigenDelegationManager.queueWithdrawals(withdrawals); - } - - /// @inheritdoc IEigenPodOwner - function completeQueuedWithdrawal( - address delegatedTo, - uint256 nonce, - uint256 shares, - uint32 startBlock, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external override onlyWithdrawalsManager { - IEigenDelegationManager.Withdrawal memory withdrawal = IEigenDelegationManager.Withdrawal({ - staker: address(this), - delegatedTo: delegatedTo, - withdrawer: address(this), - nonce: nonce, - startBlock: startBlock, - strategies: new address[](1), - shares: new uint256[](1) - }); - withdrawal.strategies[0] = _eigenPodStrategy; - withdrawal.shares[0] = shares; - - // tokens are not used for the EigenPod, but should match the length of the strategies array - address[] memory tokens = new address[](1); - tokens[0] = address(0); - - _eigenDelegationManager.completeQueuedWithdrawal( - withdrawal, - tokens, - middlewareTimesIndex, - receiveAsTokens - ); - } - - /// @inheritdoc IEigenPodOwner - function claimDelayedWithdrawals(uint256 maxNumberOfDelayedWithdrawalsToClaim) external override { - _eigenDelayedWithdrawalRouter.claimDelayedWithdrawals(maxNumberOfDelayedWithdrawalsToClaim); - } - - /// @inheritdoc IEigenPodOwner - function verifyBalanceUpdates( - uint64 oracleTimestamp, - uint40[] calldata validatorIndices, - IEigenPod.StateRootProof calldata stateRootProof, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields - ) external override { - IEigenPod(eigenPod).verifyBalanceUpdates( - oracleTimestamp, - validatorIndices, - stateRootProof, - validatorFieldsProofs, - validatorFields - ); - } - - /// @inheritdoc IEigenPodOwner - function verifyAndProcessWithdrawals( - uint64 oracleTimestamp, - IEigenPod.StateRootProof calldata stateRootProof, - IEigenPod.WithdrawalProof[] calldata withdrawalProofs, - bytes[] calldata validatorFieldsProofs, - bytes32[][] calldata validatorFields, - bytes32[][] calldata withdrawalFields - ) external override { - IEigenPod(eigenPod).verifyAndProcessWithdrawals( - oracleTimestamp, - stateRootProof, - withdrawalProofs, - validatorFieldsProofs, - validatorFields, - withdrawalFields - ); - } - - /** - * @dev Function for receiving assets and forwarding them to the Vault - */ - receive() external payable { - if (msg.sender != address(_eigenDelayedWithdrawalRouter) && msg.sender != eigenPod) { - revert Errors.AccessDenied(); - } - // forward received assets to the vault - Address.sendValue(payable(vault), msg.value); - } - - /// @inheritdoc UUPSUpgradeable - function _authorizeUpgrade(address newImplementation) internal view override { - if (msg.sender != vault) revert Errors.AccessDenied(); - if (newImplementation == address(0) || ERC1967Utils.getImplementation() == newImplementation) { - revert Errors.UpgradeFailed(); - } - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol b/contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol deleted file mode 100644 index 99b9e07a..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthRestakeBlocklistErc20Vault} from '../../../interfaces/IEthRestakeBlocklistErc20Vault.sol'; -import {IEthVaultFactory} from '../../../interfaces/IEthVaultFactory.sol'; -import {ERC20Upgradeable} from '../../../base/ERC20Upgradeable.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {VaultVersion, IVaultVersion} from '../../modules/VaultVersion.sol'; -import {VaultBlocklist} from '../../modules/VaultBlocklist.sol'; -import {EthRestakeErc20Vault, IEthRestakeErc20Vault} from './EthRestakeErc20Vault.sol'; - -/** - * @title EthRestakeBlocklistErc20Vault - * @author StakeWise - * @notice Defines the native restaking Vault with blocking and ERC-20 functionality on Ethereum - */ -contract EthRestakeBlocklistErc20Vault is - Initializable, - EthRestakeErc20Vault, - VaultBlocklist, - IEthRestakeBlocklistErc20Vault -{ - using EnumerableSet for EnumerableSet.AddressSet; - - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address sharedMevEscrow, - address depositDataRegistry, - address eigenPodOwnerImplementation, - uint256 exitingAssetsClaimDelay - ) - EthRestakeErc20Vault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImplementation, - exitingAssetsClaimDelay - ) - {} - - /// @inheritdoc IEthRestakeErc20Vault - function initialize( - bytes calldata params - ) - external - payable - virtual - override(IEthRestakeErc20Vault, EthRestakeErc20Vault) - reinitializer(_version) - { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __EthRestakeErc20Vault_initV3(); - return; - } - - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthRestakeErc20Vault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthRestakeErc20VaultInitParams)) - ); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(_admin); - } - - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(receiver, referrer); - } - - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - if (!_eigenPodOwners.contains(msg.sender)) { - // if the sender is not an EigenPod owner, deposit the received assets - _checkBlocklist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } - } - - /// @inheritdoc IVaultVersion - function vaultId() - public - pure - virtual - override(IVaultVersion, EthRestakeErc20Vault) - returns (bytes32) - { - return keccak256('EthRestakeBlocklistErc20Vault'); - } - - /// @inheritdoc IVaultVersion - function version() - public - pure - virtual - override(IVaultVersion, EthRestakeErc20Vault) - returns (uint8) - { - return _version; - } - - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - _checkBlocklist(from); - _checkBlocklist(to); - super._transfer(from, to, amount); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol b/contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol deleted file mode 100644 index 9978054c..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthRestakeBlocklistVault} from '../../../interfaces/IEthRestakeBlocklistVault.sol'; -import {IEthVaultFactory} from '../../../interfaces/IEthVaultFactory.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {VaultBlocklist} from '../../modules/VaultBlocklist.sol'; -import {VaultVersion, IVaultVersion} from '../../modules/VaultVersion.sol'; -import {EthRestakeVault, IEthRestakeVault} from './EthRestakeVault.sol'; - -/** - * @title EthRestakeBlocklistVault - * @author StakeWise - * @notice Defines the native restaking Vault with blocking addresses functionality on Ethereum - */ -contract EthRestakeBlocklistVault is - Initializable, - EthRestakeVault, - VaultBlocklist, - IEthRestakeBlocklistVault -{ - using EnumerableSet for EnumerableSet.AddressSet; - - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address sharedMevEscrow, - address depositDataRegistry, - address eigenPodOwnerImplementation, - uint256 exitingAssetsClaimDelay - ) - EthRestakeVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImplementation, - exitingAssetsClaimDelay - ) - {} - - /// @inheritdoc IEthRestakeVault - function initialize( - bytes calldata params - ) external payable virtual override(IEthRestakeVault, EthRestakeVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __EthRestakeVault_initV3(); - return; - } - - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthRestakeVault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthRestakeVaultInitParams)) - ); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(_admin); - } - - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(receiver, referrer); - } - - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - _checkBlocklist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } - - /// @inheritdoc IVaultVersion - function vaultId() - public - pure - virtual - override(IVaultVersion, EthRestakeVault) - returns (bytes32) - { - return keccak256('EthRestakeBlocklistVault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthRestakeVault) returns (uint8) { - return _version; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol b/contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol deleted file mode 100644 index b7d61d2c..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthRestakeErc20Vault} from '../../../interfaces/IEthRestakeErc20Vault.sol'; -import {IEthVaultFactory} from '../../../interfaces/IEthVaultFactory.sol'; -import {Multicall} from '../../../base/Multicall.sol'; -import {ERC20Upgradeable} from '../../../base/ERC20Upgradeable.sol'; -import {VaultValidators} from '../../modules/VaultValidators.sol'; -import {VaultAdmin} from '../../modules/VaultAdmin.sol'; -import {VaultFee} from '../../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../../modules/VaultVersion.sol'; -import {VaultImmutables} from '../../modules/VaultImmutables.sol'; -import {VaultState} from '../../modules/VaultState.sol'; -import {VaultEnterExit, IVaultEnterExit} from '../../modules/VaultEnterExit.sol'; -import {VaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {VaultMev} from '../../modules/VaultMev.sol'; -import {VaultToken} from '../../modules/VaultToken.sol'; -import {VaultEthRestaking} from '../../modules/VaultEthRestaking.sol'; - -/** - * @title EthRestakeErc20Vault - * @author StakeWise - * @notice Defines the native restaking Vault with ERC-20 token on Ethereum - */ -contract EthRestakeErc20Vault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultMev, - VaultToken, - VaultEthStaking, - VaultEthRestaking, - Multicall, - IEthRestakeErc20Vault -{ - using EnumerableSet for EnumerableSet.AddressSet; - - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address sharedMevEscrow, - address depositDataRegistry, - address eigenPodOwnerImplementation, - uint256 exitingAssetsClaimDelay - ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) - VaultEnterExit(exitingAssetsClaimDelay) - VaultMev(sharedMevEscrow) - VaultEthRestaking(eigenPodOwnerImplementation) - { - _disableInitializers(); - } - - /// @inheritdoc IEthRestakeErc20Vault - function initialize( - bytes calldata params - ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __EthRestakeErc20Vault_initV3(); - return; - } - - // initialize deployed vault - __EthRestakeErc20Vault_init( - IEthVaultFactory(msg.sender).vaultAdmin(), - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthRestakeErc20VaultInitParams)) - ); - } - - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) public virtual override(IVaultEnterExit, VaultEnterExit) returns (uint256 positionTicket) { - positionTicket = super.enterExitQueue(shares, receiver); - emit Transfer(msg.sender, address(this), shares); - } - - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('EthRestakeErc20Vault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } - - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - if (!_eigenPodOwners.contains(msg.sender)) { - // if the sender is not an EigenPod owner, deposit the received assets - _deposit(msg.sender, msg.value, address(0)); - } - } - - /// @inheritdoc VaultState - function _updateExitQueue() - internal - virtual - override(VaultState, VaultToken) - returns (uint256 burnedShares) - { - return super._updateExitQueue(); - } - - /// @inheritdoc VaultState - function _mintShares( - address owner, - uint256 shares - ) internal virtual override(VaultState, VaultToken) { - super._mintShares(owner, shares); - } - - /// @inheritdoc VaultState - function _burnShares( - address owner, - uint256 shares - ) internal virtual override(VaultState, VaultToken) { - super._burnShares(owner, shares); - } - - /// @inheritdoc VaultValidators - function _registerSingleValidator( - bytes calldata validator - ) internal virtual override(VaultValidators, VaultEthStaking, VaultEthRestaking) { - return super._registerSingleValidator(validator); - } - - /// @inheritdoc VaultValidators - function _registerMultipleValidators( - bytes calldata validators - ) internal override(VaultValidators, VaultEthStaking, VaultEthRestaking) { - return super._registerMultipleValidators(validators); - } - - /// @inheritdoc VaultValidators - function _validatorLength() - internal - pure - virtual - override(VaultValidators, VaultEthStaking, VaultEthRestaking) - returns (uint256) - { - return super._validatorLength(); - } - - /** - * @dev Initializes the EthRestakeErc20Vault contract upgrade to V3 - */ - function __EthRestakeErc20Vault_initV3() internal { - __VaultState_initV3(); - __VaultValidators_initV3(); - } - - /** - * @dev Initializes the EthRestakeErc20Vault contract - * @param admin The address of the admin of the Vault - * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. - * @param params The decoded parameters for initializing the EthRestakeErc20Vault contract - */ - function __EthRestakeErc20Vault_init( - address admin, - address ownMevEscrow, - EthRestakeErc20VaultInitParams memory params - ) internal onlyInitializing { - __VaultAdmin_init(admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(ownMevEscrow); - __VaultToken_init(params.name, params.symbol); - __VaultEthStaking_init(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol b/contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol deleted file mode 100644 index efda39fd..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthRestakePrivErc20Vault} from '../../../interfaces/IEthRestakePrivErc20Vault.sol'; -import {IEthVaultFactory} from '../../../interfaces/IEthVaultFactory.sol'; -import {ERC20Upgradeable} from '../../../base/ERC20Upgradeable.sol'; -import {VaultWhitelist} from '../../modules/VaultWhitelist.sol'; -import {VaultVersion, IVaultVersion} from '../../modules/VaultVersion.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {EthRestakeErc20Vault, IEthRestakeErc20Vault} from './EthRestakeErc20Vault.sol'; - -/** - * @title EthRestakePrivErc20Vault - * @author StakeWise - * @notice Defines the restaking Vault with whitelist and ERC-20 token on Ethereum - */ -contract EthRestakePrivErc20Vault is - Initializable, - EthRestakeErc20Vault, - VaultWhitelist, - IEthRestakePrivErc20Vault -{ - using EnumerableSet for EnumerableSet.AddressSet; - - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address sharedMevEscrow, - address depositDataRegistry, - address eigenPodOwnerImplementation, - uint256 exitingAssetsClaimDelay - ) - EthRestakeErc20Vault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImplementation, - exitingAssetsClaimDelay - ) - {} - - /// @inheritdoc IEthRestakeErc20Vault - function initialize( - bytes calldata params - ) - external - payable - virtual - override(IEthRestakeErc20Vault, EthRestakeErc20Vault) - reinitializer(_version) - { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __EthRestakeErc20Vault_initV3(); - return; - } - - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthRestakeErc20Vault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthRestakeErc20VaultInitParams)) - ); - // whitelister is initially set to admin address - __VaultWhitelist_init(_admin); - } - - /// @inheritdoc IVaultVersion - function vaultId() - public - pure - virtual - override(IVaultVersion, EthRestakeErc20Vault) - returns (bytes32) - { - return keccak256('EthRestakePrivErc20Vault'); - } - - /// @inheritdoc IVaultVersion - function version() - public - pure - virtual - override(IVaultVersion, EthRestakeErc20Vault) - returns (uint8) - { - return _version; - } - - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkWhitelist(msg.sender); - _checkWhitelist(receiver); - return super.deposit(receiver, referrer); - } - - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - if (!_eigenPodOwners.contains(msg.sender)) { - // if the sender is not an EigenPod owner, deposit the received assets - _checkWhitelist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } - } - - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - _checkWhitelist(from); - _checkWhitelist(to); - super._transfer(from, to, amount); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakePrivVault.sol b/contracts/vaults/ethereum/restake/EthRestakePrivVault.sol deleted file mode 100644 index 22ad5b52..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakePrivVault.sol +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthRestakePrivVault} from '../../../interfaces/IEthRestakePrivVault.sol'; -import {IEthVaultFactory} from '../../../interfaces/IEthVaultFactory.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {VaultWhitelist} from '../../modules/VaultWhitelist.sol'; -import {IVaultVersion} from '../../modules/VaultVersion.sol'; -import {EthRestakeVault, IEthRestakeVault} from './EthRestakeVault.sol'; - -/** - * @title EthRestakePrivVault - * @author StakeWise - * @notice Defines the restaking Vault with whitelist on Ethereum - */ -contract EthRestakePrivVault is - Initializable, - EthRestakeVault, - VaultWhitelist, - IEthRestakePrivVault -{ - using EnumerableSet for EnumerableSet.AddressSet; - - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address sharedMevEscrow, - address depositDataRegistry, - address eigenPodOwnerImplementation, - uint256 exitingAssetsClaimDelay - ) - EthRestakeVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImplementation, - exitingAssetsClaimDelay - ) - {} - - /// @inheritdoc IEthRestakeVault - function initialize( - bytes calldata params - ) external payable virtual override(IEthRestakeVault, EthRestakeVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __EthRestakeVault_initV3(); - return; - } - - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthRestakeVault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthRestakeVaultInitParams)) - ); - // whitelister is initially set to admin address - __VaultWhitelist_init(_admin); - } - - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkWhitelist(msg.sender); - _checkWhitelist(receiver); - return super.deposit(receiver, referrer); - } - - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - if (!_eigenPodOwners.contains(msg.sender)) { - // if the sender is not an EigenPod owner, deposit the received assets - _checkWhitelist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } - } - - /// @inheritdoc IVaultVersion - function vaultId() - public - pure - virtual - override(IVaultVersion, EthRestakeVault) - returns (bytes32) - { - return keccak256('EthRestakePrivVault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthRestakeVault) returns (uint8) { - return _version; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakeVault.sol b/contracts/vaults/ethereum/restake/EthRestakeVault.sol deleted file mode 100644 index d2ae7c60..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakeVault.sol +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthRestakeVault} from '../../../interfaces/IEthRestakeVault.sol'; -import {IEthVaultFactory} from '../../../interfaces/IEthVaultFactory.sol'; -import {Multicall} from '../../../base/Multicall.sol'; -import {VaultValidators} from '../../modules/VaultValidators.sol'; -import {VaultAdmin} from '../../modules/VaultAdmin.sol'; -import {VaultFee} from '../../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../../modules/VaultVersion.sol'; -import {VaultImmutables} from '../../modules/VaultImmutables.sol'; -import {VaultState} from '../../modules/VaultState.sol'; -import {VaultEnterExit, IVaultEnterExit} from '../../modules/VaultEnterExit.sol'; -import {VaultMev} from '../../modules/VaultMev.sol'; -import {VaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {VaultEthRestaking} from '../../modules/VaultEthRestaking.sol'; - -/** - * @title EthRestakeVault - * @author StakeWise - * @notice Defines the restaking Vault on Ethereum - */ -contract EthRestakeVault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultMev, - VaultEthStaking, - VaultEthRestaking, - Multicall, - IEthRestakeVault -{ - using EnumerableSet for EnumerableSet.AddressSet; - - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address sharedMevEscrow, - address depositDataRegistry, - address eigenPodOwnerImplementation, - uint256 exitingAssetsClaimDelay - ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) - VaultEnterExit(exitingAssetsClaimDelay) - VaultMev(sharedMevEscrow) - VaultEthRestaking(eigenPodOwnerImplementation) - { - _disableInitializers(); - } - - /// @inheritdoc IEthRestakeVault - function initialize( - bytes calldata params - ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __EthRestakeVault_initV3(); - return; - } - - // initialize deployed vault - __EthRestakeVault_init( - IEthVaultFactory(msg.sender).vaultAdmin(), - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthRestakeVaultInitParams)) - ); - } - - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) public virtual override(IVaultEnterExit, VaultEnterExit) returns (uint256 positionTicket) { - return super.enterExitQueue(shares, receiver); - } - - /// @inheritdoc VaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('EthRestakeVault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } - - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - if (!_eigenPodOwners.contains(msg.sender)) { - // if the sender is not an EigenPod owner, deposit the received assets - _deposit(msg.sender, msg.value, address(0)); - } - } - - /// @inheritdoc VaultValidators - function _registerSingleValidator( - bytes calldata validator - ) internal virtual override(VaultValidators, VaultEthStaking, VaultEthRestaking) { - return super._registerSingleValidator(validator); - } - - /// @inheritdoc VaultValidators - function _registerMultipleValidators( - bytes calldata validators - ) internal override(VaultValidators, VaultEthStaking, VaultEthRestaking) { - return super._registerMultipleValidators(validators); - } - - /// @inheritdoc VaultValidators - function _validatorLength() - internal - pure - virtual - override(VaultValidators, VaultEthStaking, VaultEthRestaking) - returns (uint256) - { - return super._validatorLength(); - } - - /** - * @dev Initializes the EthRestakeVault contract upgrade to V3 - */ - function __EthRestakeVault_initV3() internal { - __VaultState_initV3(); - __VaultValidators_initV3(); - } - - /** - * @dev Initializes the EthRestakeVault contract - * @param admin The address of the admin of the Vault - * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. - * @param params The decoded parameters for initializing the EthRestakeVault contract - */ - function __EthRestakeVault_init( - address admin, - address ownMevEscrow, - EthRestakeVaultInitParams memory params - ) internal onlyInitializing { - __VaultAdmin_init(admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(ownMevEscrow); - __VaultEthStaking_init(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/contracts/vaults/ethereum/restake/EthRestakeVaultFactory.sol b/contracts/vaults/ethereum/restake/EthRestakeVaultFactory.sol deleted file mode 100644 index eb811324..00000000 --- a/contracts/vaults/ethereum/restake/EthRestakeVaultFactory.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {IVaultsRegistry} from '../../../interfaces/IVaultsRegistry.sol'; -import {IEthRestakeVaultFactory} from '../../../interfaces/IEthRestakeVaultFactory.sol'; -import {IEthRestakeVault} from '../../../interfaces/IEthRestakeVault.sol'; -import {Errors} from '../../../libraries/Errors.sol'; -import {OwnMevEscrow} from '../mev/OwnMevEscrow.sol'; - -/** - * @title EthRestakeVaultFactory - * @author StakeWise - * @notice Factory for deploying Ethereum restaking Vaults - */ -contract EthRestakeVaultFactory is Ownable2Step, IEthRestakeVaultFactory { - IVaultsRegistry internal immutable _vaultsRegistry; - - /// @inheritdoc IEthRestakeVaultFactory - address public immutable override implementation; - - /// @inheritdoc IEthRestakeVaultFactory - address public override ownMevEscrow; - - /// @inheritdoc IEthRestakeVaultFactory - address public override vaultAdmin; - - /** - * @dev Constructor - * @param initialOwner The address of the contract owner - * @param _implementation The implementation address of Vault - * @param vaultsRegistry The address of the VaultsRegistry contract - */ - constructor( - address initialOwner, - address _implementation, - IVaultsRegistry vaultsRegistry - ) Ownable(initialOwner) { - implementation = _implementation; - _vaultsRegistry = vaultsRegistry; - } - - /// @inheritdoc IEthRestakeVaultFactory - function createVault( - address admin, - bytes calldata params, - bool isOwnMevEscrow - ) public payable override onlyOwner returns (address vault) { - if (admin == address(0)) revert Errors.ZeroAddress(); - - // create vault - vault = address(new ERC1967Proxy(implementation, '')); - - // create MEV escrow contract if needed - address _mevEscrow; - if (isOwnMevEscrow) { - _mevEscrow = address(new OwnMevEscrow(vault)); - // set MEV escrow contract so that it can be initialized in the Vault - ownMevEscrow = _mevEscrow; - } - - // set admin so that it can be initialized in the Vault - vaultAdmin = admin; - - // initialize Vault - IEthRestakeVault(vault).initialize{value: msg.value}(params); - - // cleanup MEV escrow contract - if (isOwnMevEscrow) delete ownMevEscrow; - - // cleanup admin - delete vaultAdmin; - - // add vault to the registry - _vaultsRegistry.addVault(vault); - - // emit event - emit VaultCreated(admin, vault, _mevEscrow, params); - } -} diff --git a/contracts/vaults/modules/VaultEthRestaking.sol b/contracts/vaults/modules/VaultEthRestaking.sol deleted file mode 100644 index a97caa2d..00000000 --- a/contracts/vaults/modules/VaultEthRestaking.sol +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -import {IVaultEthRestaking} from '../../interfaces/IVaultEthRestaking.sol'; -import {IEigenPodOwner} from '../../interfaces/IEigenPodOwner.sol'; -import {IEthValidatorsRegistry} from '../../interfaces/IEthValidatorsRegistry.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; -import {VaultEthStaking} from './VaultEthStaking.sol'; - -/** - * @title VaultEthRestaking - * @author StakeWise - * @notice Defines the logic for the Ethereum native restaking vault - */ -abstract contract VaultEthRestaking is VaultAdmin, VaultEthStaking, IVaultEthRestaking { - using EnumerableSet for EnumerableSet.AddressSet; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _eigenPodOwnerImplementation; - - address private _restakeOperatorsManager; - address private _restakeWithdrawalsManager; - - EnumerableSet.AddressSet private _eigenPods; - EnumerableSet.AddressSet internal _eigenPodOwners; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param eigenPodOwnerImplementation The address of the EigenPodOwner implementation contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address eigenPodOwnerImplementation) { - _eigenPodOwnerImplementation = eigenPodOwnerImplementation; - } - - /// @inheritdoc IVaultEthRestaking - function restakeOperatorsManager() public view override returns (address) { - // SLOAD to memory - address restakeOperatorsManager_ = _restakeOperatorsManager; - // if restakeOperatorsManager is not set, use admin address - return restakeOperatorsManager_ == address(0) ? admin : restakeOperatorsManager_; - } - - /// @inheritdoc IVaultEthRestaking - function restakeWithdrawalsManager() public view override returns (address) { - // SLOAD to memory - address restakeWithdrawalsManager_ = _restakeWithdrawalsManager; - // if restakeWithdrawalsManager is not set, use admin address - return restakeWithdrawalsManager_ == address(0) ? admin : restakeWithdrawalsManager_; - } - - /// @inheritdoc IVaultEthRestaking - function getEigenPods() external view override returns (address[] memory) { - return _eigenPods.values(); - } - - /// @inheritdoc IVaultEthRestaking - function createEigenPod() external override { - if (msg.sender != restakeOperatorsManager()) revert Errors.AccessDenied(); - - // create a new EigenPodOwner - address eigenPodOwner = address(new ERC1967Proxy(_eigenPodOwnerImplementation, '')); - IEigenPodOwner(eigenPodOwner).initialize(''); - - // add eigen pod to the list of vault's eigen pods - address eigenPod = IEigenPodOwner(eigenPodOwner).eigenPod(); - _eigenPods.add(eigenPod); - _eigenPodOwners.add(eigenPodOwner); - - // emit event - emit EigenPodCreated(eigenPodOwner, eigenPod); - } - - /// @inheritdoc IVaultEthRestaking - function setRestakeOperatorsManager(address newRestakeOperatorsManager) external override { - if (_restakeOperatorsManager == newRestakeOperatorsManager) revert Errors.ValueNotChanged(); - _checkAdmin(); - _restakeOperatorsManager = newRestakeOperatorsManager; - emit RestakeOperatorsManagerUpdated(newRestakeOperatorsManager); - } - - /// @inheritdoc IVaultEthRestaking - function setRestakeWithdrawalsManager(address newRestakeWithdrawalsManager) external override { - if (_restakeWithdrawalsManager == newRestakeWithdrawalsManager) revert Errors.ValueNotChanged(); - _checkAdmin(); - _restakeWithdrawalsManager = newRestakeWithdrawalsManager; - emit RestakeWithdrawalsManagerUpdated(newRestakeWithdrawalsManager); - } - - /// @inheritdoc VaultEthStaking - function _registerSingleValidator(bytes calldata validator) internal virtual override { - bytes calldata publicKey = validator[:48]; - IEthValidatorsRegistry(_validatorsRegistry).deposit{value: _validatorDeposit()}( - publicKey, - _extractWithdrawalCredentials(validator[176:validator.length]), - validator[48:144], - bytes32(validator[144:176]) - ); - emit ValidatorRegistered(publicKey); - } - - /// @inheritdoc VaultEthStaking - function _registerMultipleValidators(bytes calldata validators) internal virtual override { - uint256 startIndex; - uint256 endIndex; - uint256 validatorLength = _validatorLength(); - uint256 validatorsCount = validators.length / validatorLength; - bytes calldata validator; - bytes calldata publicKey; - for (uint256 i = 0; i < validatorsCount; ) { - unchecked { - // cannot realistically overflow - endIndex += validatorLength; - } - validator = validators[startIndex:endIndex]; - publicKey = validator[:48]; - IEthValidatorsRegistry(_validatorsRegistry).deposit{value: _validatorDeposit()}( - publicKey, - _extractWithdrawalCredentials(validator[176:validator.length]), - validator[48:144], - bytes32(validator[144:validatorLength]) - ); - emit ValidatorRegistered(publicKey); - startIndex = endIndex; - unchecked { - // cannot realistically overflow - ++i; - } - } - } - - /// @inheritdoc VaultEthStaking - function _validatorLength() internal pure virtual override returns (uint256) { - return 196; - } - - /** - * @dev Internal function to extract the withdrawal credentials from the validator data - * @param withdrawalAddress The withdrawal address in bytes - * @return The credentials used for the validators withdrawals - */ - function _extractWithdrawalCredentials( - bytes calldata withdrawalAddress - ) private view returns (bytes memory) { - if (withdrawalAddress.length != 20) revert Errors.InvalidWithdrawalCredentials(); - - // check if the EigenPod exists - address eigenPod = address(uint160(bytes20(withdrawalAddress))); - if (!_eigenPods.contains(eigenPod)) revert Errors.EigenPodNotFound(); - return abi.encodePacked(bytes1(0x01), bytes11(0x0), eigenPod); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} diff --git a/deployments/holesky.json b/deployments/holesky.json index 0e73c423..730ff7fa 100644 --- a/deployments/holesky.json +++ b/deployments/holesky.json @@ -18,6 +18,5 @@ "EthOsTokenVaultEscrow": "0x807305c086A99cbDBff07cB4256cE556d9d6F0af", "OsTokenFlashLoans": "0x3e30370cabD4B4D95Be17706D840FF9de1ADdb67", "PriceFeed": "0xe31FAf135A6047Cbe595F91B4b6802cDB9B46E2b", - "RewardSplitterFactory": "0x2Ed24638b3aB48cF0076f19199c78A62bfEb5889", - "CumulativeMerkleDrop": "0x6737277a4A9071AF88cCa91042d77b4237f368C4" + "RewardSplitterFactory": "0x2Ed24638b3aB48cF0076f19199c78A62bfEb5889" } \ No newline at end of file diff --git a/deployments/mainnet.json b/deployments/mainnet.json index 882e58ff..f3b65867 100644 --- a/deployments/mainnet.json +++ b/deployments/mainnet.json @@ -19,5 +19,4 @@ "OsTokenFlashLoans": "0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2", "PriceFeed": "0x8023518b2192FB5384DAdc596765B3dD1cdFe471", "RewardSplitterFactory": "0x256aF27ce81282A0491A5361172c1Db08f6cC5F8", - "CumulativeMerkleDrop": "0x849DA65aFEd8483152f8Baa75F776c6f2C02E540" } \ No newline at end of file diff --git a/helpers/constants.ts b/helpers/constants.ts index f8af415f..83d66c5b 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -69,16 +69,6 @@ export const NETWORKS: { metadataIpfsHash: '', }, priceFeedDescription: 'osETH/ETH', - - // Cumulative MerkleDrop - liquidityCommittee: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - swiseToken: '0x484871C6D54a3dAEBeBBDB0AB7a54c97D72986Bb', - - // Restake vault settings - eigenPodManager: '0x30770d7E3e71112d7A6b7259542D1f680a70e315', - eigenDelegationManager: '0xA44151489861Fe9e3055d95adC98FbD462B948e7', - eigenDelayedWithdrawalRouter: '0x642c646053eaf2254f088e9019ACD73d9AE0FA32', - restakeFactoryOwner: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', }, [Networks.mainnet]: { url: process.env.MAINNET_RPC_URL || '', @@ -144,16 +134,6 @@ export const NETWORKS: { metadataIpfsHash: '', }, priceFeedDescription: 'osETH/ETH', - - // Cumulative MerkleDrop - liquidityCommittee: '0x189Cb93839AD52b5e955ddA254Ed7212ae1B1f61', - swiseToken: '0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2', - - // Restake vault settings - eigenPodManager: '0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338', - eigenDelegationManager: '0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A', - eigenDelayedWithdrawalRouter: '0x7Fe7E9CC0F274d2435AD5d56D5fa73E47F6A23D8', - restakeFactoryOwner: '0xf91AA4a655B6F43243ed4C2853F3508314DaA2aB', }, [Networks.chiado]: { url: process.env.CHIADO_RPC_URL || '', @@ -223,16 +203,6 @@ export const NETWORKS: { maxSlippage: 100, // 1% stalePriceTimeDelta: MAX_UINT128, // unlimited }, - - // Cumulative MerkleDrop - liquidityCommittee: '0x0000000000000000000000000000000000000000', - swiseToken: '0x0000000000000000000000000000000000000000', - - // Restake vault settings - eigenPodManager: '0x0000000000000000000000000000000000000000', - eigenDelegationManager: '0x0000000000000000000000000000000000000000', - eigenDelayedWithdrawalRouter: '0x0000000000000000000000000000000000000000', - restakeFactoryOwner: '0x0000000000000000000000000000000000000000', }, [Networks.gnosis]: { url: process.env.GNOSIS_RPC_URL || '', @@ -302,16 +272,6 @@ export const NETWORKS: { maxSlippage: 100, // 1% stalePriceTimeDelta: 172800n, // 48 hours }, - - // Cumulative MerkleDrop - liquidityCommittee: '0x0000000000000000000000000000000000000000', - swiseToken: '0x0000000000000000000000000000000000000000', - - // Restake vault settings - eigenPodManager: '0x0000000000000000000000000000000000000000', - eigenDelegationManager: '0x0000000000000000000000000000000000000000', - eigenDelayedWithdrawalRouter: '0x0000000000000000000000000000000000000000', - restakeFactoryOwner: '0x0000000000000000000000000000000000000000', }, } diff --git a/helpers/types.ts b/helpers/types.ts index e5227f18..1ecacc30 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -73,16 +73,6 @@ export type NetworkConfig = { // PriceFeed priceFeedDescription: string - - // Cumulative MerkleDrop - liquidityCommittee: string - swiseToken: string - - // Restake vault settings - eigenPodManager: string - eigenDelegationManager: string - eigenDelayedWithdrawalRouter: string - restakeFactoryOwner: string } export type GovernorCall = { diff --git a/tasks/eth-full-deploy-local.ts b/tasks/eth-full-deploy-local.ts index 0341f2e8..fb9ac00a 100644 --- a/tasks/eth-full-deploy-local.ts +++ b/tasks/eth-full-deploy-local.ts @@ -282,64 +282,6 @@ task('eth-full-deploy-local', 'deploys StakeWise V3 for Ethereum to local networ await callContract(vaultsRegistry.addVault(foxVaultAddress)) console.log('Added EthFoxVault to VaultsRegistry') - // Deploy EigenPodOwner implementation - constructorArgs = [ - networkConfig.eigenPodManager, - networkConfig.eigenDelegationManager, - networkConfig.eigenDelayedWithdrawalRouter, - ] - const eigenPodOwnerImpl = await deployContract(hre, 'EigenPodOwner', constructorArgs) - const eigenPodOwnerFactory = await ethers.getContractFactory('EigenPodOwner') - const eigenPodOwnerImplAddress = await eigenPodOwnerImpl.getAddress() - await simulateDeployImpl( - hre, - eigenPodOwnerFactory, - { constructorArgs }, - eigenPodOwnerImplAddress - ) - - // Deploy restake vaults - for (const vaultType of [ - 'EthRestakeVault', - 'EthRestakePrivVault', - 'EthRestakeBlocklistVault', - 'EthRestakeErc20Vault', - 'EthRestakePrivErc20Vault', - 'EthRestakeBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - validatorsRegistryAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - eigenPodOwnerImplAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract(hre, vaultType, constructorArgs) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // Deploy Restake Vault Factory - const vaultFactory = await deployContract(hre, 'EthRestakeVaultFactory', [ - networkConfig.governor, - vaultImplAddress, - vaultsRegistryAddress, - ]) - const vaultFactoryAddress = await vaultFactory.getAddress() - factories.push(vaultFactoryAddress) - - // Add factory to registry - await callContract(vaultsRegistry.addFactory(vaultFactoryAddress)) - console.log(`Added ${vaultType}Factory to VaultsRegistry`) - } - // Deploy PriceFeed const priceFeed = await deployContract(hre, 'PriceFeed', [ osTokenVaultControllerAddress, @@ -357,13 +299,6 @@ task('eth-full-deploy-local', 'deploys StakeWise V3 for Ethereum to local networ ]) const rewardSplitterFactoryAddress = await rewardSplitterFactory.getAddress() - // Deploy CumulativeMerkleDrop - const cumulativeMerkleDrop = await deployContract(hre, 'CumulativeMerkleDrop', [ - networkConfig.liquidityCommittee, - networkConfig.swiseToken, - ]) - const cumulativeMerkleDropAddress = await cumulativeMerkleDrop.getAddress() - // transfer ownership to governor await callContract(vaultsRegistry.initialize(networkConfig.governor)) console.log('VaultsRegistry ownership transferred to', networkConfig.governor) @@ -384,19 +319,12 @@ task('eth-full-deploy-local', 'deploys StakeWise V3 for Ethereum to local networ EthErc20VaultFactory: factories[3], EthPrivErc20VaultFactory: factories[4], EthBlocklistErc20VaultFactory: factories[5], - EthRestakeVaultFactory: factories[6], - EthRestakePrivVaultFactory: factories[7], - EthRestakeBlocklistVaultFactory: factories[8], - EthRestakeErc20VaultFactory: factories[9], - EthRestakePrivErc20VaultFactory: factories[10], - EthRestakeBlocklistErc20VaultFactory: factories[11], SharedMevEscrow: sharedMevEscrowAddress, OsToken: osTokenAddress, OsTokenConfig: osTokenConfigAddress, OsTokenVaultController: osTokenVaultControllerAddress, PriceFeed: priceFeedAddress, RewardSplitterFactory: rewardSplitterFactoryAddress, - CumulativeMerkleDrop: cumulativeMerkleDropAddress, } const json = JSON.stringify(addresses, null, 2) const fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` diff --git a/tasks/eth-full-deploy.ts b/tasks/eth-full-deploy.ts index b0faf304..8f4afca0 100644 --- a/tasks/eth-full-deploy.ts +++ b/tasks/eth-full-deploy.ts @@ -318,70 +318,6 @@ task('eth-full-deploy', 'deploys StakeWise V3 for Ethereum').setAction(async (ta await callContract(vaultsRegistry.addVault(foxVaultAddress)) console.log('Added EthFoxVault to VaultsRegistry') - // Deploy EigenPodOwner implementation - constructorArgs = [ - networkConfig.eigenPodManager, - networkConfig.eigenDelegationManager, - networkConfig.eigenDelayedWithdrawalRouter, - ] - const eigenPodOwnerImpl = await deployContract( - hre, - 'EigenPodOwner', - constructorArgs, - 'contracts/vaults/ethereum/restake/EigenPodOwner.sol:EigenPodOwner' - ) - const eigenPodOwnerFactory = await ethers.getContractFactory('EigenPodOwner') - const eigenPodOwnerImplAddress = await eigenPodOwnerImpl.getAddress() - await simulateDeployImpl(hre, eigenPodOwnerFactory, { constructorArgs }, eigenPodOwnerImplAddress) - - // Deploy restake vaults - for (const vaultType of [ - 'EthRestakeVault', - 'EthRestakePrivVault', - 'EthRestakeBlocklistVault', - 'EthRestakeErc20Vault', - 'EthRestakePrivErc20Vault', - 'EthRestakeBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - sharedMevEscrowAddress, - depositDataRegistryAddress, - eigenPodOwnerImplAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract( - hre, - vaultType, - constructorArgs, - `contracts/vaults/ethereum/restake/${vaultType}.sol:${vaultType}` - ) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // Deploy Restake Vault Factory - const vaultFactory = await deployContract( - hre, - 'EthRestakeVaultFactory', - [networkConfig.restakeFactoryOwner, vaultImplAddress, vaultsRegistryAddress], - 'contracts/vaults/ethereum/restake/EthRestakeVaultFactory.sol:EthRestakeVaultFactory' - ) - const vaultFactoryAddress = await vaultFactory.getAddress() - factories.push(vaultFactoryAddress) - - // Add factory to registry - await callContract(vaultsRegistry.addFactory(vaultFactoryAddress)) - console.log(`Added ${vaultType}Factory to VaultsRegistry`) - } - // Deploy PriceFeed const priceFeed = await deployContract( hre, @@ -409,15 +345,6 @@ task('eth-full-deploy', 'deploys StakeWise V3 for Ethereum').setAction(async (ta ) const rewardSplitterFactoryAddress = await rewardSplitterFactory.getAddress() - // Deploy CumulativeMerkleDrop - const cumulativeMerkleDrop = await deployContract( - hre, - 'CumulativeMerkleDrop', - [networkConfig.liquidityCommittee, networkConfig.swiseToken], - 'contracts/misc/CumulativeMerkleDrop.sol:CumulativeMerkleDrop' - ) - const cumulativeMerkleDropAddress = await cumulativeMerkleDrop.getAddress() - // transfer ownership to governor await callContract(vaultsRegistry.initialize(networkConfig.governor)) console.log('VaultsRegistry ownership transferred to', networkConfig.governor) @@ -439,19 +366,12 @@ task('eth-full-deploy', 'deploys StakeWise V3 for Ethereum').setAction(async (ta EthErc20VaultFactory: factories[3], EthPrivErc20VaultFactory: factories[4], EthBlocklistErc20VaultFactory: factories[5], - EthRestakeVaultFactory: factories[6], - EthRestakePrivVaultFactory: factories[7], - EthRestakeBlocklistVaultFactory: factories[8], - EthRestakeErc20VaultFactory: factories[9], - EthRestakePrivErc20VaultFactory: factories[10], - EthRestakeBlocklistErc20VaultFactory: factories[11], SharedMevEscrow: sharedMevEscrowAddress, OsToken: osTokenAddress, OsTokenConfig: osTokenConfigAddress, OsTokenVaultController: osTokenVaultControllerAddress, PriceFeed: priceFeedAddress, RewardSplitterFactory: rewardSplitterFactoryAddress, - CumulativeMerkleDrop: cumulativeMerkleDropAddress, } const json = JSON.stringify(addresses, null, 2) const fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` diff --git a/tasks/eth-upgrade.ts b/tasks/eth-upgrade.ts index e815f25d..09a812ad 100644 --- a/tasks/eth-upgrade.ts +++ b/tasks/eth-upgrade.ts @@ -32,7 +32,6 @@ task('eth-upgrade', 'upgrades StakeWise for Ethereum').setAction(async (taskArgs const genesisVaultAddress = deployment.EthGenesisVault const foxVaultAddress = deployment.EthFoxVault const priceFeedAddress = deployment.PriceFeed - const cumulativeMerkleDropAddress = deployment.CumulativeMerkleDrop const osTokenConfigAddress = deployment.OsTokenConfig const depositDataRegistryAddress = deployment.DepositDataRegistry const ethValidatorsCheckerAddress = deployment.EthValidatorsChecker @@ -157,7 +156,6 @@ task('eth-upgrade', 'upgrades StakeWise for Ethereum').setAction(async (taskArgs OsTokenFlashLoans: osTokenFlashLoansAddress, PriceFeed: priceFeedAddress, RewardSplitterFactory: rewardSplitterFactoryAddress, - CumulativeMerkleDrop: cumulativeMerkleDropAddress, } let json = JSON.stringify(addresses, null, 2) let fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` diff --git a/test/CumulativeMerkleDrop.spec.ts b/test/CumulativeMerkleDrop.spec.ts deleted file mode 100644 index 15686e40..00000000 --- a/test/CumulativeMerkleDrop.spec.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { ethers } from 'hardhat' -import { BigNumberish, Wallet } from 'ethers' -import { CumulativeMerkleDrop, ERC20Mock, ERC20Mock__factory } from '../typechain-types' -import { createCumulativeMerkleDrop } from './shared/fixtures' -import { StandardMerkleTree } from '@openzeppelin/merkle-tree' -import { expect } from './shared/expect' -import snapshotGasCost from './shared/snapshotGasCost' -import { PANIC_CODES } from './shared/constants' - -type RewardsTree = StandardMerkleTree<[string, BigNumberish]> - -describe('CumulativeMerkleDrop', () => { - const proofsIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const rewards: { address: string; reward: bigint }[] = [ - { address: '0x5E0375cFD64e036b37f74EbD213B061a0fFd6CC0', reward: 283n }, - { address: '0x3D238CccC9839f012ee613D1076F747093A25F16', reward: 649n }, - { address: '0xb12F7f27A07AB869761FF2bD11943db317a06466', reward: 779n }, - { address: '0x267a0909ea6043550D7054957061dC01eDd2915F', reward: 573n }, - { address: '0x03079134787b4570952Eacb53Bef82a7AF773fED', reward: 959n }, - { address: '0x704e14dFf77cdA4155BBC7b6AA8d3B39810aAE91', reward: 563n }, - { address: '0xC1016a99a8b37fDE1cFddf638f3d8Ec5B14c7d78', reward: 444n }, - { address: '0x6aBb7fFd8ad5770A90640ce7ca7647fA98a48702', reward: 172n }, - { address: '0x6c9A2c104D10fcA6510eF4B2c1E778aA94b50A5a', reward: 969n }, - { address: '0x408bdc9EF95A89F3B200eCb02dffEFEb87650da4', reward: 327n }, - ] - const tree: RewardsTree = StandardMerkleTree.of( - rewards.map((r) => [r.address, r.reward]), - ['address', 'uint256'] - ) as RewardsTree - let dao: Wallet, sender: Wallet - let merkleDrop: CumulativeMerkleDrop, token: ERC20Mock - - beforeEach('deploy fixtures', async () => { - ;[dao, sender] = await (ethers as any).getSigners() - const factory = await ethers.getContractFactory('ERC20Mock') - const contract = await factory.deploy() - token = ERC20Mock__factory.connect(await contract.getAddress(), dao) - merkleDrop = await createCumulativeMerkleDrop(await token.getAddress(), dao) - - let totalReward = 0n - for (let i = 0; i < 10; i++) { - totalReward += rewards[i].reward - } - await token.mint(await merkleDrop.getAddress(), totalReward) - }) - - describe('set merkle root', () => { - it('fails for not owner', async () => { - await expect( - merkleDrop.connect(sender).setMerkleRoot(tree.root, proofsIpfsHash) - ).revertedWithCustomError(merkleDrop, 'OwnableUnauthorizedAccount') - }) - - it('works for owner', async () => { - const receipt = await merkleDrop.connect(dao).setMerkleRoot(tree.root, proofsIpfsHash) - expect(await merkleDrop.merkleRoot()).to.eq(tree.root) - await expect(receipt) - .to.emit(merkleDrop, 'MerkleRootUpdated') - .withArgs(tree.root, proofsIpfsHash) - await snapshotGasCost(receipt) - }) - }) - - describe('claim', () => { - beforeEach('set merkle root', async () => { - await merkleDrop.connect(dao).setMerkleRoot(tree.root, proofsIpfsHash) - }) - - it('fails with invalid proof', async () => { - const reward = rewards[0] - await expect( - merkleDrop.claim( - reward.address, - reward.reward, - tree.getProof([rewards[1].address, rewards[1].reward]) - ) - ).revertedWithCustomError(merkleDrop, 'InvalidProof') - }) - - it('reverts with cumulative amount less than previous', async () => { - let reward = rewards[0] - await merkleDrop.claim( - reward.address, - reward.reward, - tree.getProof([reward.address, reward.reward]) - ) - const newRewards = [{ address: reward.address, reward: reward.reward - 1n }] - const newTree = StandardMerkleTree.of( - newRewards.map((r) => [r.address, r.reward]), - ['address', 'uint256'] - ) as RewardsTree - await merkleDrop.connect(dao).setMerkleRoot(newTree.root, proofsIpfsHash) - - reward = newRewards[0] - await expect( - merkleDrop.claim( - reward.address, - reward.reward, - newTree.getProof([reward.address, reward.reward]) - ) - ).revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('works with valid proof', async () => { - const reward = rewards[0] - const receipt = await merkleDrop.claim( - reward.address, - reward.reward, - tree.getProof([reward.address, reward.reward]) - ) - await expect(receipt).to.emit(merkleDrop, 'Claimed').withArgs(reward.address, reward.reward) - await snapshotGasCost(receipt) - - // fails to claim second time - await expect( - merkleDrop.claim( - reward.address, - reward.reward, - tree.getProof([reward.address, reward.reward]) - ) - ).revertedWithCustomError(merkleDrop, 'AlreadyClaimed') - }) - }) -}) diff --git a/test/__snapshots__/CumulativeMerkleDrop.spec.ts.snap b/test/__snapshots__/CumulativeMerkleDrop.spec.ts.snap deleted file mode 100644 index 0683225d..00000000 --- a/test/__snapshots__/CumulativeMerkleDrop.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CumulativeMerkleDrop claim works with valid proof 1`] = ` -Object { - "calldataByteLength": 228, - "gasUsed": 83633, -} -`; - -exports[`CumulativeMerkleDrop set merkle root works for owner 1`] = ` -Object { - "calldataByteLength": 164, - "gasUsed": 49750, -} -`; diff --git a/test/restake/EigenPodOwner.spec.ts b/test/restake/EigenPodOwner.spec.ts deleted file mode 100644 index 9640e264..00000000 --- a/test/restake/EigenPodOwner.spec.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { loadFixture, mine } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { ethers } from 'hardhat' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { - EigenPodOwner, - EigenPodOwner__factory, - EthRestakeVault, - EigenPodOwnerV2Mock__factory, -} from '../../typechain-types' -import { expect } from '../shared/expect' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { MAX_UINT256, ZERO_ADDRESS, ZERO_BYTES32 } from '../shared/constants' -import { extractEigenPodOwner, setBalance } from '../shared/utils' -import { - getEigenDelayedWithdrawalRouter, - getEigenDelegationManager, - getEigenPodManager, -} from '../shared/contracts' -import { registerEthValidator } from '../shared/validators' -import { MAINNET_FORK } from '../../helpers/constants' -import snapshotGasCost from '../shared/snapshotGasCost' - -const gwei = 1000000000n -const validatorDeposit = parseEther('32') - -describe('EigenPodOwner', () => { - const capacity = MAX_UINT256 - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - let admin: Signer, operatorsManager: Wallet, other: Wallet, withdrawalsManager: Wallet - let vault: EthRestakeVault, - eigenPodOwner: EigenPodOwner, - delegationManager: Contract, - eigenPodManager: Contract, - delayedWithdrawalRouter: Contract - let eigenPodAddress: string - - before('create fixture loader', async function () { - ;[admin, operatorsManager, withdrawalsManager, other] = await (ethers as any).getSigners() - }) - - beforeEach('deploy fixture', async () => { - const fixture = await loadFixture(ethRestakeVaultFixture) - eigenPodManager = await getEigenPodManager() - delegationManager = await getEigenDelegationManager() - delayedWithdrawalRouter = await getEigenDelayedWithdrawalRouter() - vault = await fixture.createEthRestakeVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - await vault.connect(admin).setRestakeOperatorsManager(operatorsManager.address) - await vault.connect(admin).setRestakeWithdrawalsManager(withdrawalsManager.address) - const receipt = await vault.connect(operatorsManager).createEigenPod() - const eigenPodOwnerAddr = await extractEigenPodOwner(receipt) - eigenPodOwner = EigenPodOwner__factory.connect(eigenPodOwnerAddr, admin) - eigenPodAddress = (await vault.getEigenPods())[0] - - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: validatorDeposit }) - await registerEthValidator( - vault, - fixture.keeper, - fixture.depositDataRegistry, - admin, - fixture.validatorsRegistry - ) - }) - - it('initializes correctly', async () => { - await expect(eigenPodOwner.initialize(ZERO_BYTES32)).to.revertedWithCustomError( - eigenPodOwner, - 'InvalidInitialization' - ) - expect(await eigenPodOwner.vault()).to.equal(await vault.getAddress()) - const eigenPod = (await vault.getEigenPods())[0] - expect(await eigenPodOwner.eigenPod()).to.equal(eigenPod) - }) - - describe('delegation', () => { - beforeEach(async () => { - const eigenPod = await ethers.getImpersonatedSigner(eigenPodAddress) - await setBalance(eigenPod.address, parseEther('1')) - await eigenPodManager - .connect(eigenPod) - .recordBeaconChainETHBalanceUpdate(eigenPodOwner, validatorDeposit / gwei) - }) - - it('not operators manager cannot delegate', async () => { - await expect( - eigenPodOwner - .connect(other) - .delegateTo(MAINNET_FORK.eigenOperator, { signature: '0x', expiry: 0 }, ZERO_BYTES32) - ).to.revertedWithCustomError(eigenPodOwner, 'AccessDenied') - }) - - it('operators manager can delegate', async () => { - const receipt = await eigenPodOwner - .connect(operatorsManager) - .delegateTo(MAINNET_FORK.eigenOperator, { signature: '0x', expiry: 0 }, ZERO_BYTES32) - expect(await delegationManager.delegatedTo(await eigenPodOwner.getAddress())).to.be.eq( - MAINNET_FORK.eigenOperator - ) - await snapshotGasCost(receipt) - }) - - it('not operators manager cannot undelegate', async () => { - await expect(eigenPodOwner.connect(other).undelegate()).to.revertedWithCustomError( - eigenPodOwner, - 'AccessDenied' - ) - }) - - it('operator manager can undelegate', async () => { - await eigenPodOwner - .connect(operatorsManager) - .delegateTo(MAINNET_FORK.eigenOperator, { signature: '0x', expiry: 0 }, ZERO_BYTES32) - const receipt = await eigenPodOwner.connect(operatorsManager).undelegate() - expect(await delegationManager.delegatedTo(await eigenPodOwner.getAddress())).to.be.eq( - ZERO_ADDRESS - ) - await snapshotGasCost(receipt) - }) - }) - - describe('withdrawals', () => { - const withdrawalShares = validatorDeposit / gwei - - beforeEach(async () => { - const eigenPod = await ethers.getImpersonatedSigner(eigenPodAddress) - await setBalance(eigenPod.address, parseEther('1')) - await eigenPodManager - .connect(eigenPod) - .recordBeaconChainETHBalanceUpdate(eigenPodOwner, withdrawalShares) - await eigenPodOwner - .connect(operatorsManager) - .delegateTo(MAINNET_FORK.eigenOperator, { signature: '0x', expiry: 0 }, ZERO_BYTES32) - }) - - it('not withdrawals manager cannot queue withdrawal', async () => { - await expect( - eigenPodOwner.connect(other).queueWithdrawal(withdrawalShares) - ).to.revertedWithCustomError(eigenPodOwner, 'AccessDenied') - }) - - it('withdrawals manager can queue withdrawal', async () => { - const receipt = await eigenPodOwner - .connect(withdrawalsManager) - .queueWithdrawal(withdrawalShares / 2n) - expect(await eigenPodManager.podOwnerShares(await eigenPodOwner.getAddress())).to.be.eq( - withdrawalShares / 2n - ) - await snapshotGasCost(receipt) - }) - - it('not withdrawals manager cannot complete withdrawal', async () => { - await expect( - eigenPodOwner - .connect(other) - .completeQueuedWithdrawal(MAINNET_FORK.eigenOperator, 0, withdrawalShares, 0, 0, false) - ).to.revertedWithCustomError(eigenPodOwner, 'AccessDenied') - }) - - it('withdrawals manager can complete withdrawal', async () => { - let receipt = await eigenPodOwner - .connect(withdrawalsManager) - .queueWithdrawal(withdrawalShares) - const withdrawalBlockNumber = receipt.blockNumber as number - const eigenPodOwnerAddress = await eigenPodOwner.getAddress() - expect(await eigenPodManager.podOwnerShares(eigenPodOwnerAddress)).to.be.eq(0) - - await mine(await delegationManager.minWithdrawalDelayBlocks()) - receipt = await eigenPodOwner - .connect(withdrawalsManager) - .completeQueuedWithdrawal( - MAINNET_FORK.eigenOperator, - 0, - withdrawalShares, - withdrawalBlockNumber, - 0, - false - ) - expect(await eigenPodManager.podOwnerShares(eigenPodOwnerAddress)).to.be.eq(withdrawalShares) - await snapshotGasCost(receipt) - }) - - it('not eigen pod or delayed withdrawals manager cannot transfer assets', async () => { - await expect( - other.sendTransaction({ - to: await eigenPodOwner.getAddress(), - value: parseEther('1'), - }) - ).to.be.revertedWithCustomError(eigenPodOwner, 'AccessDenied') - }) - - it('can claim delayed withdrawals', async () => { - const eigenPod = await ethers.getImpersonatedSigner(eigenPodAddress) - const eigenPodOwnerAddress = await eigenPodOwner.getAddress() - await setBalance(eigenPod.address, parseEther('11')) - - const withdrawalAmount = parseEther('10') - await delayedWithdrawalRouter - .connect(eigenPod) - .createDelayedWithdrawal(eigenPodOwnerAddress, eigenPodOwnerAddress, { - value: withdrawalAmount, - }) - - const totalAssetsBefore = await vault.totalAssets() - const totalSharesBefore = await vault.totalShares() - const vaultBalanceBefore = await ethers.provider.getBalance(await vault.getAddress()) - - await mine(await delayedWithdrawalRouter.withdrawalDelayBlocks()) - const receipt = await eigenPodOwner.claimDelayedWithdrawals(1) - - expect(await vault.totalAssets()).to.be.eq(totalAssetsBefore) - expect(await vault.totalShares()).to.be.eq(totalSharesBefore) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq( - vaultBalanceBefore + withdrawalAmount - ) - - await snapshotGasCost(receipt) - }) - }) - describe('upgrade', () => { - it('fails to upgrade by not vault', async () => { - await expect( - eigenPodOwner.connect(other).upgradeToAndCall(other.address, '0x') - ).to.revertedWithCustomError(eigenPodOwner, 'AccessDenied') - }) - - it('fails to upgrade to same implementation', async () => { - const vaultSigner = await ethers.getImpersonatedSigner(await vault.getAddress()) - await setBalance(vaultSigner.address, parseEther('1')) - - await expect( - eigenPodOwner - .connect(vaultSigner) - .upgradeToAndCall(await eigenPodOwner.implementation(), '0x') - ).to.revertedWithCustomError(eigenPodOwner, 'UpgradeFailed') - }) - - it('fails to upgrade to zero address', async () => { - const vaultSigner = await ethers.getImpersonatedSigner(await vault.getAddress()) - await setBalance(vaultSigner.address, parseEther('1')) - await expect( - eigenPodOwner.connect(vaultSigner).upgradeToAndCall(ZERO_ADDRESS, '0x') - ).to.revertedWithCustomError(eigenPodOwner, 'UpgradeFailed') - }) - - it('succeeds to upgrade', async () => { - const vaultSigner = await ethers.getImpersonatedSigner(await vault.getAddress()) - await setBalance(vaultSigner.address, parseEther('1')) - - const newImplementation = await ethers.getContractFactory('EigenPodOwnerV2Mock') - const newImplementationAddress = await newImplementation.deploy( - MAINNET_FORK.eigenPodManager, - MAINNET_FORK.eigenDelegationManager, - MAINNET_FORK.eigenDelayedWithdrawalRouter - ) - const receipt = await eigenPodOwner - .connect(vaultSigner) - .upgradeToAndCall(newImplementationAddress, '0x') - - const eigenPodOwnerV2 = EigenPodOwnerV2Mock__factory.connect( - await eigenPodOwner.getAddress(), - admin - ) - expect(await eigenPodOwnerV2.implementation()).to.be.eq(newImplementationAddress) - expect(await eigenPodOwnerV2.somethingNew()).to.be.eq(true) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/restake/EthRestakeBlocklistErc20Vault.spec.ts b/test/restake/EthRestakeBlocklistErc20Vault.spec.ts deleted file mode 100644 index e8489696..00000000 --- a/test/restake/EthRestakeBlocklistErc20Vault.spec.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthRestakeBlocklistErc20Vault } from '../../typechain-types' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' -import { createDepositorMock } from '../shared/fixtures' - -describe('EthRestakeBlocklistErc20Vault', () => { - const name = 'SW Vault' - const symbol = 'SW-1' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, blocklistManager: Wallet, receiver: Wallet - let vault: EthRestakeBlocklistErc20Vault - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, blocklistManager] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethRestakeVaultFixture) - vault = await fixture.createEthRestakeBlocklistErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq( - `0x${keccak256('EthRestakeBlocklistErc20Vault').toString('hex')}` - ) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('transfer', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - vault.connect(sender).deposit(receiver.address, ZERO_ADDRESS, { value: amount }) - }) - - it('cannot transfer to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot transfer from blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(sender.address, true) - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can transfer', async () => { - const receipt = await vault.connect(receiver).transfer(other.address, amount) - expect(await vault.balanceOf(receiver.address)).to.eq(0) - expect(await vault.balanceOf(other.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(receiver.address, other.address, amount) - await snapshotGasCost(receipt) - }) - }) - - describe('deposit', () => { - const assets = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be called by blocked sender', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(other).deposit(sender.address, ZERO_ADDRESS, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).deposit(other.address, ZERO_ADDRESS, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('deposit through receive fallback cannot be called by blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await vault.connect(blocklistManager).updateBlocklist(await depositorMock.getAddress(), true) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by not blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - it('can be called by not blocked user', async () => { - const receipt = await vault - .connect(sender) - .deposit(receiver.address, ZERO_ADDRESS, { value: assets }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, assets, shares, referrer) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/restake/EthRestakeBlocklistVault.spec.ts b/test/restake/EthRestakeBlocklistVault.spec.ts deleted file mode 100644 index f69978bf..00000000 --- a/test/restake/EthRestakeBlocklistVault.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { ethers } from 'hardhat' -import { parseEther, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthRestakeBlocklistVault } from '../../typechain-types' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' -import { createDepositorMock } from '../shared/fixtures' - -describe('EthRestakeBlocklistVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, blocklistManager: Wallet, receiver: Wallet - let vault: EthRestakeBlocklistVault - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, blocklistManager] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethRestakeVaultFixture) - vault = await fixture.createEthRestakeBlocklistVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq( - `0x${keccak256('EthRestakeBlocklistVault').toString('hex')}` - ) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const assets = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be called by blocked sender', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(other).deposit(receiver.address, ZERO_ADDRESS, { value: parseEther('1') }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).deposit(other.address, ZERO_ADDRESS, { value: parseEther('1') }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('deposit through receive fallback cannot be called by blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await vault.connect(blocklistManager).updateBlocklist(await depositorMock.getAddress(), true) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by not blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - it('can be called by not blocked user', async () => { - const receipt = await vault - .connect(sender) - .deposit(receiver.address, ZERO_ADDRESS, { value: parseEther('1') }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, assets, shares, referrer) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/restake/EthRestakeErc20Vault.spec.ts b/test/restake/EthRestakeErc20Vault.spec.ts deleted file mode 100644 index c972c1e6..00000000 --- a/test/restake/EthRestakeErc20Vault.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import keccak256 from 'keccak256' -import { EthRestakeErc20Vault, Keeper, DepositDataRegistry } from '../../typechain-types' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import { extractExitPositionTicket } from '../shared/utils' -import { collateralizeEthVault } from '../shared/rewards' - -describe('EthRestakeErc20Vault', () => { - const name = 'SW Vault' - const symbol = 'SW-1' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, receiver: Wallet - let vault: EthRestakeErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethRestakeVaultFixture) - vault = await fixture.createEthRestakeErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthRestakeErc20Vault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - it('deposit emits transfer event', async () => { - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - const receipt = await vault - .connect(sender) - .deposit(receiver.address, ZERO_ADDRESS, { value: amount }) - expect(await vault.balanceOf(receiver.address)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, expectedShares, referrer) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(ZERO_ADDRESS, receiver.address, expectedShares) - await snapshotGasCost(receipt) - }) - - it('enter exit queue emits transfer event', async () => { - await vault.connect(admin).createEigenPod() - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const queuedSharesBefore = await vault.queuedShares() - const totalAssetsBefore = await vault.totalAssets() - const totalSharesBefore = await vault.totalShares() - - const amount = ethers.parseEther('100') - const shares = await vault.convertToShares(amount) - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: amount }) - expect(await vault.balanceOf(sender.address)).to.be.eq(shares) - - const receipt = await vault.connect(sender).enterExitQueue(shares, receiver.address) - const positionTicket = await extractExitPositionTicket(receipt) - await expect(receipt) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(sender.address, receiver.address, positionTicket, shares) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, await vault.getAddress(), shares) - expect(await vault.queuedShares()).to.be.eq(queuedSharesBefore + shares) - expect(await vault.totalAssets()).to.be.eq(totalAssetsBefore + amount) - expect(await vault.totalSupply()).to.be.eq(totalSharesBefore + shares) - expect(await vault.balanceOf(sender.address)).to.be.eq(0) - - await snapshotGasCost(receipt) - }) -}) diff --git a/test/restake/EthRestakePrivErc20Vault.spec.ts b/test/restake/EthRestakePrivErc20Vault.spec.ts deleted file mode 100644 index c838ff12..00000000 --- a/test/restake/EthRestakePrivErc20Vault.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthRestakePrivErc20Vault } from '../../typechain-types' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' -import { createDepositorMock } from '../shared/fixtures' - -describe('EthRestakePrivErc20Vault', () => { - const name = 'SW Vault' - const symbol = 'SW-1' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, whitelister: Wallet, receiver: Wallet - let vault: EthRestakePrivErc20Vault - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, whitelister] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethRestakeVaultFixture) - vault = await fixture.createEthRestakePrivErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq( - `0x${keccak256('EthRestakePrivErc20Vault').toString('hex')}` - ) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(whitelister.address) - await vault.connect(whitelister).updateWhitelist(sender.address, true) - }) - - it('cannot be called by not whitelisted sender', async () => { - await expect( - vault.connect(receiver).deposit(sender.address, ZERO_ADDRESS, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to not whitelisted user', async () => { - await expect( - vault.connect(sender).deposit(receiver.address, ZERO_ADDRESS, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('deposit through receive fallback cannot be called by not whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - await vault.connect(whitelister).updateWhitelist(depositorMockAddress, true) - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - it('can be called by whitelisted user', async () => { - const receipt = await vault - .connect(sender) - .deposit(sender.address, ZERO_ADDRESS, { value: amount }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, amount, shares, referrer) - await snapshotGasCost(receipt) - }) - }) - - describe('transfer', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).updateWhitelist(sender.address, true) - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: amount }) - }) - - it('cannot transfer to not whitelisted user', async () => { - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot transfer from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(other.address, true) - await vault.connect(sender).transfer(other.address, amount) - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(other).transfer(sender.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can transfer to whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(other.address, true) - const receipt = await vault.connect(sender).transfer(other.address, amount) - expect(await vault.balanceOf(sender.address)).to.eq(0) - expect(await vault.balanceOf(other.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, other.address, amount) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/restake/EthRestakePrivVault.spec.ts b/test/restake/EthRestakePrivVault.spec.ts deleted file mode 100644 index 8440e3eb..00000000 --- a/test/restake/EthRestakePrivVault.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { ethers } from 'hardhat' -import { parseEther, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthRestakePrivVault } from '../../typechain-types' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' -import { createDepositorMock } from '../shared/fixtures' - -describe('EthRestakePrivVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, whitelister: Wallet, receiver: Wallet - let vault: EthRestakePrivVault - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, whitelister] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethRestakeVaultFixture) - vault = await fixture.createEthRestakePrivVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthRestakePrivVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(whitelister.address) - await vault.connect(whitelister).updateWhitelist(sender.address, true) - }) - - it('cannot be called by not whitelisted sender', async () => { - await expect( - vault.connect(receiver).deposit(receiver.address, ZERO_ADDRESS, { value: parseEther('1') }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to not whitelisted user', async () => { - await expect( - vault.connect(sender).deposit(receiver.address, ZERO_ADDRESS, { value: parseEther('1') }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('deposit through receive fallback cannot be called by not whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - await vault.connect(whitelister).updateWhitelist(depositorMockAddress, true) - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - it('can be called by whitelisted user', async () => { - await vault.connect(whitelister).updateWhitelist(receiver.address, true) - const receipt = await vault - .connect(sender) - .deposit(receiver.address, ZERO_ADDRESS, { value: parseEther('1') }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, shares, referrer) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/restake/EthRestakeVault.spec.ts b/test/restake/EthRestakeVault.spec.ts deleted file mode 100644 index 1e060c78..00000000 --- a/test/restake/EthRestakeVault.spec.ts +++ /dev/null @@ -1,350 +0,0 @@ -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { ethers } from 'hardhat' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { EthRestakeVault, Keeper } from '../../typechain-types' -import { ethRestakeVaultFixture } from '../shared/restakeFixtures' -import { ThenArg } from '../../helpers/types' -import { - MAX_UINT256, - VALIDATORS_DEADLINE, - VALIDATORS_MIN_ORACLES, - ZERO_ADDRESS, - ZERO_BYTES32, -} from '../shared/constants' -import { expect } from '../shared/expect' -import { extractEigenPodOwner, toHexString } from '../shared/utils' -import { - createEthValidatorsData, - EthValidatorsData, - exitSignatureIpfsHashes, - getEthValidatorsSigningData, - getWithdrawalCredentials, -} from '../shared/validators' -import snapshotGasCost from '../shared/snapshotGasCost' -import { getOraclesSignatures } from '../shared/fixtures' -import { UintNumberType } from '@chainsafe/ssz' -import { getEigenPodManager } from '../shared/contracts' -import keccak256 from 'keccak256' - -const gwei = 1000000000n -const uintSerializer = new UintNumberType(8) -const validatorDeposit = parseEther('32') - -describe('EthRestakeVault', () => { - const capacity = MAX_UINT256 - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - let admin: Signer, - operatorsManager: Wallet, - validatorsManager: Wallet, - other: Wallet, - withdrawalsManager: Wallet - let vault: EthRestakeVault, keeper: Keeper, validatorsRegistry: Contract - let createVault: ThenArg>['createEthRestakeVault'] - - before('create fixture loader', async function () { - ;[admin, operatorsManager, validatorsManager, withdrawalsManager, other] = await ( - ethers as any - ).getSigners() - }) - - beforeEach('deploy fixture', async () => { - ;({ - createEthRestakeVault: createVault, - keeper, - validatorsRegistry, - } = await loadFixture(ethRestakeVaultFixture)) - vault = await createVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - }) - - it('initializes correctly', async () => { - await expect(vault.connect(admin).initialize(ZERO_BYTES32)).to.revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - expect(await vault.capacity()).to.be.eq(capacity) - - // VaultAdmin - const adminAddr = await admin.getAddress() - - // VaultVersion - expect(await vault.version()).to.be.eq(3) - expect(await vault.vaultId()).to.be.eq(`0x${keccak256('EthRestakeVault').toString('hex')}`) - - // VaultFee - expect(await vault.admin()).to.be.eq(adminAddr) - expect(await vault.feeRecipient()).to.be.eq(adminAddr) - expect(await vault.feePercent()).to.be.eq(feePercent) - }) - - describe('create eigen pod', () => { - let eigenPodManager: Contract - - beforeEach(async () => { - eigenPodManager = await getEigenPodManager() - }) - - it('fails for non-operators manager', async () => { - await expect(vault.connect(other).createEigenPod()).to.be.revertedWithCustomError( - vault, - 'AccessDenied' - ) - }) - - it('succeeds', async () => { - const receipt = await vault.connect(admin).createEigenPod() - expect(await vault.getEigenPods()).to.have.lengthOf(1) - - const eigenPodOwner = await extractEigenPodOwner(receipt) - const eigenPod = (await vault.getEigenPods())[0] - await expect(receipt).to.emit(vault, 'EigenPodCreated').withArgs(eigenPodOwner, eigenPod) - expect(await eigenPodManager.ownerToPod(eigenPodOwner)).to.eq(eigenPod) - await snapshotGasCost(receipt) - }) - }) - - describe('restake operators manager', () => { - it('defaults to admin', async () => { - expect(await vault.restakeOperatorsManager()).to.equal(await admin.getAddress()) - }) - - it('fails to set by non-admin', async () => { - await expect( - vault.connect(other).setRestakeOperatorsManager(other.address) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails to set to the same address', async () => { - await vault.connect(admin).setRestakeOperatorsManager(other.address) - await expect( - vault.connect(admin).setRestakeOperatorsManager(other.address) - ).to.be.revertedWithCustomError(vault, 'ValueNotChanged') - }) - - it('succeeds', async () => { - const receipt = await vault - .connect(admin) - .setRestakeOperatorsManager(operatorsManager.address) - expect(await vault.restakeOperatorsManager()).to.equal(operatorsManager.address) - await expect(receipt) - .to.emit(vault, 'RestakeOperatorsManagerUpdated') - .withArgs(operatorsManager.address) - await snapshotGasCost(receipt) - }) - }) - - describe('restake withdrawals manager', () => { - it('defaults to admin', async () => { - expect(await vault.restakeWithdrawalsManager()).to.equal(await admin.getAddress()) - }) - - it('fails to set by non-admin', async () => { - await expect( - vault.connect(other).setRestakeWithdrawalsManager(other.address) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails to set to the same address', async () => { - await vault.connect(admin).setRestakeWithdrawalsManager(other.address) - await expect( - vault.connect(admin).setRestakeWithdrawalsManager(other.address) - ).to.be.revertedWithCustomError(vault, 'ValueNotChanged') - }) - - it('succeeds', async () => { - const receipt = await vault - .connect(admin) - .setRestakeWithdrawalsManager(withdrawalsManager.address) - expect(await vault.restakeWithdrawalsManager()).to.equal(withdrawalsManager.address) - await expect(receipt) - .to.emit(vault, 'RestakeWithdrawalsManagerUpdated') - .withArgs(withdrawalsManager.address) - await snapshotGasCost(receipt) - }) - }) - - describe('single validator', () => { - const deadline = VALIDATORS_DEADLINE - let validatorsData: EthValidatorsData - let eigenPod: string - - beforeEach(async () => { - await vault.connect(admin).setRestakeOperatorsManager(operatorsManager.address) - await vault.connect(admin).setValidatorsManager(validatorsManager.address) - await vault.connect(operatorsManager).createEigenPod() - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: validatorDeposit }) - eigenPod = (await vault.getEigenPods())[0] - validatorsData = await createEthValidatorsData(vault) - }) - - it('fails with invalid validator length', async () => { - let invalidValidator = validatorsData.validators[0] - invalidValidator = invalidValidator.subarray(0, invalidValidator.length - 1) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: invalidValidator, - deadline, - signatures, - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - }) - - it('fails with invalid withdrawal address', async () => { - const invalidValidator = Buffer.concat([ - validatorsData.validators[0].subarray(0, 176), - ethers.getBytes(await vault.getAddress()), - ]) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: invalidValidator, - deadline, - signatures, - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWithCustomError(vault, 'EigenPodNotFound') - }) - - it('succeeds', async () => { - const index = await validatorsRegistry.get_deposit_count() - const validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const validator = validatorsData.validators[0] - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - validator, - deadline, - exitSignatureIpfsHashes[0], - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - - const receipt = await vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: validator, - deadline, - signatures, - exitSignaturesIpfsHash: exitSignatureIpfsHashes[0], - }, - '0x' - ) - const publicKey = `0x${validator.subarray(0, 48).toString('hex')}` - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(eigenPod)), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - index - ) - await snapshotGasCost(receipt) - }) - }) - - describe('multiple validators', () => { - const deadline = VALIDATORS_DEADLINE - let validatorsData: EthValidatorsData - let eigenPod: string - - beforeEach(async () => { - await vault.connect(admin).setRestakeOperatorsManager(operatorsManager.address) - await vault.connect(admin).setValidatorsManager(validatorsManager.address) - await vault.connect(operatorsManager).createEigenPod() - eigenPod = (await vault.getEigenPods())[0] - validatorsData = await createEthValidatorsData(vault) - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { - value: validatorDeposit * BigInt(validatorsData.validators.length), - }) - }) - - it('succeeds', async () => { - const validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.concat(validatorsData.validators), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - const approvalParams = { - validatorsRegistryRoot, - validators: Buffer.concat(validatorsData.validators), - signatures, - exitSignaturesIpfsHash, - deadline, - } - const startIndex = uintSerializer.deserialize( - ethers.getBytes(await validatorsRegistry.get_deposit_count()) - ) - const receipt = await vault - .connect(validatorsManager) - .registerValidators(approvalParams, '0x') - for (let i = 0; i < validatorsData.validators.length; i++) { - const validator = validatorsData.validators[i] - const publicKey = toHexString(validator.subarray(0, 48)) - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(eigenPod)), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - toHexString(Buffer.from(uintSerializer.serialize(startIndex + i))) - ) - } - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/restake/EthRestakeVault.upgrade.spec.ts b/test/restake/EthRestakeVault.upgrade.spec.ts deleted file mode 100644 index f601287a..00000000 --- a/test/restake/EthRestakeVault.upgrade.spec.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - DepositDataRegistry, - EthRestakeVault__factory, - EthVaultFactory, - Keeper, - SharedMevEscrow, - VaultsRegistry, -} from '../../typechain-types' -import snapshotGasCost from '../shared/snapshotGasCost' -import { - deployEthRestakeVaultV2, - encodeEthRestakeErc20VaultInitParams, - encodeEthRestakeVaultInitParams, - ethRestakeVaultFixture, -} from '../shared/restakeFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import { - getEthRestakeBlocklistErc20VaultV2Factory, - getEthRestakeBlocklistVaultV2Factory, - getEthRestakeErc20VaultV2Factory, - getEthRestakePrivErc20VaultV2Factory, - getEthRestakePrivVaultV2Factory, - getEthRestakeVaultV2Factory, -} from '../shared/contracts' - -describe('EthRestakeVault - upgrade', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7r' - let admin: Signer, other: Wallet - let vaultsRegistry: VaultsRegistry, - keeper: Keeper, - validatorsRegistry: Contract, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - ethRestakeVaultFactory: EthVaultFactory, - ethRestakePrivVaultFactory: EthVaultFactory, - ethRestakeBlocklistVaultFactory: EthVaultFactory, - ethRestakeErc20VaultFactory: EthVaultFactory, - ethRestakePrivErc20VaultFactory: EthVaultFactory, - ethRestakeBlocklistErc20VaultFactory: EthVaultFactory, - eigenPodOwnerImpl: string - let fixture: any - - beforeEach('deploy fixture', async () => { - ;([admin, other] = await (ethers as any).getSigners()).slice(1, 3) - fixture = await loadFixture(ethRestakeVaultFixture) - vaultsRegistry = fixture.vaultsRegistry - validatorsRegistry = fixture.validatorsRegistry - keeper = fixture.keeper - sharedMevEscrow = fixture.sharedMevEscrow - depositDataRegistry = fixture.depositDataRegistry - ethRestakeVaultFactory = fixture.ethRestakeVaultFactory - ethRestakePrivVaultFactory = fixture.ethRestakePrivVaultFactory - ethRestakeBlocklistVaultFactory = fixture.ethRestakeBlocklistVaultFactory - ethRestakeErc20VaultFactory = fixture.ethRestakeErc20VaultFactory - ethRestakePrivErc20VaultFactory = fixture.ethRestakePrivErc20VaultFactory - ethRestakeBlocklistErc20VaultFactory = fixture.ethRestakeBlocklistErc20VaultFactory - eigenPodOwnerImpl = fixture.eigenPodOwnerImplementation - }) - - it('does not modify the state variables', async () => { - const vaults: Contract[] = [] - for (const factory of [ - await getEthRestakeVaultV2Factory(), - await getEthRestakePrivVaultV2Factory(), - await getEthRestakeBlocklistVaultV2Factory(), - ]) { - const vault = await deployEthRestakeVaultV2( - factory, - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImpl, - encodeEthRestakeVaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - }) - ) - vaults.push(vault) - } - for (const factory of [ - await getEthRestakeErc20VaultV2Factory(), - await getEthRestakePrivErc20VaultV2Factory(), - await getEthRestakeBlocklistErc20VaultV2Factory(), - ]) { - const vault = await deployEthRestakeVaultV2( - factory, - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImpl, - encodeEthRestakeErc20VaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - name: 'Vault', - symbol: 'VLT', - }) - ) - vaults.push(vault) - } - - const checkVault = async (vault: Contract, newImpl: string) => { - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: parseEther('3') }) - await vault.connect(other).enterExitQueue(parseEther('1'), other.address) - - const userShares = await vault.getShares(other.address) - const userAssets = await vault.convertToAssets(userShares) - const mevEscrow = await vault.mevEscrow() - const totalAssets = await vault.totalAssets() - const totalShares = await vault.totalShares() - const vaultAddress = await vault.getAddress() - expect(await vault.version()).to.be.eq(2) - - const receipt = await vault.connect(admin).upgradeToAndCall(newImpl, '0x') - const vaultV3 = EthRestakeVault__factory.connect(vaultAddress, admin) - expect(await vaultV3.version()).to.be.eq(3) - expect(await vaultV3.implementation()).to.be.eq(newImpl) - expect(await vaultV3.getShares(other.address)).to.be.eq(userShares) - expect(await vaultV3.convertToAssets(userShares)).to.be.deep.eq(userAssets) - expect(await vaultV3.validatorsManager()).to.be.eq(await depositDataRegistry.getAddress()) - expect(await vaultV3.mevEscrow()).to.be.eq(mevEscrow) - expect(await vaultV3.totalAssets()).to.be.eq(totalAssets) - expect(await vaultV3.totalShares()).to.be.eq(totalShares) - await snapshotGasCost(receipt) - } - await checkVault(vaults[0], await ethRestakeVaultFactory.implementation()) - await vaults[1].connect(admin).updateWhitelist(other.address, true) - await checkVault(vaults[1], await ethRestakePrivVaultFactory.implementation()) - await checkVault(vaults[2], await ethRestakeBlocklistVaultFactory.implementation()) - - await checkVault(vaults[3], await ethRestakeErc20VaultFactory.implementation()) - await vaults[4].connect(admin).updateWhitelist(other.address, true) - await checkVault(vaults[4], await ethRestakePrivErc20VaultFactory.implementation()) - await checkVault(vaults[5], await ethRestakeBlocklistErc20VaultFactory.implementation()) - }) -}) diff --git a/test/restake/EthRestakeVaultFactory.spec.ts b/test/restake/EthRestakeVaultFactory.spec.ts deleted file mode 100644 index fba6ccb4..00000000 --- a/test/restake/EthRestakeVaultFactory.spec.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthRestakeVaultFactory, SharedMevEscrow, VaultsRegistry } from '../../typechain-types' -import snapshotGasCost from '../shared/snapshotGasCost' -import { expect } from '../shared/expect' -import { - encodeEthRestakeVaultInitParams, - encodeEthRestakeErc20VaultInitParams, - ethRestakeVaultFixture, -} from '../shared/restakeFixtures' -import { SECURITY_DEPOSIT, ZERO_ADDRESS, ZERO_BYTES32 } from '../shared/constants' -import { extractMevEscrowAddress, extractVaultAddress, toHexString } from '../shared/utils' -import keccak256 from 'keccak256' - -describe('EthRestakeVaultFactory', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const name = 'SW ETH Vault' - const symbol = 'SW-ETH-1' - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - const ethRestakeVaultInitParams = { - capacity, - feePercent, - metadataIpfsHash, - } - const ethRestakeVaultInitParamsEncoded = - encodeEthRestakeVaultInitParams(ethRestakeVaultInitParams) - const ethRestakeErc20VaultInitParams = { - capacity, - feePercent, - name, - symbol, - metadataIpfsHash, - } - const ethRestakeErc20VaultInitParamsEncoded = encodeEthRestakeErc20VaultInitParams( - ethRestakeErc20VaultInitParams - ) - let admin: Wallet, other: Wallet - let ethRestakeVaultFactory: EthRestakeVaultFactory, - ethRestakePrivVaultFactory: EthRestakeVaultFactory, - ethRestakeErc20VaultFactory: EthRestakeVaultFactory, - ethRestakePrivErc20VaultFactory: EthRestakeVaultFactory, - ethRestakeBlocklistVaultFactory: EthRestakeVaultFactory, - ethRestakeBlocklistErc20VaultFactory: EthRestakeVaultFactory - let sharedMevEscrow: SharedMevEscrow - let vaultsRegistry: VaultsRegistry - - beforeEach(async () => { - ;[admin, other] = (await (ethers as any).getSigners()).slice(1, 3) - ;({ - ethRestakeVaultFactory, - ethRestakePrivVaultFactory, - ethRestakeErc20VaultFactory, - ethRestakePrivErc20VaultFactory, - ethRestakeBlocklistVaultFactory, - ethRestakeBlocklistErc20VaultFactory, - vaultsRegistry, - sharedMevEscrow, - } = await loadFixture(ethRestakeVaultFixture)) - }) - - it('not dao fails to create vault', async () => { - await expect( - ethRestakeVaultFactory - .connect(other) - .createVault(admin.address, ethRestakeVaultInitParamsEncoded, false, { - value: SECURITY_DEPOSIT, - }) - ).to.be.revertedWithCustomError(ethRestakeVaultFactory, 'OwnableUnauthorizedAccount') - }) - - it('fails to create with zero admin address', async () => { - await expect( - ethRestakeVaultFactory.createVault(ZERO_ADDRESS, ethRestakeVaultInitParamsEncoded, false, { - value: SECURITY_DEPOSIT, - }) - ).to.be.revertedWithCustomError(ethRestakeVaultFactory, 'ZeroAddress') - }) - - describe('EthRestakeVault', () => { - it('public vault deployment with own escrow gas', async () => { - const receipt = await ethRestakeVaultFactory.createVault( - admin.address, - ethRestakeVaultInitParamsEncoded, - true, - { value: SECURITY_DEPOSIT } - ) - await snapshotGasCost(receipt) - }) - - it('public vault deployment with shared escrow gas', async () => { - const receipt = await ethRestakeVaultFactory.createVault( - admin.address, - ethRestakeVaultInitParamsEncoded, - false, - { value: SECURITY_DEPOSIT } - ) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with own escrow gas', async () => { - const receipt = await ethRestakePrivVaultFactory.createVault( - admin.address, - ethRestakeVaultInitParamsEncoded, - true, - { value: SECURITY_DEPOSIT } - ) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with shared escrow gas', async () => { - const receipt = await ethRestakePrivVaultFactory.createVault( - admin.address, - ethRestakeVaultInitParamsEncoded, - false, - { value: SECURITY_DEPOSIT } - ) - await snapshotGasCost(receipt) - }) - }) - - describe('EthErc20Vault', () => { - it('public vault deployment with own escrow gas', async () => { - const receipt = await ethRestakeErc20VaultFactory.createVault( - admin.address, - ethRestakeErc20VaultInitParamsEncoded, - true, - { - value: SECURITY_DEPOSIT, - } - ) - await snapshotGasCost(receipt) - }) - - it('public vault deployment with shared escrow gas', async () => { - const receipt = await ethRestakeErc20VaultFactory.createVault( - admin.address, - ethRestakeErc20VaultInitParamsEncoded, - false, - { - value: SECURITY_DEPOSIT, - } - ) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with own escrow gas', async () => { - const receipt = await ethRestakePrivErc20VaultFactory.createVault( - admin.address, - ethRestakeErc20VaultInitParamsEncoded, - true, - { - value: SECURITY_DEPOSIT, - } - ) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with shared escrow gas', async () => { - const receipt = await ethRestakePrivErc20VaultFactory.createVault( - admin.address, - ethRestakeErc20VaultInitParamsEncoded, - false, - { - value: SECURITY_DEPOSIT, - } - ) - await snapshotGasCost(receipt) - }) - }) - - it('creates vaults correctly', async () => { - for (const config of [ - { - factory: ethRestakeVaultFactory, - vaultClass: 'EthRestakeVault', - isErc20: false, - isPrivate: false, - isBlocklist: false, - }, - { - factory: ethRestakePrivVaultFactory, - vaultClass: 'EthRestakePrivVault', - isErc20: false, - isPrivate: true, - isBlocklist: false, - }, - { - factory: ethRestakeBlocklistVaultFactory, - vaultClass: 'EthRestakeBlocklistVault', - isErc20: false, - isPrivate: false, - isBlocklist: true, - }, - { - factory: ethRestakeErc20VaultFactory, - vaultClass: 'EthRestakeErc20Vault', - isErc20: true, - isPrivate: false, - isBlocklist: false, - }, - { - factory: ethRestakePrivErc20VaultFactory, - vaultClass: 'EthRestakePrivErc20Vault', - isErc20: true, - isPrivate: true, - isBlocklist: false, - }, - { - factory: ethRestakeBlocklistErc20VaultFactory, - vaultClass: 'EthRestakeBlocklistErc20Vault', - isErc20: true, - isPrivate: false, - isBlocklist: true, - }, - ]) { - for (const isOwnEscrow of [false, true]) { - const { factory, isErc20, vaultClass, isPrivate, isBlocklist } = config - const initParamsEncoded = isErc20 - ? encodeEthRestakeErc20VaultInitParams(ethRestakeErc20VaultInitParams) - : encodeEthRestakeVaultInitParams(ethRestakeVaultInitParams) - - // fails without security deposit - await expect( - factory.connect(admin).createVault(admin.address, initParamsEncoded, isOwnEscrow) - ).to.reverted - - const tx = await factory.createVault(admin.address, initParamsEncoded, isOwnEscrow, { - value: SECURITY_DEPOSIT, - }) - const vaultAddress = await extractVaultAddress(tx) - const mevEscrow = isOwnEscrow - ? await extractMevEscrowAddress(tx) - : await sharedMevEscrow.getAddress() - - await expect(tx) - .to.emit(factory, 'VaultCreated') - .withArgs( - admin.address, - vaultAddress, - isOwnEscrow ? mevEscrow : ZERO_ADDRESS, - initParamsEncoded - ) - - const vaultFactory = await ethers.getContractFactory(vaultClass) - const vault = await vaultFactory.attach(vaultAddress) - - await expect(tx) - .to.emit(vaultsRegistry, 'VaultAdded') - .withArgs(await factory.getAddress(), vaultAddress) - await expect(vault.connect(admin).initialize(ZERO_BYTES32)).to.revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - - // Factory - expect(await factory.vaultAdmin()).to.be.eq(ZERO_ADDRESS) - expect(await factory.ownMevEscrow()).to.be.eq(ZERO_ADDRESS) - - expect(await vaultsRegistry.vaults(vaultAddress)).to.be.eq(true) - expect(await vault.capacity()).to.be.eq(capacity) - - // VaultToken - if (isErc20) { - expect(await vault.name()).to.be.eq(name) - expect(await vault.symbol()).to.be.eq(symbol) - } - - // VaultAdmin - expect(await vault.admin()).to.be.eq(admin.address) - await expect(tx) - .to.emit(vault, 'MetadataUpdated') - .withArgs(await factory.getAddress(), metadataIpfsHash) - - // VaultVersion - expect(await vault.version()).to.be.eq(3) - expect(await vault.vaultId()).to.be.eq(toHexString(keccak256(vaultClass))) - expect(await factory.implementation()).to.be.eq(await vault.implementation()) - - // VaultFee - expect(await vault.feeRecipient()).to.be.eq(admin.address) - expect(await vault.feePercent()).to.be.eq(feePercent) - await expect(tx) - .to.emit(vault, 'FeeRecipientUpdated') - .withArgs(await factory.getAddress(), admin.address) - - // VaultMev - expect(await vault.mevEscrow()).to.be.eq(mevEscrow) - - // VaultWhitelist - if (isPrivate) { - await expect(await vault.whitelister()).to.be.eq(admin.address) - await expect(tx) - .to.emit(vault, 'WhitelisterUpdated') - .withArgs(await factory.getAddress(), admin.address) - } - - // VaultBlocklist - if (isBlocklist) { - await expect(await vault.blocklistManager()).to.be.eq(admin.address) - await expect(tx) - .to.emit(vault, 'BlocklistManagerUpdated') - .withArgs(await factory.getAddress(), admin.address) - } - } - } - }) -}) diff --git a/test/restake/__snapshots__/EigenPodOwner.spec.ts.snap b/test/restake/__snapshots__/EigenPodOwner.spec.ts.snap deleted file mode 100644 index 609bd939..00000000 --- a/test/restake/__snapshots__/EigenPodOwner.spec.ts.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EigenPodOwner delegation operator manager can undelegate 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 146611, -} -`; - -exports[`EigenPodOwner delegation operators manager can delegate 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 118993, -} -`; - -exports[`EigenPodOwner upgrade succeeds to upgrade 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 37475, -} -`; - -exports[`EigenPodOwner withdrawals can claim delayed withdrawals 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 98777, -} -`; - -exports[`EigenPodOwner withdrawals withdrawals manager can complete withdrawal 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 115980, -} -`; - -exports[`EigenPodOwner withdrawals withdrawals manager can queue withdrawal 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 136023, -} -`; diff --git a/test/restake/__snapshots__/EthRestakeBlocklistErc20Vault.spec.ts.snap b/test/restake/__snapshots__/EthRestakeBlocklistErc20Vault.spec.ts.snap deleted file mode 100644 index 1cf5c1e6..00000000 --- a/test/restake/__snapshots__/EthRestakeBlocklistErc20Vault.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakeBlocklistErc20Vault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 73103, -} -`; - -exports[`EthRestakeBlocklistErc20Vault deposit deposit through receive fallback can be called by not blocked sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 80515, -} -`; - -exports[`EthRestakeBlocklistErc20Vault transfer can transfer 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 56459, -} -`; diff --git a/test/restake/__snapshots__/EthRestakeBlocklistVault.spec.ts.snap b/test/restake/__snapshots__/EthRestakeBlocklistVault.spec.ts.snap deleted file mode 100644 index 033a26ec..00000000 --- a/test/restake/__snapshots__/EthRestakeBlocklistVault.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakeBlocklistVault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 70990, -} -`; - -exports[`EthRestakeBlocklistVault deposit deposit through receive fallback can be called by not blocked sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 76519, -} -`; diff --git a/test/restake/__snapshots__/EthRestakeErc20Vault.spec.ts.snap b/test/restake/__snapshots__/EthRestakeErc20Vault.spec.ts.snap deleted file mode 100644 index 823601b3..00000000 --- a/test/restake/__snapshots__/EthRestakeErc20Vault.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakeErc20Vault deposit emits transfer event 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 68558, -} -`; - -exports[`EthRestakeErc20Vault enter exit queue emits transfer event 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 88814, -} -`; diff --git a/test/restake/__snapshots__/EthRestakePrivErc20Vault.spec.ts.snap b/test/restake/__snapshots__/EthRestakePrivErc20Vault.spec.ts.snap deleted file mode 100644 index 9e41573b..00000000 --- a/test/restake/__snapshots__/EthRestakePrivErc20Vault.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakePrivErc20Vault deposit can be called by whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 71091, -} -`; - -exports[`EthRestakePrivErc20Vault deposit deposit through receive fallback can be called by whitelisted sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 80518, -} -`; - -exports[`EthRestakePrivErc20Vault transfer can transfer to whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 56487, -} -`; diff --git a/test/restake/__snapshots__/EthRestakePrivVault.spec.ts.snap b/test/restake/__snapshots__/EthRestakePrivVault.spec.ts.snap deleted file mode 100644 index 99fa8a93..00000000 --- a/test/restake/__snapshots__/EthRestakePrivVault.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakePrivVault deposit can be called by whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 70978, -} -`; - -exports[`EthRestakePrivVault deposit deposit through receive fallback can be called by whitelisted sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 78702, -} -`; diff --git a/test/restake/__snapshots__/EthRestakeVault.spec.ts.snap b/test/restake/__snapshots__/EthRestakeVault.spec.ts.snap deleted file mode 100644 index c8253bf8..00000000 --- a/test/restake/__snapshots__/EthRestakeVault.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakeVault create eigen pod succeeds 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 651839, -} -`; - -exports[`EthRestakeVault multiple validators succeeds 1`] = ` -Object { - "calldataByteLength": 2820, - "gasUsed": 556020, -} -`; - -exports[`EthRestakeVault restake operators manager succeeds 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 52674, -} -`; - -exports[`EthRestakeVault restake withdrawals manager succeeds 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 51882, -} -`; - -exports[`EthRestakeVault single validator succeeds 1`] = ` -Object { - "calldataByteLength": 1060, - "gasUsed": 268348, -} -`; diff --git a/test/restake/__snapshots__/EthRestakeVault.upgrade.spec.ts.snap b/test/restake/__snapshots__/EthRestakeVault.upgrade.spec.ts.snap deleted file mode 100644 index 280cceea..00000000 --- a/test/restake/__snapshots__/EthRestakeVault.upgrade.spec.ts.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakeVault - upgrade does not modify the state variables 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 63055, -} -`; - -exports[`EthRestakeVault - upgrade does not modify the state variables 2`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 63269, -} -`; - -exports[`EthRestakeVault - upgrade does not modify the state variables 3`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 63159, -} -`; - -exports[`EthRestakeVault - upgrade does not modify the state variables 4`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 63736, -} -`; - -exports[`EthRestakeVault - upgrade does not modify the state variables 5`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 63950, -} -`; - -exports[`EthRestakeVault - upgrade does not modify the state variables 6`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 63840, -} -`; diff --git a/test/restake/__snapshots__/EthRestakeVaultFactory.spec.ts.snap b/test/restake/__snapshots__/EthRestakeVaultFactory.spec.ts.snap deleted file mode 100644 index cbc31aff..00000000 --- a/test/restake/__snapshots__/EthRestakeVaultFactory.spec.ts.snap +++ /dev/null @@ -1,57 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthRestakeVaultFactory EthErc20Vault private vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 548, - "gasUsed": 602399, -} -`; - -exports[`EthRestakeVaultFactory EthErc20Vault private vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 548, - "gasUsed": 453565, -} -`; - -exports[`EthRestakeVaultFactory EthErc20Vault public vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 548, - "gasUsed": 578479, -} -`; - -exports[`EthRestakeVaultFactory EthErc20Vault public vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 548, - "gasUsed": 429645, -} -`; - -exports[`EthRestakeVaultFactory EthRestakeVault private vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 356, - "gasUsed": 528289, -} -`; - -exports[`EthRestakeVaultFactory EthRestakeVault private vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 356, - "gasUsed": 379455, -} -`; - -exports[`EthRestakeVaultFactory EthRestakeVault public vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 356, - "gasUsed": 504369, -} -`; - -exports[`EthRestakeVaultFactory EthRestakeVault public vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 356, - "gasUsed": 355535, -} -`; diff --git a/test/shared/artifacts/EigenDelayedWithdrawalRouter.json b/test/shared/artifacts/EigenDelayedWithdrawalRouter.json deleted file mode 100644 index 4ee9394e..00000000 --- a/test/shared/artifacts/EigenDelayedWithdrawalRouter.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "abi": [{"inputs":[{"internalType":"contract IEigenPodManager","name":"_eigenPodManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"podOwner","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"DelayedWithdrawalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountClaimed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delayedWithdrawalsCompleted","type":"uint256"}],"name":"DelayedWithdrawalsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IPauserRegistry","name":"pauserRegistry","type":"address"},{"indexed":false,"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"PauserRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"WithdrawalDelayBlocksSet","type":"event"},{"inputs":[],"name":"MAX_WITHDRAWAL_DELAY_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"canClaimDelayedWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxNumberOfDelayedWithdrawalsToClaim","type":"uint256"}],"name":"claimDelayedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"maxNumberOfDelayedWithdrawalsToClaim","type":"uint256"}],"name":"claimDelayedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"createDelayedWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eigenPodManager","outputs":[{"internalType":"contract IEigenPodManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getClaimableUserDelayedWithdrawals","outputs":[{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"blockCreated","type":"uint32"}],"internalType":"struct IDelayedWithdrawalRouter.DelayedWithdrawal[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserDelayedWithdrawals","outputs":[{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"blockCreated","type":"uint32"}],"internalType":"struct IDelayedWithdrawalRouter.DelayedWithdrawal[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initOwner","type":"address"},{"internalType":"contract IPauserRegistry","name":"_pauserRegistry","type":"address"},{"internalType":"uint256","name":"initPausedStatus","type":"uint256"},{"internalType":"uint256","name":"_withdrawalDelayBlocks","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauserRegistry","outputs":[{"internalType":"contract IPauserRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"setPauserRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"setWithdrawalDelayBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"userDelayedWithdrawalByIndex","outputs":[{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"blockCreated","type":"uint32"}],"internalType":"struct IDelayedWithdrawalRouter.DelayedWithdrawal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userWithdrawals","outputs":[{"components":[{"internalType":"uint256","name":"delayedWithdrawalsCompleted","type":"uint256"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"blockCreated","type":"uint32"}],"internalType":"struct IDelayedWithdrawalRouter.DelayedWithdrawal[]","name":"delayedWithdrawals","type":"tuple[]"}],"internalType":"struct IDelayedWithdrawalRouter.UserDelayedWithdrawals","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userWithdrawalsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalDelayBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] -} \ No newline at end of file diff --git a/test/shared/artifacts/EigenDelegationManager.json b/test/shared/artifacts/EigenDelegationManager.json deleted file mode 100644 index b565fe60..00000000 --- a/test/shared/artifacts/EigenDelegationManager.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "abi": [{"inputs":[{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"},{"internalType":"contract ISlasher","name":"_slasher","type":"address"},{"internalType":"contract IEigenPodManager","name":"_eigenPodManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"MinWithdrawalDelayBlocksSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"components":[{"internalType":"address","name":"earningsReceiver","type":"address"},{"internalType":"address","name":"delegationApprover","type":"address"},{"internalType":"uint32","name":"stakerOptOutWindowBlocks","type":"uint32"}],"indexed":false,"internalType":"struct IDelegationManager.OperatorDetails","name":"newOperatorDetails","type":"tuple"}],"name":"OperatorDetailsModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"OperatorMetadataURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"components":[{"internalType":"address","name":"earningsReceiver","type":"address"},{"internalType":"address","name":"delegationApprover","type":"address"},{"internalType":"uint32","name":"stakerOptOutWindowBlocks","type":"uint32"}],"indexed":false,"internalType":"struct IDelegationManager.OperatorDetails","name":"operatorDetails","type":"tuple"}],"name":"OperatorRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"OperatorSharesDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"OperatorSharesIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IPauserRegistry","name":"pauserRegistry","type":"address"},{"indexed":false,"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"PauserRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"StakerDelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"StakerForceUndelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"StakerUndelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"StrategyWithdrawalDelayBlocksSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"WithdrawalCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"oldWithdrawalRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newWithdrawalRoot","type":"bytes32"}],"name":"WithdrawalMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"indexed":false,"internalType":"struct IDelegationManager.Withdrawal","name":"withdrawal","type":"tuple"}],"name":"WithdrawalQueued","type":"event"},{"inputs":[],"name":"DELEGATION_APPROVAL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STAKER_OPT_OUT_WINDOW_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_WITHDRAWAL_DELAY_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKER_DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beaconChainETHStrategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"calculateCurrentStakerDelegationDigestHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"_delegationApprover","type":"address"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"calculateDelegationApprovalDigestHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"_stakerNonce","type":"uint256"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"calculateStakerDelegationDigestHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"internalType":"struct IDelegationManager.Withdrawal","name":"withdrawal","type":"tuple"}],"name":"calculateWithdrawalRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"internalType":"struct IDelegationManager.Withdrawal","name":"withdrawal","type":"tuple"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"middlewareTimesIndex","type":"uint256"},{"internalType":"bool","name":"receiveAsTokens","type":"bool"}],"name":"completeQueuedWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"internalType":"struct IDelegationManager.Withdrawal[]","name":"withdrawals","type":"tuple[]"},{"internalType":"contract IERC20[][]","name":"tokens","type":"address[][]"},{"internalType":"uint256[]","name":"middlewareTimesIndexes","type":"uint256[]"},{"internalType":"bool[]","name":"receiveAsTokens","type":"bool[]"}],"name":"completeQueuedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cumulativeWithdrawalsQueued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"decreaseDelegatedShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct ISignatureUtils.SignatureWithExpiry","name":"approverSignatureAndExpiry","type":"tuple"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"}],"name":"delegateTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct ISignatureUtils.SignatureWithExpiry","name":"stakerSignatureAndExpiry","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct ISignatureUtils.SignatureWithExpiry","name":"approverSignatureAndExpiry","type":"tuple"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"}],"name":"delegateToBySignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegatedTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"delegationApprover","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"delegationApproverSaltIsSpent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"earningsReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenPodManager","outputs":[{"internalType":"contract IEigenPodManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getDelegatableShares","outputs":[{"internalType":"contract IStrategy[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"}],"name":"getOperatorShares","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"}],"name":"getWithdrawalDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"increaseDelegatedShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"contract IPauserRegistry","name":"_pauserRegistry","type":"address"},{"internalType":"uint256","name":"initialPausedStatus","type":"uint256"},{"internalType":"uint256","name":"_minWithdrawalDelayBlocks","type":"uint256"},{"internalType":"contract IStrategy[]","name":"_strategies","type":"address[]"},{"internalType":"uint256[]","name":"_withdrawalDelayBlocks","type":"uint256[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"isDelegated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"internalType":"address","name":"staker","type":"address"},{"components":[{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint96","name":"nonce","type":"uint96"}],"internalType":"struct IStrategyManager.DeprecatedStruct_WithdrawerAndNonce","name":"withdrawerAndNonce","type":"tuple"},{"internalType":"uint32","name":"withdrawalStartBlock","type":"uint32"},{"internalType":"address","name":"delegatedAddress","type":"address"}],"internalType":"struct IStrategyManager.DeprecatedStruct_QueuedWithdrawal[]","name":"withdrawalsToMigrate","type":"tuple[]"}],"name":"migrateQueuedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minWithdrawalDelayBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"earningsReceiver","type":"address"},{"internalType":"address","name":"delegationApprover","type":"address"},{"internalType":"uint32","name":"stakerOptOutWindowBlocks","type":"uint32"}],"internalType":"struct IDelegationManager.OperatorDetails","name":"newOperatorDetails","type":"tuple"}],"name":"modifyOperatorDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"operatorDetails","outputs":[{"components":[{"internalType":"address","name":"earningsReceiver","type":"address"},{"internalType":"address","name":"delegationApprover","type":"address"},{"internalType":"uint32","name":"stakerOptOutWindowBlocks","type":"uint32"}],"internalType":"struct IDelegationManager.OperatorDetails","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract IStrategy","name":"","type":"address"}],"name":"operatorShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauserRegistry","outputs":[{"internalType":"contract IPauserRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"pendingWithdrawals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"internalType":"address","name":"withdrawer","type":"address"}],"internalType":"struct IDelegationManager.QueuedWithdrawalParams[]","name":"queuedWithdrawalParams","type":"tuple[]"}],"name":"queueWithdrawals","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"earningsReceiver","type":"address"},{"internalType":"address","name":"delegationApprover","type":"address"},{"internalType":"uint32","name":"stakerOptOutWindowBlocks","type":"uint32"}],"internalType":"struct IDelegationManager.OperatorDetails","name":"registeringOperatorDetails","type":"tuple"},{"internalType":"string","name":"metadataURI","type":"string"}],"name":"registerAsOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinWithdrawalDelayBlocks","type":"uint256"}],"name":"setMinWithdrawalDelayBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"setPauserRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"withdrawalDelayBlocks","type":"uint256[]"}],"name":"setStrategyWithdrawalDelayBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slasher","outputs":[{"internalType":"contract ISlasher","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakerNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"stakerOptOutWindowBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"name":"strategyWithdrawalDelayBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"undelegate","outputs":[{"internalType":"bytes32[]","name":"withdrawalRoots","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"metadataURI","type":"string"}],"name":"updateOperatorMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"}] -} \ No newline at end of file diff --git a/test/shared/artifacts/EigenPodManager.json b/test/shared/artifacts/EigenPodManager.json deleted file mode 100644 index 4f5e47ff..00000000 --- a/test/shared/artifacts/EigenPodManager.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "abi": [{"inputs":[{"internalType":"contract IETHPOSDeposit","name":"_ethPOS","type":"address"},{"internalType":"contract IBeacon","name":"_eigenPodBeacon","type":"address"},{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"},{"internalType":"contract ISlasher","name":"_slasher","type":"address"},{"internalType":"contract IDelegationManager","name":"_delegationManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"podOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BeaconChainETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"podOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"nonce","type":"uint96"},{"indexed":false,"internalType":"address","name":"delegatedAddress","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"BeaconChainETHWithdrawalCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOracleAddress","type":"address"}],"name":"BeaconOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newValue","type":"uint64"}],"name":"DenebForkTimestampUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IPauserRegistry","name":"pauserRegistry","type":"address"},{"indexed":false,"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"PauserRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"eigenPod","type":"address"},{"indexed":true,"internalType":"address","name":"podOwner","type":"address"}],"name":"PodDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"podOwner","type":"address"},{"indexed":false,"internalType":"int256","name":"sharesDelta","type":"int256"}],"name":"PodSharesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"addShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"beaconChainETHStrategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beaconChainOracle","outputs":[{"internalType":"contract IBeaconChainOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"createPod","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegationManager","outputs":[{"internalType":"contract IDelegationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"denebForkTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenPodBeacon","outputs":[{"internalType":"contract IBeacon","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethPOS","outputs":[{"internalType":"contract IETHPOSDeposit","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"timestamp","type":"uint64"}],"name":"getBlockRootAtTimestamp","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"}],"name":"getPod","outputs":[{"internalType":"contract IEigenPod","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"}],"name":"hasPod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBeaconChainOracle","name":"_beaconChainOracle","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"contract IPauserRegistry","name":"_pauserRegistry","type":"address"},{"internalType":"uint256","name":"_initPausedStatus","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"numPods","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ownerToPod","outputs":[{"internalType":"contract IEigenPod","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauserRegistry","outputs":[{"internalType":"contract IPauserRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"podOwnerShares","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"},{"internalType":"int256","name":"sharesDelta","type":"int256"}],"name":"recordBeaconChainETHBalanceUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"removeShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newDenebForkTimestamp","type":"uint64"}],"name":"setDenebForkTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"setPauserRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slasher","outputs":[{"internalType":"contract ISlasher","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"}],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBeaconChainOracle","name":"newBeaconChainOracle","type":"address"}],"name":"updateBeaconChainOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"podOwner","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"withdrawSharesAsTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}] -} \ No newline at end of file diff --git a/test/shared/artifacts/EthRestakeBlocklistErc20Vault.json b/test/shared/artifacts/EthRestakeBlocklistErc20Vault.json deleted file mode 100644 index a90e85a9..00000000 --- a/test/shared/artifacts/EthRestakeBlocklistErc20Vault.json +++ /dev/null @@ -1,1779 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthRestakeBlocklistErc20Vault", - "sourceName": "contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "eigenPodOwnerImplementation", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101c0346200016d57601f6200558038819003918201601f19168301916001600160401b03831184841017620001715780849260e0946040528339810103126200016d576200004e8162000185565b906200005d6020820162000185565b906200006c6040820162000185565b6200007a6060830162000185565b90620000896080840162000185565b9360c06200009a60a0860162000185565b9401519560805260a05260c0523060e052620000b56200019a565b610100934685526101209384526101404681526101609182526101809283526101a0938452620000e46200019a565b6040519461534696876200023a883960805187818161135d0152818161161601528181612f1d015261386d015260a05187611030015260c0518781816145c10152614717015260e0518781816111dc015261351f0152518661253901525185612bc5015251846138eb015251836117ef0152518281816125140152612f6a015251816108310152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200016d57565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1662000227576001600160401b036002600160401b031982821601620001e857505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101562000026575b36156200001a575f80fd5b6200002462002ca3565b005b5f3560e01c806301e1d114146200041a57806306fdde03146200041457806307a2d13a146200040e578063095ea7b31462000408578063096ae80d14620004025780630b10b20114620003fc57806314c4184b14620003f657806318160ddd14620003c057806318f7295014620003f05780631a7ff55314620003ea57806323b872dd14620003e45780632cdf740114620003de578063313ce56714620003d85780633229fa9514620003d257806333194c0a14620003cc5780633644e51514620003c65780633a98ef3914620003c0578063439fab9114620003ba5780634690484014620003b45780634f1ef28614620003ae57806352d1902d14620003a857806353156f2814620003a257806354fd4d50146200039c5780635c60da1b14620003965780635cfc1a51146200039057806360d60e6e146200038a57806370a0823114620002ee57806372b410a81462000384578063754c3888146200037e57806376b58b9014620003785780637b6341c614620003725780637ecebe00146200036c5780637fd6f15c146200036657806383d430d514620003605780638697d2c2146200035a5780638ceab9aa146200035457806395d89b41146200034e578063a045dd0c1462000348578063a49a1e7d1462000342578063a9059cbb146200033c578063ac9650d81462000336578063ad3cb1cc1462000330578063b1f0e7c7146200032a578063b45a1eb51462000324578063c5aecb22146200031e578063c6e6f5921462000318578063d0a64ddc1462000312578063d505accf146200030c578063d83ad00c1462000306578063dd62ed3e1462000300578063e74b981b14620002fa578063ee3bd5df14620002f4578063f04da65b14620002ee578063f132f5d314620002e8578063f45bf3d214620002e2578063f851a44014620002dc5763f9609f08036200000f57620023e6565b620023bc565b62002377565b6200230a565b620012f1565b620022e2565b620022ad565b62002265565b62002213565b62001feb565b62001faa565b62001f88565b62001f6a565b62001f30565b62001f07565b62001ebc565b62001e4d565b62001dab565b62001d52565b62001d10565b62001c5e565b62001a5b565b620017be565b620015b9565b62001593565b62001554565b62001490565b62001438565b620013c6565b62001330565b620012cf565b620012b1565b6200127a565b6200125d565b62001235565b620011c8565b62000f00565b62000e4e565b62000ca1565b620009de565b62000c21565b62000be5565b62000bb5565b62000b98565b62000b7a565b62000ac9565b62000a90565b62000a15565b620009b3565b620007ca565b62000735565b6200068d565b62000651565b62000574565b6200042f565b5f9103126200042b57565b5f80fd5b346200042b575f3660031901126200042b57602060cf5460801c604051908152f35b90600182811c9216801562000481575b60208310146200046d57565b634e487b7160e01b5f52602260045260245ffd5b91607f169162000461565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111620004b457604052565b6200048c565b604081019081106001600160401b03821117620004b457604052565b608081019081106001600160401b03821117620004b457604052565b90601f801991011681019081106001600160401b03821117620004b457604052565b5f5b838110620005265750505f910152565b818101518382015260200162000516565b90602091620005528151809281855285808601910162000514565b601f01601f1916010190565b9060206200057192818152019062000537565b90565b346200042b575f3660031901126200042b576040515f8054620005978162000451565b80845290602090600190818116908115620006245750600114620005da575b620005d685620005c981870382620004f2565b604051918291826200055e565b0390f35b5f80805293505f80516020620052918339815191525b8385106200061057505050508101602001620005c982620005d6620005b6565b8054868601840152938201938101620005f0565b869550620005d696935060209250620005c994915060ff191682840152151560051b8201019293620005b6565b346200042b5760203660031901126200042b5760206200067360043562002403565b604051908152f35b6001600160a01b038116036200042b57565b346200042b5760403660031901126200042b57600435620006ae816200067b565b6001600160a01b038116906024359082156200072357620006eb8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b346200042b5760203660031901126200042b5760043562000756816200067b565b610206805490916001600160a01b039081169082168114620007b8577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e89281602093620007a262002dd0565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200042b575f3660031901126200042b57620007f6620007ea62002c81565b6001600160a01b031690565b3303620009a1576040516102c8808201908282106001600160401b03831117620004b4578291620008679162004fc984396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff080156200097d576001600160a01b0390811690813b156200042b5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af180156200097d5762000983575b506040516351d5709b60e11b815291602083600481845afa9182156200097d577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f9362000940575b506200090f90831662003e79565b506200091b8162003ee7565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200090f9193506200096d9060203d60201162000975575b620009648183620004f2565b81019062002437565b929062000901565b503d62000958565b6200242c565b80620009936200099a92620004a0565b8062000420565b5f620008b7565b604051634ca8886760e01b8152600490fd5b346200042b575f3660031901126200042b5761026f546040516001600160a01b039091168152602090f35b346200042b575f3660031901126200042b5760206001600160801b0360cf5416604051908152f35b908160809103126200042b5790565b60603660031901126200042b5760043562000a30816200067b565b60243562000a3e816200067b565b604435906001600160401b0382116200042b5760209262000a7262000a6c6200067394369060040162000a06565b6200244f565b62000a7d3362003cc3565b62000a888162003cc3565b349062003dbd565b346200042b5760203660031901126200042b576004356001600160401b0381116200042b5762000a6c6200002491369060040162000a06565b346200042b5760603660031901126200042b5760043562000aea816200067b565b60243562000af8816200067b565b6001600160a01b0382165f818152600260209081526040808320338452909152902090926044359291546001810162000b45575b5062000b39935062003276565b60405160018152602090f35b83810390811162000b74575f94855260026020908152604080872033885290915285205562000b399362000b2c565b6200249f565b346200042b575f3660031901126200042b57602062000673620024c1565b346200042b575f3660031901126200042b57602060405160128152f35b346200042b575f3660031901126200042b57602062000bd3620024fa565b6040516001600160a01b039091168152f35b346200042b575f3660031901126200042b5760206040517f813d21398e0f42fde0737b550f7475616bb950f32cd3f6012ad8b7d81b6c415f8152f35b346200042b575f3660031901126200042b5760206200067362002536565b9181601f840112156200042b578235916001600160401b0383116200042b57602083818601950101116200042b57565b60206003198201126200042b57600435906001600160401b0382116200042b5762000c9d9160040162000c3f565b9091565b62000cac3662000c6f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16801562000e39575b62000e275768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156200097d575f9362000e03575b50604051636f4fa30f60e01b8152938285600481335afa9081156200097d5762000d759562000d6f945f9362000dda575b505062000d6791928101906200259c565b908362003433565b62003506565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016200093b565b62000d679350908162000dfb92903d106200097557620009648183620004f2565b915f62000d56565b62000e1f919350823d84116200097557620009648183620004f2565b915f62000d25565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000cde565b346200042b575f3660031901126200042b57609c546040516001600160a01b039091168152602090f35b6040519060a082018281106001600160401b03821117620004b457604052565b6040519062000ea782620004ba565b565b6001600160401b038111620004b457601f01601f191660200190565b92919262000ed38262000ea9565b9162000ee36040519384620004f2565b8294818452818301116200042b578281602093845f960137010152565b6040806003193601126200042b57600490813562000f1e816200067b565b6024356001600160401b0381116200042b57366023820112156200042b5762000f51903690602481870135910162000ec5565b9162000f5c62003515565b80519262000f978462000f8860209363439fab9160e01b85840152846024840152604483019062000537565b03601f198101865285620004f2565b62000fa162003515565b62000fab62002dd0565b6001600160a01b0383811680159291908790841562001197575b84156200110f575b8415620010a1575b5050821562001001575b505062000ff25762000024838362004254565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156200097d575f926200106d575b5050155f8062000fdf565b620010919250803d1062001099575b620010888183620004f2565b81019062002737565b5f8062001062565b503d6200107c565b855163054fd4d560e41b81529294508391839182905afa9081156200097d5760039160ff915f91620010db575b5016141591865f62000fd5565b620011009150843d861162001107575b620010f78183620004f2565b8101906200423c565b5f620010ce565b503d620010eb565b935050835163198ca60560e11b815282818981875afa9081156200097d5788917f813d21398e0f42fde0737b550f7475616bb950f32cd3f6012ad8b7d81b6c415f915f9162001163575b5014159362000fcd565b620011889150853d87116200118f575b6200117f8183620004f2565b81019062002ebe565b5f62001159565b503d62001173565b5f80516020620052b1833981519152549094508490620011c0906001600160a01b0316620007ea565b149362000fc5565b346200042b575f3660031901126200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620012235760206040515f80516020620052b18339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200042b576001600160a01b0362001253620024fa565b163303620009a157005b346200042b575f3660031901126200042b57602060405160028152f35b346200042b575f3660031901126200042b575f80516020620052b1833981519152546040516001600160a01b039091168152602090f35b346200042b575f3660031901126200042b576020620006736200264b565b346200042b5760203660031901126200042b5760206200067360043562002668565b346200042b5760203660031901126200042b5760043562001312816200067b565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156200097d576020915f91620013a4575b506040519015158152f35b620013bf9150823d84116200109957620010888183620004f2565b5f62001399565b346200042b5760203660031901126200042b57600435620013e7816200067b565b620013f162002dd0565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200042b5760803660031901126200042b57620005d66200147360043562001461816200067b565b6064359060443590602435906200274f565b604080519384526020840192909252908201529081906060820190565b346200042b575f3660031901126200042b5760405180610207805480845260208094019081925f527f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2905f5b868282106200153f578686620014f582880383620004f2565b60405192839281840190828552518091526040840192915f5b8281106200151e57505050500390f35b83516001600160a01b0316855286955093810193928101926001016200150e565b835485529093019260019283019201620014dc565b346200042b5760203660031901126200042b5760043562001575816200067b565b60018060a01b03165f526003602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57602061ffff609c5460a01c16604051908152f35b346200042b576003196040368201126200042b5760049081356001600160401b038082116200042b5760a08285019383360301126200042b576024359081116200042b576200160c903690850162000c3f565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200042b5760405163837d444160e01b8152905f908290818381620016628c828f016200287b565b03925af180156200097d57620017a7575b506200167e62003852565b6200168862002baf565b908116331415918262001770575b505090506200175f576044019160c4620016b1848462002905565b9050048015801562001744575b6200173457620016d8620016d1620024c1565b916200295f565b1162001725575060c4620016ed838362002905565b9050145f146200170e576200002491620017079162002905565b906200470c565b62000024916200171e9162002905565b90620045bf565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b5062001751848462002905565b905060c482021415620016be565b604051634ca8886760e01b81528390fd5b6200179a9250620017936200179e946200178a88620038e5565b92369162000ec5565b91620039cb565b1590565b805f8062001696565b8062000993620017b792620004a0565b5f62001673565b346200042b5760603660031901126200042b57600435602435620017e76044358284336200274f565b9192620018157f0000000000000000000000000000000000000000000000000000000000000000826200265a565b4210801562001a52575b801562001a49575b62001a37577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936200187c86620018766200186a60d0546001600160801b031690565b6001600160801b031690565b62003572565b156200199557620018bc620018a1620018958662003aa7565b60d05460801c62002979565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91620019039190620018f2608082620004f2565b5190205f5260d260205260405f2090565b555f93600183116200193f575b5050505062001920823362003adb565b604080519485526020850191909152830152339180606081015b0390a2005b6200198a929394506200195390886200265a565b60408051336020820190815291810193909352606083018290529094909190620018f29082608081015b03908101835282620004f2565b555f80808062001910565b6200199f62003852565b620019e0620019c4620019b28662003aa7565b60d5546001600160801b031662002979565b6001600160801b03166001600160801b031960d554161760d555565b62001a1a620019ff620019f38562003aa7565b60d55460801c62002979565b6001600160801b0360d5549181199060801b1691161760d555565b62001a3162001a2c8460d6546200265a565b60d655565b620018bc565b604051630e3d8e8d60e11b8152600490fd5b50821562001827565b5081156200181f565b346200042b576040806003193601126200042b576024359060043562001a81836200067b565b62001a8b62003852565b801562001c4d576001600160a01b03831690811562001c3c5762001aaf8162002403565b90811562001c2b5762001ac2826200435c565b62001acd8362003aa7565b60cf5460801c9062001adf9162002979565b62001aff906001600160801b0360cf549181199060801b1691161760cf55565b62001b0b823362004f03565b60d554958660801c828160d6549062001b24916200265a565b9862001b308762003aa7565b62001b44916001600160801b031662004804565b62001b65906001600160801b03166001600160801b031960d554161760d555565b62001b70916200265a565b62001b7b9062003aa7565b62001b9b906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529062001bce608082620004f2565b51902062001be4905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200042b575f3660031901126200042b576040515f6001805462001c838162000451565b808552916020916001811690811562000624575060011462001cb257620005d685620005c981870382620004f2565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851062001cfc57505050508101602001620005c982620005d6620005b6565b805486860184015293820193810162001cdc565b346200042b575f3660031901126200042b57610206546020906001600160a01b039081168062001d4b57508060375416905b60405191168152f35b9062001d42565b346200042b576200193a7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf62001d883662000c6f565b929062001d9462002dd0565b60405191829160208352339560208401916200285b565b346200042b5760403660031901126200042b5762001ddb60043562001dd0816200067b565b602435903362003276565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831062001e1c5750505050505090565b909192939495848062001e3c600193603f198682030187528a5162000537565b980193019301919493929062001e0b565b346200042b5760203660031901126200042b576001600160401b036004358181116200042b57366023820112156200042b5780600401359182116200042b573660248360051b830101116200042b57620005d691602462001eaf920162002aee565b6040519182918262001de6565b346200042b575f3660031901126200042b57620005d660405162001ee081620004ba565b60058152640352e302e360dc1b602082015260405191829160208352602083019062000537565b346200042b575f3660031901126200042b57602062000bd362002baf565b801515036200042b57565b346200042b5760403660031901126200042b576200002460043562001f55816200067b565b6024359062001f648262001f25565b62002be7565b346200042b575f3660031901126200042b57602062000bd362002c81565b346200042b5760203660031901126200042b5760206200067360043562003b7a565b346200042b5760203660031901126200042b576200002460043562001fcf816200067b565b62001fd962002dd0565b62003c17565b60ff8116036200042b57565b346200042b5760e03660031901126200042b576004356200200c816200067b565b6024356200201a816200067b565b604435906064359260843590620020318262001fdf565b6001600160a01b03838116959092908615620007235742811062002201576020915f916200197d6200212d89878a620020ee6200206d62002536565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039162002104601f1993848101835282620004f2565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa156200097d575f51928284168015908115620021f3575b50620021e157620021d28591620021bd7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b556040519384521691602090a3005b6040516323389ba560e21b8152600490fd5b905083831614155f62002175565b604051631ab7da6b60e01b8152600490fd5b346200042b575f3660031901126200042b5760206001600160801b0360d05416604051908152f35b60409060031901126200042b5760043562002256816200067b565b9060243562000571816200067b565b346200042b576020620022a46200227c366200223b565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346200042b5760203660031901126200042b5762000024600435620022d2816200067b565b620022dc62002dd0565b62003c5e565b346200042b575f3660031901126200042b5760206001600160801b0360d55416604051908152f35b346200042b5760203660031901126200042b576004356200232b816200067b565b610205805490916001600160a01b039081169082168114620007b8577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d9281602093620007a262002dd0565b346200042b5760203660031901126200042b5760043562002398816200067b565b60018060a01b03165f52610270602052602060ff60405f2054166040519015158152f35b346200042b575f3660031901126200042b576037546040516001600160a01b039091168152602090f35b602062000673620023f7366200223b565b9062000a7d3362003cc3565b60cf546001600160801b03811690816200241c57505090565b91620005719260801c9062002d4c565b6040513d5f823e3d90fd5b908160209103126200042b575162000571816200067b565b6200245e620024669162002eea565b9190620030a2565b6200246d57565b6200247762004896565b8062002481575b50565b5f906040519081525f80516020620052d183398151915260203092a3565b634e487b7160e01b5f52601160045260245ffd5b9190820391821162000b7457565b4760d0546001600160801b03620024da81831662002403565b9060d55416019060801c01908181115f14620024f4570390565b50505f90565b61016e546001600160a01b03168015620025115790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003620025645760045490565b62000571620032fe565b359061ffff821682036200042b57565b9080601f830112156200042b57816020620005719335910162000ec5565b906020828203126200042b5781356001600160401b03928382116200042b57019060a0828203126200042b57620025d262000e78565b9282358452620025e5602084016200256e565b602085015260408301358181116200042b5782620026059185016200257e565b604085015260608301358181116200042b5782620026259185016200257e565b606085015260808301359081116200042b576200264392016200257e565b608082015290565b60d454806200057157505f1990565b9190820180921162000b7457565b6001600160801b0360d054166200267e6200430a565b90810180911162000b74578110620026b857620026a860d654620026a16200358c565b906200265a565b1115620026b3575f90565b5f1990565b60d19060d1549182915f905b848210620026e057505050811015620026da5790565b505f1990565b909193808316906001818518811c830180931162000b74575f8790525f80516020620052f18339815191528301546001600160a01b03168410156200272b575050935b9190620026c4565b90959101925062002723565b908160209103126200042b5751620005718162001f25565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200278f81608081015b03601f198101835282620004f2565b5190205f5260d260205260405f205491821562002804576001600160801b0360d0541690620027bd6200430a565b91820180921162000b74578391831015620027ef5791620027de926200369b565b90915b82810390811162000b745792565b5090620027fc9162003601565b9091620027e1565b5050505f905f905f90565b9035601e19823603018112156200042b5701602081359101916001600160401b0382116200042b5781360383136200042b57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06200057192602081528235602082015260208301356040820152620028bc620028ab60408501856200280f565b84606085015260c08401916200285b565b90620028f5620028e9620028d460608701876200280f565b601f198587038101608087015295916200285b565b9460808101906200280f565b939092828603019101526200285b565b903590601e19813603018212156200042b57018035906001600160401b0382116200042b576020019181360383136200042b57565b634e487b7160e01b5f52601260045260245ffd5b811562002959570490565b6200293a565b906801bc16d674ec800000918083029283040362000b7457565b6001600160801b03918216908216039190821162000b7457565b6001600160401b038111620004b45760051b60200190565b90620029b78262002993565b620029c66040519182620004f2565b8281528092620029d9601f199162002993565b01905f5b828110620029ea57505050565b806060602080938501015201620029dd565b634e487b7160e01b5f52603260045260245ffd5b9082101562002a2a5762000c9d9160051b81019062002905565b620029fc565b908092918237015f815290565b3d1562002a6c573d9062002a518262000ea9565b9162002a616040519384620004f2565b82523d5f602084013e565b606090565b6020818303126200042b578051906001600160401b0382116200042b570181601f820112156200042b57805162002aa88162000ea9565b9262002ab86040519485620004f2565b818452602082840101116200042b5762000571916020808501910162000514565b805182101562002a2a5760209160051b010190565b91909162002afc83620029ab565b925f5b81811062002b0c57505050565b5f8062002b1b83858762002a10565b6040939162002b2f85518093819362002a30565b0390305af49062002b3f62002a3d565b911562002b6c57509060019162002b57828862002ad9565b5262002b64818762002ad9565b500162002aff565b9060448151106200042b5762002bab62002b956004928381015160248091830101910162002a71565b925162461bcd60e51b815292839283016200055e565b0390fd5b610109546001600160a01b0316806200057157507f000000000000000000000000000000000000000000000000000000000000000090565b61026f546001600160a01b03919082163303620009a1576001600160a01b0381165f90815261027060205260409020549215159260ff161515831462002c7c576001600160a01b0381165f9081526102706020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b610205546001600160a01b039081168062002c9e57506037541690565b905090565b335f5261020a60205260405f20541562002cb957565b62002cc43362003cc3565b6200247e343362003ce5565b90808202905f198184099082808310920391808303921462002d4157612710908282111562002d2f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f198482099383808610950394808603951462002dc1578483111562002d2f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906200057192506200294e565b6037546001600160a01b03163303620009a157565b908160609103126200042b5780519160406020830151920151620005718162001f25565b81835290916001600160fb1b0383116200042b5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200042b576040830152604081013562002e60816200067b565b6001600160a01b031660608381019190915281013536829003601e19018112156200042b5701602081359101906001600160401b0381116200042b578060051b360382136200042b5760a08360808062000571960152019162002e09565b908160209103126200042b575190565b9190915f838201938412911290801582169115161762000b7457565b6040516325f56f1160e01b81526001600160a01b0392916060908290819062002f17906004830162002e2e565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156200097d575f915f905f9562003055575b50841562002ffa578162002f66620024fa565b16917f000000000000000000000000000000000000000000000000000000000000000016821462002ff257509060205f92600460405180958193634641257d60e01b83525af19081156200097d5762002fc8925f9262002fcc575b5062002ece565b9190565b62002fea91925060203d6020116200118f576200117f8183620004f2565b905f62002fc1565b908162003000575b50509190565b803b156200042b57604051636ee3193160e11b815260048101929092525f908290602490829084905af180156200097d576200303e575b8062002ffa565b80620009936200304e92620004a0565b5f62003037565b9194505062003080915060603d60601162003089575b620030778183620004f2565b81019062002de5565b93905f62002f53565b503d6200306b565b600160ff1b811462000b74575f0390565b80156200247e57620030ba6200186a60cf5460801c90565b5f8212620031ba5781620030ce916200265a565b90620030f9620030de8362003aa7565b6001600160801b0360cf549181199060801b1691161760cf55565b62003110609c549161ffff8360a01c169062002cd0565b801562002c7c57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793620031516200186a60cf546001600160801b031690565b80620031a05750506200319b90925b6001600160a01b03169162003176848462004820565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6200319b92620031b39203908462002d4c565b9262003160565b90620031c69062003091565b620031dd6200186a60d5546001600160801b031690565b8062003209575b5080620031ef575050565b62003203620030de9162000ea793620024b3565b62003aa7565b906200326c7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916200325c620019c4620032506200324888886200265a565b878562002d4c565b80809403960362003aa7565b6040519081529081906020820190565b0390a15f620031e4565b90620032828262003cc3565b6200328d8162003cc3565b6001600160a01b039182169182158015620032f3575b6200072357825f5260d360205260405f209081549285840393841162000b74575f80516020620052d183398151915293602093551693845f5260d3825260405f20818154019055604051908152a3565b5080821615620032a3565b6040515f905f5490620033118262000451565b9283825260209384830193600190866001821691825f1462003411575050600114620033c9575b5050918162003352620033c39362002780950382620004f2565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020620052918339815191525b828410620033fb57505050820101816200335262003338565b80548685018601528794909301928101620033e2565b60ff1916875292151560051b8501909201925083915062003352905062003338565b91906200343f62003f55565b6080820151906200344f62003f55565b6001600160a01b03841680156200072357620034fc94620034eb93620034cf926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280620034bc3394602083019062000537565b0390a2602085015161ffff169062003f97565b620034db835162003fed565b620034e562004021565b62004055565b606060408201519101519062004087565b62000ea7620041d0565b62000ea79062001fd962003f55565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562003555575b50506200122357565b5f80516020620052b18339815191525416141590505f806200354c565b906200357d6200430a565b91820180921162000b74571090565b4760d0548060801c820391821162000b745781620035b46001600160801b0380931662002403565b9081620035e0575b50508115620024f4576200057191620035da9160d55416906200434e565b6200435c565b9192509081811115620035f857035b905f80620035bc565b50505f620035ef565b6200360b6200358c565b9160d65492830180931162000b7457808311156200365c57620036309203906200434e565b9060d5548060801c80155f14620036475750508190565b6001600160801b036200057192168462002d4c565b5050505f905f90565b90604051604081018181106001600160401b03821117620004b45760405291546001600160a01b038116835260a01c6020830152565b60d1545f94859493909180841080159062003849575b6200383c578362003805575f5b60d15f526001600160a01b0316620036e65f80516020620052f1833981519152860162003665565b8051909790620036ff906001600160a01b0316620007ea565b98620037266200371a6020809b01516001600160601b031690565b6001600160601b031690565b948381108015620037fa575b620037e85791600193979a956200375562003762939488035b838c03906200434e565b8092019887039162002d4c565b01970193808611801590620037dd575b620037d25760d15f528290620037985f80516020620052f1833981519152870162003665565b805190890151969992966001600160a01b039091169460019392620037629290916001600160601b0390911690620037559088036200374b565b945050509250509190565b508185101562003772565b60405163e8722f8f60e01b8152600490fd5b50808b111562003732565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316620036be565b505093505050505f905f90565b508415620036b1565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156200097d575f91620038c1575b50620038af57565b60405163e775715160e01b8152600490fd5b620038de915060203d6020116200109957620010888183620004f2565b5f620038a7565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200399b5761010a54905b6200393162003929604083018362002905565b369162000ec5565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526200397e81620004d6565b5190206040519161190160f01b8352600283015260228201522090565b620039a562004398565b9062003916565b60041115620039b757565b634e487b7160e01b5f52602160045260245ffd5b620039d7838362004468565b50620039e681959295620039ac565b15938462003a90575b508315620039fe575b50505090565b5f92935090829160405162003a3981620027806020820194630b135d3f60e11b998a8752602484015260406044840152606483019062000537565b51915afa9062003a4862002a3d565b8262003a81575b8262003a61575b50505f8080620039f8565b62003a789192506020808251830101910162002ebe565b145f8062003a56565b91506020825110159162003a4f565b6001600160a01b0383811691161493505f620039ef565b6001600160801b039081811162003abc571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541462003b68576002835581471062003b50575f918291829182916001600160a01b03165af162003b3162002a3d565b501562003b3e5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b0382168115801562003bad575b1562003b9e5750905090565b620005719260801c9162002d4c565b50801562003b92565b60cf546001600160801b038116908215801562003c0e575b1562003bd957505090565b60801c9062003bea82828562002d4c565b92821562002959570962003bfb5790565b600181018091111562000571576200249f565b50811562003bce565b61026f80546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b62003c6862003852565b6001600160a01b0316801562003cb157609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610270602052604090205460ff16620009a157565b919062003cf162003852565b6001600160a01b0383169081156200072357801562003dab578062003d1c6200186a60cf5460801c90565b019362003d286200264b565b851162003d9957620030de9462003d579162003d5162003d488562003bb6565b97889362003aa7565b62004820565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b9092919262003dcb62003852565b6001600160a01b0382169182156200072357811562003dab578162003df66200186a60cf5460801c90565b0162003e016200264b565b811162003d9957620030de9562003e5062003d94927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003d5162003e478862003bb6565b9a8b9362003aa7565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f526102088060205260405f2054155f14620024f4576102078054600160401b811015620004b4576001810180835581101562002a2a5783907f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2015554915f5260205260405f2055600190565b805f5261020a8060205260405f2054155f14620024f4576102098054600160401b811015620004b4576001810180835581101562002a2a5783907f99e87348be6dc95028197b5a6b69c6a7a15df569de2f3d37542e8f40b8bae486015554915f5260205260405f2055600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562003f8557565b604051631afcd79f60e31b8152600490fd5b62003fa162003f55565b61271061ffff83161162003fdb5762003fba9062003c5e565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b62003ff762003f55565b80156200400f57600181016200400a5750565b60d455565b6040516331278a8760e01b8152600490fd5b6200402b62003f55565b6801bc16d674ec8000006200403f6200264b565b106200400f576200404f62004398565b61010a55565b6200405f62003f55565b6001600160a01b031680620040715750565b61016e80546001600160a01b0319169091179055565b6200409162003f55565b601e8151118015620041c4575b620041b257620040ad62003f55565b8051906001600160401b038211620004b457620040d682620040d05f5462000451565b620049dd565b602090816001601f851114620041375750918062004110926200411895945f926200412b575b50508160011b915f199060031b1c19161790565b5f5562004ab2565b62000ea762004126620032fe565b600455565b015190505f80620040fc565b5f80529190601f1984165f8051602062005291833981519152935f905b82821062004199575050916001939185620041189796941062004180575b505050811b015f5562004ab2565b01515f1960f88460031b161c191690555f808062004172565b8060018697829497870151815501960194019062004154565b604051632d3f993760e21b8152600490fd5b50600a8251116200409e565b620041da62003f55565b620041e462003f55565b620041ee62003f55565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca0034106200422a576200247e343062003ce5565b60405163ea2559bb60e01b8152600490fd5b908160209103126200042b5751620005718162001fdf565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481620042e4575b50620042a657604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020620052b18339815191528403620042cb5762000ea792935062004b9d565b604051632a87526960e21b815260048101859052602490fd5b6200430291955060203d6020116200118f576200117f8183620004f2565b935f6200427f565b60d154806200431857505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316620007ea565b908082101562002c9e575090565b60d554908160801c811580156200438f575b156200437a5750905090565b6001600160801b036200057193169162002d4c565b5080156200436e565b6e5661756c7456616c696461746f727360881b6020604051620043bb81620004ba565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117620004b45760405251902090565b81519190604183036200449b57620044949250602082015190606060408401519301515f1a9062004c45565b9192909190565b50505f9160029190565b906030116200042b5790603090565b909291928360b0116200042b5783116200042b5760b0019160af190190565b906090116200042b5760300190606090565b9060c4116200042b5760900190603490565b909392938483116200042b5784116200042b578101920390565b35906020811062004520575090565b5f199060200360031b1b1690565b959493620045606200456f93620045516060969460808b5260808b019062002843565b9089820360208b015262000537565b9187830360408901526200285b565b930152565b969594906200456f936200455162004560926060979560808c5260808c01916200285b565b9060206200057192818152019062002843565b916020620005719381815201916200285b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062004608575050505050505050565b8262004619910180928787620044f7565b90620046268282620044a5565b916200463f62004638858084620044b4565b9062004cdd565b90620046646200465d620046548784620044d3565b979093620044e5565b9062004511565b948c3b156200042b578c5f926801bc16d674ec800000604095620046a087519a8b96879586946304512a2360e31b86528d8d6004880162004574565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194620046e592620046f5575b505192839283620045ac565b0390a160018193019290620045f6565b80620009936200470592620004a0565b5f620046d9565b816030116200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916200475162004638828085620044b4565b6200475d8284620044d3565b94909260b0116200042b57803b156200042b57620047a6946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b600487016200452e565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926200319b92620047ed575b506040519182918262004599565b8062000993620047fd92620004a0565b5f620047df565b9190916001600160801b038080941691160191821162000b7457565b5f80516020620052d183398151915260205f926200483e8562003aa7565b60cf5490620048586001600160801b039182841662004804565b6fffffffffffffffffffffffffffffffff1990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b038216918215620049d75760801c620048d1620048bf8247620024b3565b620048ca8562002403565b906200434e565b908115620049d057620048e48262003b7a565b938415620049c857826200493d620018a16200320362000ea796620030de96620049376200491b620032038d620049bc9a620024b3565b6001600160801b03166001600160801b031960d054161760d055565b6200265a565b62004949818762004dff565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162003203620049a06200498e8862003aa7565b60cf546001600160801b031662002979565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c62002979565b505f93505050565b505f925050565b505f9150565b601f8111620049ea575050565b5f80525f8051602062005291833981519152906020601f840160051c8301931062004a31575b601f0160051c01905b81811062004a25575050565b5f815560010162004a19565b909150819062004a10565b90601f821162004a4a575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931062004aa7575b601f0160051c01905b81811062004a9c57505050565b5f8155820162004a8f565b909150819062004a86565b9081516001600160401b038111620004b45760019062004ade8162004ad8845462000451565b62004a3c565b602080601f831160011462004b165750819062004b129394955f926200412b5750508160011b915f199060031b1c19161790565b9055565b90601f1983169562004b4960015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821062004b85575050838596971062004b6c575b505050811b019055565b01515f1960f88460031b161c191690555f808062004b62565b80878596829496860151815501950193019062004b4d565b90813b1562004c24575f80516020620052b183398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562004c08576200247e9162004ee2565b50503462004c1257565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162004cd2579062004ca06020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156200097d575f516001600160a01b0381161562004cc857905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362004d91576bffffffffffffffffffffffff19919035828116916014811062004d7b575b5050905060601c62004d276200179a825f5261020860205260405f2054151590565b62004d695760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c83015262000571908290810162002780565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004d05565b604051639be7315960e01b8152600490fd5b60d15490600160401b821015620004b457600182018060d15582101562002a2a5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020620052f183398151915290910155565b9190918015801562004ed9575b62004ec75762004e1b6200430a565b90810180911162000b74576001600160a01b0380821162004ea7576001600160601b039081851162004e87579062000ea7939462004e7062004e819362004e6162000e98565b95166001600160a01b03168552565b166001600160601b03166020830152565b62004da3565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562004e0c565b5f806200057193602081519101845af462004efc62002a3d565b9162004f72565b6001600160a01b03165f81815260d36020526040902080548381039190821162000b74575f935f80516020620052d1833981519152926020925562004f488162003aa7565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b9062004f89575080511562003b3e57805190602001fd5b8151158062004fbe575b62004f9c575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562004f9356fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c63430008160033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a264697066735822122030100710f8628d5c8d033f3b3bccd8427a47477495128d4a840fa73135e4039964736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101562000026575b36156200001a575f80fd5b6200002462002ca3565b005b5f3560e01c806301e1d114146200041a57806306fdde03146200041457806307a2d13a146200040e578063095ea7b31462000408578063096ae80d14620004025780630b10b20114620003fc57806314c4184b14620003f657806318160ddd14620003c057806318f7295014620003f05780631a7ff55314620003ea57806323b872dd14620003e45780632cdf740114620003de578063313ce56714620003d85780633229fa9514620003d257806333194c0a14620003cc5780633644e51514620003c65780633a98ef3914620003c0578063439fab9114620003ba5780634690484014620003b45780634f1ef28614620003ae57806352d1902d14620003a857806353156f2814620003a257806354fd4d50146200039c5780635c60da1b14620003965780635cfc1a51146200039057806360d60e6e146200038a57806370a0823114620002ee57806372b410a81462000384578063754c3888146200037e57806376b58b9014620003785780637b6341c614620003725780637ecebe00146200036c5780637fd6f15c146200036657806383d430d514620003605780638697d2c2146200035a5780638ceab9aa146200035457806395d89b41146200034e578063a045dd0c1462000348578063a49a1e7d1462000342578063a9059cbb146200033c578063ac9650d81462000336578063ad3cb1cc1462000330578063b1f0e7c7146200032a578063b45a1eb51462000324578063c5aecb22146200031e578063c6e6f5921462000318578063d0a64ddc1462000312578063d505accf146200030c578063d83ad00c1462000306578063dd62ed3e1462000300578063e74b981b14620002fa578063ee3bd5df14620002f4578063f04da65b14620002ee578063f132f5d314620002e8578063f45bf3d214620002e2578063f851a44014620002dc5763f9609f08036200000f57620023e6565b620023bc565b62002377565b6200230a565b620012f1565b620022e2565b620022ad565b62002265565b62002213565b62001feb565b62001faa565b62001f88565b62001f6a565b62001f30565b62001f07565b62001ebc565b62001e4d565b62001dab565b62001d52565b62001d10565b62001c5e565b62001a5b565b620017be565b620015b9565b62001593565b62001554565b62001490565b62001438565b620013c6565b62001330565b620012cf565b620012b1565b6200127a565b6200125d565b62001235565b620011c8565b62000f00565b62000e4e565b62000ca1565b620009de565b62000c21565b62000be5565b62000bb5565b62000b98565b62000b7a565b62000ac9565b62000a90565b62000a15565b620009b3565b620007ca565b62000735565b6200068d565b62000651565b62000574565b6200042f565b5f9103126200042b57565b5f80fd5b346200042b575f3660031901126200042b57602060cf5460801c604051908152f35b90600182811c9216801562000481575b60208310146200046d57565b634e487b7160e01b5f52602260045260245ffd5b91607f169162000461565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111620004b457604052565b6200048c565b604081019081106001600160401b03821117620004b457604052565b608081019081106001600160401b03821117620004b457604052565b90601f801991011681019081106001600160401b03821117620004b457604052565b5f5b838110620005265750505f910152565b818101518382015260200162000516565b90602091620005528151809281855285808601910162000514565b601f01601f1916010190565b9060206200057192818152019062000537565b90565b346200042b575f3660031901126200042b576040515f8054620005978162000451565b80845290602090600190818116908115620006245750600114620005da575b620005d685620005c981870382620004f2565b604051918291826200055e565b0390f35b5f80805293505f80516020620052918339815191525b8385106200061057505050508101602001620005c982620005d6620005b6565b8054868601840152938201938101620005f0565b869550620005d696935060209250620005c994915060ff191682840152151560051b8201019293620005b6565b346200042b5760203660031901126200042b5760206200067360043562002403565b604051908152f35b6001600160a01b038116036200042b57565b346200042b5760403660031901126200042b57600435620006ae816200067b565b6001600160a01b038116906024359082156200072357620006eb8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b346200042b5760203660031901126200042b5760043562000756816200067b565b610206805490916001600160a01b039081169082168114620007b8577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e89281602093620007a262002dd0565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200042b575f3660031901126200042b57620007f6620007ea62002c81565b6001600160a01b031690565b3303620009a1576040516102c8808201908282106001600160401b03831117620004b4578291620008679162004fc984396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff080156200097d576001600160a01b0390811690813b156200042b5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af180156200097d5762000983575b506040516351d5709b60e11b815291602083600481845afa9182156200097d577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f9362000940575b506200090f90831662003e79565b506200091b8162003ee7565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200090f9193506200096d9060203d60201162000975575b620009648183620004f2565b81019062002437565b929062000901565b503d62000958565b6200242c565b80620009936200099a92620004a0565b8062000420565b5f620008b7565b604051634ca8886760e01b8152600490fd5b346200042b575f3660031901126200042b5761026f546040516001600160a01b039091168152602090f35b346200042b575f3660031901126200042b5760206001600160801b0360cf5416604051908152f35b908160809103126200042b5790565b60603660031901126200042b5760043562000a30816200067b565b60243562000a3e816200067b565b604435906001600160401b0382116200042b5760209262000a7262000a6c6200067394369060040162000a06565b6200244f565b62000a7d3362003cc3565b62000a888162003cc3565b349062003dbd565b346200042b5760203660031901126200042b576004356001600160401b0381116200042b5762000a6c6200002491369060040162000a06565b346200042b5760603660031901126200042b5760043562000aea816200067b565b60243562000af8816200067b565b6001600160a01b0382165f818152600260209081526040808320338452909152902090926044359291546001810162000b45575b5062000b39935062003276565b60405160018152602090f35b83810390811162000b74575f94855260026020908152604080872033885290915285205562000b399362000b2c565b6200249f565b346200042b575f3660031901126200042b57602062000673620024c1565b346200042b575f3660031901126200042b57602060405160128152f35b346200042b575f3660031901126200042b57602062000bd3620024fa565b6040516001600160a01b039091168152f35b346200042b575f3660031901126200042b5760206040517f813d21398e0f42fde0737b550f7475616bb950f32cd3f6012ad8b7d81b6c415f8152f35b346200042b575f3660031901126200042b5760206200067362002536565b9181601f840112156200042b578235916001600160401b0383116200042b57602083818601950101116200042b57565b60206003198201126200042b57600435906001600160401b0382116200042b5762000c9d9160040162000c3f565b9091565b62000cac3662000c6f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16801562000e39575b62000e275768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156200097d575f9362000e03575b50604051636f4fa30f60e01b8152938285600481335afa9081156200097d5762000d759562000d6f945f9362000dda575b505062000d6791928101906200259c565b908362003433565b62003506565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016200093b565b62000d679350908162000dfb92903d106200097557620009648183620004f2565b915f62000d56565b62000e1f919350823d84116200097557620009648183620004f2565b915f62000d25565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000cde565b346200042b575f3660031901126200042b57609c546040516001600160a01b039091168152602090f35b6040519060a082018281106001600160401b03821117620004b457604052565b6040519062000ea782620004ba565b565b6001600160401b038111620004b457601f01601f191660200190565b92919262000ed38262000ea9565b9162000ee36040519384620004f2565b8294818452818301116200042b578281602093845f960137010152565b6040806003193601126200042b57600490813562000f1e816200067b565b6024356001600160401b0381116200042b57366023820112156200042b5762000f51903690602481870135910162000ec5565b9162000f5c62003515565b80519262000f978462000f8860209363439fab9160e01b85840152846024840152604483019062000537565b03601f198101865285620004f2565b62000fa162003515565b62000fab62002dd0565b6001600160a01b0383811680159291908790841562001197575b84156200110f575b8415620010a1575b5050821562001001575b505062000ff25762000024838362004254565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156200097d575f926200106d575b5050155f8062000fdf565b620010919250803d1062001099575b620010888183620004f2565b81019062002737565b5f8062001062565b503d6200107c565b855163054fd4d560e41b81529294508391839182905afa9081156200097d5760039160ff915f91620010db575b5016141591865f62000fd5565b620011009150843d861162001107575b620010f78183620004f2565b8101906200423c565b5f620010ce565b503d620010eb565b935050835163198ca60560e11b815282818981875afa9081156200097d5788917f813d21398e0f42fde0737b550f7475616bb950f32cd3f6012ad8b7d81b6c415f915f9162001163575b5014159362000fcd565b620011889150853d87116200118f575b6200117f8183620004f2565b81019062002ebe565b5f62001159565b503d62001173565b5f80516020620052b1833981519152549094508490620011c0906001600160a01b0316620007ea565b149362000fc5565b346200042b575f3660031901126200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620012235760206040515f80516020620052b18339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200042b576001600160a01b0362001253620024fa565b163303620009a157005b346200042b575f3660031901126200042b57602060405160028152f35b346200042b575f3660031901126200042b575f80516020620052b1833981519152546040516001600160a01b039091168152602090f35b346200042b575f3660031901126200042b576020620006736200264b565b346200042b5760203660031901126200042b5760206200067360043562002668565b346200042b5760203660031901126200042b5760043562001312816200067b565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156200097d576020915f91620013a4575b506040519015158152f35b620013bf9150823d84116200109957620010888183620004f2565b5f62001399565b346200042b5760203660031901126200042b57600435620013e7816200067b565b620013f162002dd0565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200042b5760803660031901126200042b57620005d66200147360043562001461816200067b565b6064359060443590602435906200274f565b604080519384526020840192909252908201529081906060820190565b346200042b575f3660031901126200042b5760405180610207805480845260208094019081925f527f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2905f5b868282106200153f578686620014f582880383620004f2565b60405192839281840190828552518091526040840192915f5b8281106200151e57505050500390f35b83516001600160a01b0316855286955093810193928101926001016200150e565b835485529093019260019283019201620014dc565b346200042b5760203660031901126200042b5760043562001575816200067b565b60018060a01b03165f526003602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57602061ffff609c5460a01c16604051908152f35b346200042b576003196040368201126200042b5760049081356001600160401b038082116200042b5760a08285019383360301126200042b576024359081116200042b576200160c903690850162000c3f565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200042b5760405163837d444160e01b8152905f908290818381620016628c828f016200287b565b03925af180156200097d57620017a7575b506200167e62003852565b6200168862002baf565b908116331415918262001770575b505090506200175f576044019160c4620016b1848462002905565b9050048015801562001744575b6200173457620016d8620016d1620024c1565b916200295f565b1162001725575060c4620016ed838362002905565b9050145f146200170e576200002491620017079162002905565b906200470c565b62000024916200171e9162002905565b90620045bf565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b5062001751848462002905565b905060c482021415620016be565b604051634ca8886760e01b81528390fd5b6200179a9250620017936200179e946200178a88620038e5565b92369162000ec5565b91620039cb565b1590565b805f8062001696565b8062000993620017b792620004a0565b5f62001673565b346200042b5760603660031901126200042b57600435602435620017e76044358284336200274f565b9192620018157f0000000000000000000000000000000000000000000000000000000000000000826200265a565b4210801562001a52575b801562001a49575b62001a37577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936200187c86620018766200186a60d0546001600160801b031690565b6001600160801b031690565b62003572565b156200199557620018bc620018a1620018958662003aa7565b60d05460801c62002979565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91620019039190620018f2608082620004f2565b5190205f5260d260205260405f2090565b555f93600183116200193f575b5050505062001920823362003adb565b604080519485526020850191909152830152339180606081015b0390a2005b6200198a929394506200195390886200265a565b60408051336020820190815291810193909352606083018290529094909190620018f29082608081015b03908101835282620004f2565b555f80808062001910565b6200199f62003852565b620019e0620019c4620019b28662003aa7565b60d5546001600160801b031662002979565b6001600160801b03166001600160801b031960d554161760d555565b62001a1a620019ff620019f38562003aa7565b60d55460801c62002979565b6001600160801b0360d5549181199060801b1691161760d555565b62001a3162001a2c8460d6546200265a565b60d655565b620018bc565b604051630e3d8e8d60e11b8152600490fd5b50821562001827565b5081156200181f565b346200042b576040806003193601126200042b576024359060043562001a81836200067b565b62001a8b62003852565b801562001c4d576001600160a01b03831690811562001c3c5762001aaf8162002403565b90811562001c2b5762001ac2826200435c565b62001acd8362003aa7565b60cf5460801c9062001adf9162002979565b62001aff906001600160801b0360cf549181199060801b1691161760cf55565b62001b0b823362004f03565b60d554958660801c828160d6549062001b24916200265a565b9862001b308762003aa7565b62001b44916001600160801b031662004804565b62001b65906001600160801b03166001600160801b031960d554161760d555565b62001b70916200265a565b62001b7b9062003aa7565b62001b9b906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529062001bce608082620004f2565b51902062001be4905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200042b575f3660031901126200042b576040515f6001805462001c838162000451565b808552916020916001811690811562000624575060011462001cb257620005d685620005c981870382620004f2565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851062001cfc57505050508101602001620005c982620005d6620005b6565b805486860184015293820193810162001cdc565b346200042b575f3660031901126200042b57610206546020906001600160a01b039081168062001d4b57508060375416905b60405191168152f35b9062001d42565b346200042b576200193a7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf62001d883662000c6f565b929062001d9462002dd0565b60405191829160208352339560208401916200285b565b346200042b5760403660031901126200042b5762001ddb60043562001dd0816200067b565b602435903362003276565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831062001e1c5750505050505090565b909192939495848062001e3c600193603f198682030187528a5162000537565b980193019301919493929062001e0b565b346200042b5760203660031901126200042b576001600160401b036004358181116200042b57366023820112156200042b5780600401359182116200042b573660248360051b830101116200042b57620005d691602462001eaf920162002aee565b6040519182918262001de6565b346200042b575f3660031901126200042b57620005d660405162001ee081620004ba565b60058152640352e302e360dc1b602082015260405191829160208352602083019062000537565b346200042b575f3660031901126200042b57602062000bd362002baf565b801515036200042b57565b346200042b5760403660031901126200042b576200002460043562001f55816200067b565b6024359062001f648262001f25565b62002be7565b346200042b575f3660031901126200042b57602062000bd362002c81565b346200042b5760203660031901126200042b5760206200067360043562003b7a565b346200042b5760203660031901126200042b576200002460043562001fcf816200067b565b62001fd962002dd0565b62003c17565b60ff8116036200042b57565b346200042b5760e03660031901126200042b576004356200200c816200067b565b6024356200201a816200067b565b604435906064359260843590620020318262001fdf565b6001600160a01b03838116959092908615620007235742811062002201576020915f916200197d6200212d89878a620020ee6200206d62002536565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039162002104601f1993848101835282620004f2565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa156200097d575f51928284168015908115620021f3575b50620021e157620021d28591620021bd7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b556040519384521691602090a3005b6040516323389ba560e21b8152600490fd5b905083831614155f62002175565b604051631ab7da6b60e01b8152600490fd5b346200042b575f3660031901126200042b5760206001600160801b0360d05416604051908152f35b60409060031901126200042b5760043562002256816200067b565b9060243562000571816200067b565b346200042b576020620022a46200227c366200223b565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346200042b5760203660031901126200042b5762000024600435620022d2816200067b565b620022dc62002dd0565b62003c5e565b346200042b575f3660031901126200042b5760206001600160801b0360d55416604051908152f35b346200042b5760203660031901126200042b576004356200232b816200067b565b610205805490916001600160a01b039081169082168114620007b8577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d9281602093620007a262002dd0565b346200042b5760203660031901126200042b5760043562002398816200067b565b60018060a01b03165f52610270602052602060ff60405f2054166040519015158152f35b346200042b575f3660031901126200042b576037546040516001600160a01b039091168152602090f35b602062000673620023f7366200223b565b9062000a7d3362003cc3565b60cf546001600160801b03811690816200241c57505090565b91620005719260801c9062002d4c565b6040513d5f823e3d90fd5b908160209103126200042b575162000571816200067b565b6200245e620024669162002eea565b9190620030a2565b6200246d57565b6200247762004896565b8062002481575b50565b5f906040519081525f80516020620052d183398151915260203092a3565b634e487b7160e01b5f52601160045260245ffd5b9190820391821162000b7457565b4760d0546001600160801b03620024da81831662002403565b9060d55416019060801c01908181115f14620024f4570390565b50505f90565b61016e546001600160a01b03168015620025115790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003620025645760045490565b62000571620032fe565b359061ffff821682036200042b57565b9080601f830112156200042b57816020620005719335910162000ec5565b906020828203126200042b5781356001600160401b03928382116200042b57019060a0828203126200042b57620025d262000e78565b9282358452620025e5602084016200256e565b602085015260408301358181116200042b5782620026059185016200257e565b604085015260608301358181116200042b5782620026259185016200257e565b606085015260808301359081116200042b576200264392016200257e565b608082015290565b60d454806200057157505f1990565b9190820180921162000b7457565b6001600160801b0360d054166200267e6200430a565b90810180911162000b74578110620026b857620026a860d654620026a16200358c565b906200265a565b1115620026b3575f90565b5f1990565b60d19060d1549182915f905b848210620026e057505050811015620026da5790565b505f1990565b909193808316906001818518811c830180931162000b74575f8790525f80516020620052f18339815191528301546001600160a01b03168410156200272b575050935b9190620026c4565b90959101925062002723565b908160209103126200042b5751620005718162001f25565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200278f81608081015b03601f198101835282620004f2565b5190205f5260d260205260405f205491821562002804576001600160801b0360d0541690620027bd6200430a565b91820180921162000b74578391831015620027ef5791620027de926200369b565b90915b82810390811162000b745792565b5090620027fc9162003601565b9091620027e1565b5050505f905f905f90565b9035601e19823603018112156200042b5701602081359101916001600160401b0382116200042b5781360383136200042b57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06200057192602081528235602082015260208301356040820152620028bc620028ab60408501856200280f565b84606085015260c08401916200285b565b90620028f5620028e9620028d460608701876200280f565b601f198587038101608087015295916200285b565b9460808101906200280f565b939092828603019101526200285b565b903590601e19813603018212156200042b57018035906001600160401b0382116200042b576020019181360383136200042b57565b634e487b7160e01b5f52601260045260245ffd5b811562002959570490565b6200293a565b906801bc16d674ec800000918083029283040362000b7457565b6001600160801b03918216908216039190821162000b7457565b6001600160401b038111620004b45760051b60200190565b90620029b78262002993565b620029c66040519182620004f2565b8281528092620029d9601f199162002993565b01905f5b828110620029ea57505050565b806060602080938501015201620029dd565b634e487b7160e01b5f52603260045260245ffd5b9082101562002a2a5762000c9d9160051b81019062002905565b620029fc565b908092918237015f815290565b3d1562002a6c573d9062002a518262000ea9565b9162002a616040519384620004f2565b82523d5f602084013e565b606090565b6020818303126200042b578051906001600160401b0382116200042b570181601f820112156200042b57805162002aa88162000ea9565b9262002ab86040519485620004f2565b818452602082840101116200042b5762000571916020808501910162000514565b805182101562002a2a5760209160051b010190565b91909162002afc83620029ab565b925f5b81811062002b0c57505050565b5f8062002b1b83858762002a10565b6040939162002b2f85518093819362002a30565b0390305af49062002b3f62002a3d565b911562002b6c57509060019162002b57828862002ad9565b5262002b64818762002ad9565b500162002aff565b9060448151106200042b5762002bab62002b956004928381015160248091830101910162002a71565b925162461bcd60e51b815292839283016200055e565b0390fd5b610109546001600160a01b0316806200057157507f000000000000000000000000000000000000000000000000000000000000000090565b61026f546001600160a01b03919082163303620009a1576001600160a01b0381165f90815261027060205260409020549215159260ff161515831462002c7c576001600160a01b0381165f9081526102706020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b610205546001600160a01b039081168062002c9e57506037541690565b905090565b335f5261020a60205260405f20541562002cb957565b62002cc43362003cc3565b6200247e343362003ce5565b90808202905f198184099082808310920391808303921462002d4157612710908282111562002d2f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f198482099383808610950394808603951462002dc1578483111562002d2f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906200057192506200294e565b6037546001600160a01b03163303620009a157565b908160609103126200042b5780519160406020830151920151620005718162001f25565b81835290916001600160fb1b0383116200042b5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200042b576040830152604081013562002e60816200067b565b6001600160a01b031660608381019190915281013536829003601e19018112156200042b5701602081359101906001600160401b0381116200042b578060051b360382136200042b5760a08360808062000571960152019162002e09565b908160209103126200042b575190565b9190915f838201938412911290801582169115161762000b7457565b6040516325f56f1160e01b81526001600160a01b0392916060908290819062002f17906004830162002e2e565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156200097d575f915f905f9562003055575b50841562002ffa578162002f66620024fa565b16917f000000000000000000000000000000000000000000000000000000000000000016821462002ff257509060205f92600460405180958193634641257d60e01b83525af19081156200097d5762002fc8925f9262002fcc575b5062002ece565b9190565b62002fea91925060203d6020116200118f576200117f8183620004f2565b905f62002fc1565b908162003000575b50509190565b803b156200042b57604051636ee3193160e11b815260048101929092525f908290602490829084905af180156200097d576200303e575b8062002ffa565b80620009936200304e92620004a0565b5f62003037565b9194505062003080915060603d60601162003089575b620030778183620004f2565b81019062002de5565b93905f62002f53565b503d6200306b565b600160ff1b811462000b74575f0390565b80156200247e57620030ba6200186a60cf5460801c90565b5f8212620031ba5781620030ce916200265a565b90620030f9620030de8362003aa7565b6001600160801b0360cf549181199060801b1691161760cf55565b62003110609c549161ffff8360a01c169062002cd0565b801562002c7c57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793620031516200186a60cf546001600160801b031690565b80620031a05750506200319b90925b6001600160a01b03169162003176848462004820565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6200319b92620031b39203908462002d4c565b9262003160565b90620031c69062003091565b620031dd6200186a60d5546001600160801b031690565b8062003209575b5080620031ef575050565b62003203620030de9162000ea793620024b3565b62003aa7565b906200326c7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916200325c620019c4620032506200324888886200265a565b878562002d4c565b80809403960362003aa7565b6040519081529081906020820190565b0390a15f620031e4565b90620032828262003cc3565b6200328d8162003cc3565b6001600160a01b039182169182158015620032f3575b6200072357825f5260d360205260405f209081549285840393841162000b74575f80516020620052d183398151915293602093551693845f5260d3825260405f20818154019055604051908152a3565b5080821615620032a3565b6040515f905f5490620033118262000451565b9283825260209384830193600190866001821691825f1462003411575050600114620033c9575b5050918162003352620033c39362002780950382620004f2565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020620052918339815191525b828410620033fb57505050820101816200335262003338565b80548685018601528794909301928101620033e2565b60ff1916875292151560051b8501909201925083915062003352905062003338565b91906200343f62003f55565b6080820151906200344f62003f55565b6001600160a01b03841680156200072357620034fc94620034eb93620034cf926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280620034bc3394602083019062000537565b0390a2602085015161ffff169062003f97565b620034db835162003fed565b620034e562004021565b62004055565b606060408201519101519062004087565b62000ea7620041d0565b62000ea79062001fd962003f55565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562003555575b50506200122357565b5f80516020620052b18339815191525416141590505f806200354c565b906200357d6200430a565b91820180921162000b74571090565b4760d0548060801c820391821162000b745781620035b46001600160801b0380931662002403565b9081620035e0575b50508115620024f4576200057191620035da9160d55416906200434e565b6200435c565b9192509081811115620035f857035b905f80620035bc565b50505f620035ef565b6200360b6200358c565b9160d65492830180931162000b7457808311156200365c57620036309203906200434e565b9060d5548060801c80155f14620036475750508190565b6001600160801b036200057192168462002d4c565b5050505f905f90565b90604051604081018181106001600160401b03821117620004b45760405291546001600160a01b038116835260a01c6020830152565b60d1545f94859493909180841080159062003849575b6200383c578362003805575f5b60d15f526001600160a01b0316620036e65f80516020620052f1833981519152860162003665565b8051909790620036ff906001600160a01b0316620007ea565b98620037266200371a6020809b01516001600160601b031690565b6001600160601b031690565b948381108015620037fa575b620037e85791600193979a956200375562003762939488035b838c03906200434e565b8092019887039162002d4c565b01970193808611801590620037dd575b620037d25760d15f528290620037985f80516020620052f1833981519152870162003665565b805190890151969992966001600160a01b039091169460019392620037629290916001600160601b0390911690620037559088036200374b565b945050509250509190565b508185101562003772565b60405163e8722f8f60e01b8152600490fd5b50808b111562003732565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316620036be565b505093505050505f905f90565b508415620036b1565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156200097d575f91620038c1575b50620038af57565b60405163e775715160e01b8152600490fd5b620038de915060203d6020116200109957620010888183620004f2565b5f620038a7565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200399b5761010a54905b6200393162003929604083018362002905565b369162000ec5565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526200397e81620004d6565b5190206040519161190160f01b8352600283015260228201522090565b620039a562004398565b9062003916565b60041115620039b757565b634e487b7160e01b5f52602160045260245ffd5b620039d7838362004468565b50620039e681959295620039ac565b15938462003a90575b508315620039fe575b50505090565b5f92935090829160405162003a3981620027806020820194630b135d3f60e11b998a8752602484015260406044840152606483019062000537565b51915afa9062003a4862002a3d565b8262003a81575b8262003a61575b50505f8080620039f8565b62003a789192506020808251830101910162002ebe565b145f8062003a56565b91506020825110159162003a4f565b6001600160a01b0383811691161493505f620039ef565b6001600160801b039081811162003abc571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541462003b68576002835581471062003b50575f918291829182916001600160a01b03165af162003b3162002a3d565b501562003b3e5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b0382168115801562003bad575b1562003b9e5750905090565b620005719260801c9162002d4c565b50801562003b92565b60cf546001600160801b038116908215801562003c0e575b1562003bd957505090565b60801c9062003bea82828562002d4c565b92821562002959570962003bfb5790565b600181018091111562000571576200249f565b50811562003bce565b61026f80546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b62003c6862003852565b6001600160a01b0316801562003cb157609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610270602052604090205460ff16620009a157565b919062003cf162003852565b6001600160a01b0383169081156200072357801562003dab578062003d1c6200186a60cf5460801c90565b019362003d286200264b565b851162003d9957620030de9462003d579162003d5162003d488562003bb6565b97889362003aa7565b62004820565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b9092919262003dcb62003852565b6001600160a01b0382169182156200072357811562003dab578162003df66200186a60cf5460801c90565b0162003e016200264b565b811162003d9957620030de9562003e5062003d94927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003d5162003e478862003bb6565b9a8b9362003aa7565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f526102088060205260405f2054155f14620024f4576102078054600160401b811015620004b4576001810180835581101562002a2a5783907f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2015554915f5260205260405f2055600190565b805f5261020a8060205260405f2054155f14620024f4576102098054600160401b811015620004b4576001810180835581101562002a2a5783907f99e87348be6dc95028197b5a6b69c6a7a15df569de2f3d37542e8f40b8bae486015554915f5260205260405f2055600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562003f8557565b604051631afcd79f60e31b8152600490fd5b62003fa162003f55565b61271061ffff83161162003fdb5762003fba9062003c5e565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b62003ff762003f55565b80156200400f57600181016200400a5750565b60d455565b6040516331278a8760e01b8152600490fd5b6200402b62003f55565b6801bc16d674ec8000006200403f6200264b565b106200400f576200404f62004398565b61010a55565b6200405f62003f55565b6001600160a01b031680620040715750565b61016e80546001600160a01b0319169091179055565b6200409162003f55565b601e8151118015620041c4575b620041b257620040ad62003f55565b8051906001600160401b038211620004b457620040d682620040d05f5462000451565b620049dd565b602090816001601f851114620041375750918062004110926200411895945f926200412b575b50508160011b915f199060031b1c19161790565b5f5562004ab2565b62000ea762004126620032fe565b600455565b015190505f80620040fc565b5f80529190601f1984165f8051602062005291833981519152935f905b82821062004199575050916001939185620041189796941062004180575b505050811b015f5562004ab2565b01515f1960f88460031b161c191690555f808062004172565b8060018697829497870151815501960194019062004154565b604051632d3f993760e21b8152600490fd5b50600a8251116200409e565b620041da62003f55565b620041e462003f55565b620041ee62003f55565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca0034106200422a576200247e343062003ce5565b60405163ea2559bb60e01b8152600490fd5b908160209103126200042b5751620005718162001fdf565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481620042e4575b50620042a657604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020620052b18339815191528403620042cb5762000ea792935062004b9d565b604051632a87526960e21b815260048101859052602490fd5b6200430291955060203d6020116200118f576200117f8183620004f2565b935f6200427f565b60d154806200431857505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316620007ea565b908082101562002c9e575090565b60d554908160801c811580156200438f575b156200437a5750905090565b6001600160801b036200057193169162002d4c565b5080156200436e565b6e5661756c7456616c696461746f727360881b6020604051620043bb81620004ba565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117620004b45760405251902090565b81519190604183036200449b57620044949250602082015190606060408401519301515f1a9062004c45565b9192909190565b50505f9160029190565b906030116200042b5790603090565b909291928360b0116200042b5783116200042b5760b0019160af190190565b906090116200042b5760300190606090565b9060c4116200042b5760900190603490565b909392938483116200042b5784116200042b578101920390565b35906020811062004520575090565b5f199060200360031b1b1690565b959493620045606200456f93620045516060969460808b5260808b019062002843565b9089820360208b015262000537565b9187830360408901526200285b565b930152565b969594906200456f936200455162004560926060979560808c5260808c01916200285b565b9060206200057192818152019062002843565b916020620005719381815201916200285b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062004608575050505050505050565b8262004619910180928787620044f7565b90620046268282620044a5565b916200463f62004638858084620044b4565b9062004cdd565b90620046646200465d620046548784620044d3565b979093620044e5565b9062004511565b948c3b156200042b578c5f926801bc16d674ec800000604095620046a087519a8b96879586946304512a2360e31b86528d8d6004880162004574565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194620046e592620046f5575b505192839283620045ac565b0390a160018193019290620045f6565b80620009936200470592620004a0565b5f620046d9565b816030116200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916200475162004638828085620044b4565b6200475d8284620044d3565b94909260b0116200042b57803b156200042b57620047a6946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b600487016200452e565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926200319b92620047ed575b506040519182918262004599565b8062000993620047fd92620004a0565b5f620047df565b9190916001600160801b038080941691160191821162000b7457565b5f80516020620052d183398151915260205f926200483e8562003aa7565b60cf5490620048586001600160801b039182841662004804565b6fffffffffffffffffffffffffffffffff1990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b038216918215620049d75760801c620048d1620048bf8247620024b3565b620048ca8562002403565b906200434e565b908115620049d057620048e48262003b7a565b938415620049c857826200493d620018a16200320362000ea796620030de96620049376200491b620032038d620049bc9a620024b3565b6001600160801b03166001600160801b031960d054161760d055565b6200265a565b62004949818762004dff565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162003203620049a06200498e8862003aa7565b60cf546001600160801b031662002979565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c62002979565b505f93505050565b505f925050565b505f9150565b601f8111620049ea575050565b5f80525f8051602062005291833981519152906020601f840160051c8301931062004a31575b601f0160051c01905b81811062004a25575050565b5f815560010162004a19565b909150819062004a10565b90601f821162004a4a575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931062004aa7575b601f0160051c01905b81811062004a9c57505050565b5f8155820162004a8f565b909150819062004a86565b9081516001600160401b038111620004b45760019062004ade8162004ad8845462000451565b62004a3c565b602080601f831160011462004b165750819062004b129394955f926200412b5750508160011b915f199060031b1c19161790565b9055565b90601f1983169562004b4960015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821062004b85575050838596971062004b6c575b505050811b019055565b01515f1960f88460031b161c191690555f808062004b62565b80878596829496860151815501950193019062004b4d565b90813b1562004c24575f80516020620052b183398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562004c08576200247e9162004ee2565b50503462004c1257565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162004cd2579062004ca06020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156200097d575f516001600160a01b0381161562004cc857905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362004d91576bffffffffffffffffffffffff19919035828116916014811062004d7b575b5050905060601c62004d276200179a825f5261020860205260405f2054151590565b62004d695760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c83015262000571908290810162002780565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004d05565b604051639be7315960e01b8152600490fd5b60d15490600160401b821015620004b457600182018060d15582101562002a2a5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020620052f183398151915290910155565b9190918015801562004ed9575b62004ec75762004e1b6200430a565b90810180911162000b74576001600160a01b0380821162004ea7576001600160601b039081851162004e87579062000ea7939462004e7062004e819362004e6162000e98565b95166001600160a01b03168552565b166001600160601b03166020830152565b62004da3565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562004e0c565b5f806200057193602081519101845af462004efc62002a3d565b9162004f72565b6001600160a01b03165f81815260d36020526040902080548381039190821162000b74575f935f80516020620052d1833981519152926020925562004f488162003aa7565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b9062004f89575080511562003b3e57805190602001fd5b8151158062004fbe575b62004f9c575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562004f9356fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c63430008160033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a264697066735822122030100710f8628d5c8d033f3b3bccd8427a47477495128d4a840fa73135e4039964736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthRestakeBlocklistVault.json b/test/shared/artifacts/EthRestakeBlocklistVault.json deleted file mode 100644 index b424c913..00000000 --- a/test/shared/artifacts/EthRestakeBlocklistVault.json +++ /dev/null @@ -1,1467 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthRestakeBlocklistVault", - "sourceName": "contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "eigenPodOwnerImplementation", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101a034620001e457601f620047d738819003918201601f19168301926001600160401b0392909183851183861017620001e8578160e09284926040978852833981010312620001e4576200005481620001fc565b926200006360208301620001fc565b9362000071828401620001fc565b916200008060608501620001fc565b926200008f60808601620001fc565b9660c0620000a060a08801620001fc565b9601519360805260a05260c0523060e052610100958652610120944686526101409283526101609384526101809485527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c16620001d35780808316036200018e575b50505051936145c59586620002128739608051868181610f42015281816111bf0152818161271a015261302f015260a05186610c54015260c051868181613d900152613ee6015260e051868181610e000152612ce1015251856123da015251846130ad01525183611398015251828181611d8e0152612767015251816104bd0152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200010b565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620001e45756fe6080604052600436101562000026575b36156200001a575f80fd5b62000024620024b7565b005b5f3560e01c806301e1d114146200034e57806307a2d13a1462000348578063096ae80d14620003425780630b10b201146200033c57806314c4184b146200033657806318f7295014620003305780631a7ff553146200032a5780632cdf740114620003245780633229fa95146200031e57806333194c0a14620003185780633a98ef391462000312578063439fab91146200030c5780634690484014620003065780634f1ef286146200030057806352d1902d14620002fa57806353156f2814620002f457806354fd4d5014620002ee5780635c60da1b14620002e85780635cfc1a5114620002e257806360d60e6e14620002dc57806372b410a814620002d6578063754c388814620002d057806376b58b9014620002ca5780637b6341c614620002c45780637fd6f15c14620002be57806383d430d514620002b85780638697d2c214620002b25780638ceab9aa14620002ac578063a045dd0c14620002a6578063a49a1e7d14620002a0578063ac9650d8146200029a578063ad3cb1cc1462000294578063b1f0e7c7146200028e578063b45a1eb51462000288578063c5aecb221462000282578063c6e6f592146200027c578063d0a64ddc1462000276578063d83ad00c1462000270578063e74b981b146200026a578063ee3bd5df1462000264578063f04da65b146200025e578063f132f5d31462000258578063f45bf3d21462000252578063f851a440146200024c5763f9609f08036200000f5762001c94565b62001c6b565b62001c26565b62001bb9565b62001b7a565b62001b52565b62001b1d565b62001af5565b62001ac0565b62001a9e565b62001a80565b62001a46565b62001a1d565b620019d2565b6200194d565b62001843565b62001802565b620015ff565b62001367565b62001162565b6200113c565b62001078565b6200101c565b62000fab565b62000f15565b62000ef3565b62000ed5565b62000e9e565b62000e81565b62000e59565b62000dec565b62000b24565b620009f4565b62000847565b620007bd565b62000781565b62000751565b62000733565b620006fa565b6200067f565b62000645565b62000456565b620003c1565b62000385565b62000363565b5f9103126200035f57565b5f80fd5b346200035f575f3660031901126200035f57602060985460801c604051908152f35b346200035f5760203660031901126200035f576020620003a760043562001cc4565b604051908152f35b6001600160a01b038116036200035f57565b346200035f5760203660031901126200035f57600435620003e281620003af565b61019d805490916001600160a01b03908116908216811462000444577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e892816020936200042e620025ce565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200035f575f3660031901126200035f57620004826200047662002496565b6001600160a01b031690565b330362000633576040516102c8808201908282106001600160401b038311176200062d578291620004f3916200428884396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff0801562000609576001600160a01b0390811690813b156200035f5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af1801562000609576200060f575b506040516351d5709b60e11b815291602083600481845afa91821562000609577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f93620005cc575b506200059b9083166200363a565b50620005a781620036a8565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200059b919350620005f99060203d60201162000601575b620005f0818362000a9a565b81019062001cf8565b92906200058d565b503d620005e4565b62001ced565b806200061f620006269262000a32565b8062000354565b5f62000543565b62000a1e565b604051634ca8886760e01b8152600490fd5b346200035f575f3660031901126200035f57610206546040516001600160a01b039091168152602090f35b908160809103126200035f5790565b60603660031901126200035f576004356200069a81620003af565b602435620006a881620003af565b604435906001600160401b0382116200035f57602092620006dc620006d6620003a794369060040162000670565b62001d10565b620006e73362003484565b620006f28162003484565b34906200357e565b346200035f5760203660031901126200035f576004356001600160401b0381116200035f57620006d66200002491369060040162000670565b346200035f575f3660031901126200035f576020620003a762001d3b565b346200035f575f3660031901126200035f5760206200076f62001d74565b6040516001600160a01b039091168152f35b346200035f575f3660031901126200035f5760206040517f903c7cfddba46ee63384d0bf7016d55c117fc01332779257355a1400c68e97d18152f35b346200035f575f3660031901126200035f5760206001600160801b0360985416604051908152f35b9181601f840112156200035f578235916001600160401b0383116200035f57602083818601950101116200035f57565b60206003198201126200035f57600435906001600160401b0382116200035f576200084391600401620007e5565b9091565b620008523662000815565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c168015620009df575b620009cd5768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa92831562000609575f93620009a9575b50604051636f4fa30f60e01b8152938285600481335afa90811562000609576200091b9562000915945f9362000980575b50506200090d919281019062001db0565b908362002bba565b62002cc8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2908060208101620005c7565b6200090d93509081620009a192903d106200060157620005f0818362000a9a565b915f620008fc565b620009c5919350823d84116200060157620005f0818362000a9a565b915f620008cb565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000884565b346200035f575f3660031901126200035f576065546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200062d57604052565b606081019081106001600160401b038211176200062d57604052565b604081019081106001600160401b038211176200062d57604052565b608081019081106001600160401b038211176200062d57604052565b90601f801991011681019081106001600160401b038211176200062d57604052565b6040519062000acb8262000a62565b565b6001600160401b0381116200062d57601f01601f191660200190565b92919262000af78262000acd565b9162000b07604051938462000a9a565b8294818452818301116200035f578281602093845f960137010152565b6040806003193601126200035f57600490813562000b4281620003af565b6024356001600160401b0381116200035f57366023820112156200035f5762000b75903690602481870135910162000ae9565b9162000b8062002cd7565b80519262000bbb8462000bac60209363439fab9160e01b858401528460248401526044830190620018bf565b03601f19810186528562000a9a565b62000bc562002cd7565b62000bcf620025ce565b6001600160a01b0383811680159291908790841562000dbb575b841562000d33575b841562000cc5575b5050821562000c25575b505062000c165762000024838362003a31565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821562000609575f9262000c91575b5050155f8062000c03565b62000cb59250803d1062000cbd575b62000cac818362000a9a565b81019062001f3f565b5f8062000c86565b503d62000ca0565b855163054fd4d560e41b81529294508391839182905afa908115620006095760039160ff915f9162000cff575b5016141591865f62000bf9565b62000d249150843d861162000d2b575b62000d1b818362000a9a565b81019062003a16565b5f62000cf2565b503d62000d0f565b935050835163198ca60560e11b815282818981875afa908115620006095788917f903c7cfddba46ee63384d0bf7016d55c117fc01332779257355a1400c68e97d1915f9162000d87575b5014159362000bf1565b62000dac9150853d871162000db3575b62000da3818362000a9a565b810190620026bb565b5f62000d7d565b503d62000d97565b5f805160206200457083398151915254909450849062000de4906001600160a01b031662000476565b149362000be9565b346200035f575f3660031901126200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300362000e475760206040515f80516020620045708339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200035f576001600160a01b0362000e7762001d74565b1633036200063357005b346200035f575f3660031901126200035f57602060405160028152f35b346200035f575f3660031901126200035f575f8051602062004570833981519152546040516001600160a01b039091168152602090f35b346200035f575f3660031901126200035f576020620003a762001e39565b346200035f5760203660031901126200035f576020620003a760043562001e70565b346200035f575f3660031901126200035f57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801562000609576020915f9162000f89575b506040519015158152f35b62000fa49150823d841162000cbd5762000cac818362000a9a565b5f62000f7e565b346200035f5760203660031901126200035f5760043562000fcc81620003af565b62000fd6620025ce565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200035f5760803660031901126200035f5762001074620010576004356200104581620003af565b60643590604435906024359062001f65565b604080519384526020840192909252908201529081906060820190565b0390f35b346200035f575f3660031901126200035f576040518061019e805480845260208094019081925f527fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b905f5b8682821062001127578686620010dd8288038362000a9a565b60405192839281840190828552518091526040840192915f5b8281106200110657505050500390f35b83516001600160a01b031685528695509381019392810192600101620010f6565b835485529093019260019283019201620010c4565b346200035f575f3660031901126200035f57602061ffff60655460a01c16604051908152f35b346200035f576003196040368201126200035f5760049081356001600160401b038082116200035f5760a08285019383360301126200035f576024359081116200035f57620011b59036908501620007e5565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200035f5760405163837d444160e01b8152905f9082908183816200120b8c828f0162002091565b03925af18015620006095762001350575b506200122762003014565b62001231620023c5565b908116331415918262001319575b5050905062001308576044019160c46200125a84846200211b565b90500480158015620012ed575b620012dd57620012816200127a62001d3b565b9162002175565b11620012ce575060c46200129683836200211b565b9050145f14620012b7576200002491620012b0916200211b565b9062003edb565b6200002491620012c7916200211b565b9062003d8e565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50620012fa84846200211b565b905060c48202141562001267565b604051634ca8886760e01b81528390fd5b6200134392506200133c62001347946200133388620030a7565b92369162000ae9565b916200318c565b1590565b805f806200123f565b806200061f620013609262000a32565b5f6200121c565b346200035f5760603660031901126200035f576004356024356200139060443582843362001f65565b9192620013be7f00000000000000000000000000000000000000000000000000000000000000008262001e5c565b42108015620015f6575b8015620015ed575b620015db577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb569362001425866200141f620014136099546001600160801b031690565b6001600160801b031690565b62002d34565b156200153957620014656200144a6200143e8662003268565b60995460801c6200218f565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91620014ac91906200149b60808262000a9a565b5190205f52609b60205260405f2090565b555f9360018311620014e8575b50505050620014c982336200329c565b604080519485526020850191909152830152339180606081015b0390a2005b6200152e92939450620014fc908862001e5c565b60408051336020820190815291810193909352606083018290526080958601835290949091906200149b908262000a9a565b555f808080620014b9565b6200154362003014565b6200158462001568620015568662003268565b609e546001600160801b03166200218f565b6001600160801b03166001600160801b0319609e541617609e55565b620015be620015a3620015978562003268565b609e5460801c6200218f565b6001600160801b03609e549181199060801b16911617609e55565b620015d5620015d084609f5462001e5c565b609f55565b62001465565b604051630e3d8e8d60e11b8152600490fd5b508215620013d0565b508115620013c8565b346200035f576040806003193601126200035f57602435906004356200162583620003af565b6200162f62003014565b8015620017f1576001600160a01b038316908115620017e057620016538162001cc4565b908115620017cf57620016668262003b2b565b620016718362003268565b60985460801c9062001683916200218f565b620016a3906001600160801b036098549181199060801b16911617609855565b620016af8233620041c6565b609e54958660801c8281609f5490620016c89162001e5c565b98620016d48762003268565b620016e8916001600160801b031662003716565b62001709906001600160801b03166001600160801b0319609e541617609e55565b620017149162001e5c565b6200171f9062003268565b6200173f906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906200177260808262000a9a565b51902062001788905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200035f575f3660031901126200035f5761019d546020906001600160a01b03908116806200183c5750805f5416905b60405191168152f35b9062001833565b346200035f57620014e37f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf620018793662000815565b929062001885620025ce565b604051918291602083523395602084019162002071565b5f5b838110620018ae5750505f910152565b81810151838201526020016200189e565b90602091620018da815180928185528580860191016200189c565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106200191c5750505050505090565b90919293949584806200193c600193603f198682030187528a51620018bf565b98019301930191949392906200190b565b346200035f5760203660031901126200035f576001600160401b036004358181116200035f57366023820112156200035f5780600401359182116200035f573660248360051b830101116200035f5762001074916024620019af920162002304565b60405191829182620018e6565b906020620019cf928181520190620018bf565b90565b346200035f575f3660031901126200035f5762001074604051620019f68162000a62565b60058152640352e302e360dc1b6020820152604051918291602083526020830190620018bf565b346200035f575f3660031901126200035f5760206200076f620023c5565b801515036200035f57565b346200035f5760403660031901126200035f576200002460043562001a6b81620003af565b6024359062001a7a8262001a3b565b620023fc565b346200035f575f3660031901126200035f5760206200076f62002496565b346200035f5760203660031901126200035f576020620003a76004356200333b565b346200035f5760203660031901126200035f576200002460043562001ae581620003af565b62001aef620025ce565b620033d8565b346200035f575f3660031901126200035f5760206001600160801b0360995416604051908152f35b346200035f5760203660031901126200035f576200002460043562001b4281620003af565b62001b4c620025ce565b6200341f565b346200035f575f3660031901126200035f5760206001600160801b03609e5416604051908152f35b346200035f5760203660031901126200035f5760043562001b9b81620003af565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346200035f5760203660031901126200035f5760043562001bda81620003af565b61019c805490916001600160a01b03908116908216811462000444577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d92816020936200042e620025ce565b346200035f5760203660031901126200035f5760043562001c4781620003af565b60018060a01b03165f52610207602052602060ff60405f2054166040519015158152f35b346200035f575f3660031901126200035f575f546040516001600160a01b039091168152602090f35b60403660031901126200035f576020620003a760043562001cb581620003af565b60243590620006dc82620003af565b6098546001600160801b038116908162001cdd57505090565b91620019cf9260801c906200254a565b6040513d5f823e3d90fd5b908160209103126200035f5751620019cf81620003af565b62001d1f62001d2791620026e7565b91906200289f565b62001d2e57565b62001d3862002a73565b50565b476099546001600160801b0362001d5481831662001cc4565b90609e5416019060801c01908181115f1462001d6e570390565b50505f90565b610137546001600160a01b0316801562001d8b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b906020828203126200035f5781356001600160401b03928382116200035f5701916060838303126200035f576040519262001deb8462000a46565b80358452602081013561ffff811681036200035f57602085015260408101359182116200035f57019080601f830112156200035f5781602062001e319335910162000ae9565b604082015290565b609d5480620019cf57505f1990565b634e487b7160e01b5f52601160045260245ffd5b9190820180921162001e6a57565b62001e48565b6001600160801b036099541662001e8662003ae7565b90810180911162001e6a57811062001ec05762001eb0609f5462001ea962002d4e565b9062001e5c565b111562001ebb575f90565b5f1990565b609a90609a549182915f905b84821062001ee85750505081101562001ee25790565b505f1990565b909193808316906001818518811c830180931162001e6a575f8790525f80516020620045508339815191528301546001600160a01b031684101562001f33575050935b919062001ecc565b90959101925062001f2b565b908160209103126200035f5751620019cf8162001a3b565b9190820391821162001e6a57565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919062001fa581608081015b03601f19810183528262000a9a565b5190205f52609b60205260405f20549182156200201a576001600160801b03609954169062001fd362003ae7565b91820180921162001e6a57839183101562002005579162001ff49262002e5d565b90915b82810390811162001e6a5792565b5090620020129162002dc3565b909162001ff7565b5050505f905f905f90565b9035601e19823603018112156200035f5701602081359101916001600160401b0382116200035f5781360383136200035f57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620019cf92602081528235602082015260208301356040820152620020d2620020c1604085018562002025565b84606085015260c084019162002071565b906200210b620020ff620020ea606087018762002025565b601f1985870381016080870152959162002071565b94608081019062002025565b9390928286030191015262002071565b903590601e19813603018212156200035f57018035906001600160401b0382116200035f576020019181360383136200035f57565b634e487b7160e01b5f52601260045260245ffd5b81156200216f570490565b62002150565b906801bc16d674ec800000918083029283040362001e6a57565b6001600160801b03918216908216039190821162001e6a57565b6001600160401b0381116200062d5760051b60200190565b90620021cd82620021a9565b620021dc604051918262000a9a565b8281528092620021ef601f1991620021a9565b01905f5b8281106200220057505050565b806060602080938501015201620021f3565b634e487b7160e01b5f52603260045260245ffd5b908210156200224057620008439160051b8101906200211b565b62002212565b908092918237015f815290565b3d1562002282573d90620022678262000acd565b9162002277604051938462000a9a565b82523d5f602084013e565b606090565b6020818303126200035f578051906001600160401b0382116200035f570181601f820112156200035f578051620022be8162000acd565b92620022ce604051948562000a9a565b818452602082840101116200035f57620019cf91602080850191016200189c565b8051821015620022405760209160051b010190565b9190916200231283620021c1565b925f5b8181106200232257505050565b5f806200233183858762002226565b604093916200234585518093819362002246565b0390305af4906200235562002253565b9115620023825750906001916200236d8288620022ef565b526200237a8187620022ef565b500162002315565b9060448151106200035f57620023c1620023ab6004928381015160248091830101910162002287565b925162461bcd60e51b81529283928301620019bc565b0390fd5b60d2546001600160a01b031680620019cf57507f000000000000000000000000000000000000000000000000000000000000000090565b610206546001600160a01b0391908216330362000633576001600160a01b0381165f90815261020760205260409020549215159260ff161515831462002491576001600160a01b0381165f9081526102076020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b61019c546001600160a01b0390811680620024b257505f541690565b905090565b620024c23362003484565b62001d383433620034a6565b90808202905f19818409908280831092039180830392146200253f5761271090828211156200252d577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514620025bf57848311156200252d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620019cf925062002164565b5f546001600160a01b031633036200063357565b908160609103126200035f5780519160406020830151920151620019cf8162001a3b565b81835290916001600160fb1b0383116200035f5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200035f57604083015260408101356200265d81620003af565b6001600160a01b031660608381019190915281013536829003601e19018112156200035f5701602081359101906001600160401b0381116200035f578060051b360382136200035f5760a083608080620019cf960152019162002606565b908160209103126200035f575190565b9190915f838201938412911290801582169115161762001e6a57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906200271490600483016200262b565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831562000609575f915f905f9562002852575b508415620027f757816200276362001d74565b16917f0000000000000000000000000000000000000000000000000000000000000000168214620027ef57509060205f92600460405180958193634641257d60e01b83525af19081156200060957620027c5925f92620027c9575b50620026cb565b9190565b620027e791925060203d60201162000db35762000da3818362000a9a565b905f620027be565b9081620027fd575b50509190565b803b156200035f57604051636ee3193160e11b815260048101929092525f908290602490829084905af1801562000609576200283b575b80620027f7565b806200061f6200284b9262000a32565b5f62002834565b919450506200287d915060603d60601162002886575b62002874818362000a9a565b810190620025e2565b93905f62002750565b503d62002868565b600160ff1b811462001e6a575f0390565b801562001d3857620028b76200141360985460801c90565b5f8212620029b75781620028cb9162001e5c565b90620028f6620028db8362003268565b6001600160801b036098549181199060801b16911617609855565b6200290d6065549161ffff8360a01c1690620024ce565b80156200249157807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936200294e620014136098546001600160801b031690565b806200299d5750506200299890925b6001600160a01b03169162002973848462003732565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6200299892620029b0920390846200254a565b926200295d565b90620029c3906200288e565b620029da62001413609e546001600160801b031690565b8062002a06575b5080620029ec575050565b62002a00620028db9162000acb9362001f57565b62003268565b9062002a697f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9162002a596200156862002a4d62002a45888862001e5c565b87856200254a565b80809403960362003268565b6040519081529081906020820190565b0390a15f620029e1565b609954906001600160801b03821691821562002bb45760801c62002aae62002a9c824762001f57565b62002aa78562001cc4565b9062003782565b90811562002bad5762002ac1826200333b565b93841562002ba5578262002b1a6200144a62002a0062000acb96620028db9662002b1462002af862002a008d62002b999a62001f57565b6001600160801b03166001600160801b03196099541617609955565b62001e5c565b62002b268187620037ec565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162002a0062002b7d62002b6b8862003268565b6098546001600160801b03166200218f565b6001600160801b03166001600160801b03196098541617609855565b60985460801c6200218f565b505f93505050565b505f925050565b505f9150565b62002bc4620038cf565b604083015162002bd3620038cf565b6001600160a01b038216801562002cb6576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528062002c2f33946020830190620018bf565b0390a260208301519262002c42620038cf565b61271061ffff85161162002ca45762002c9a9362002c6462002c8a936200341f565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555162003911565b62002c9462003945565b62003978565b62000acb620039aa565b604051638a81d3b360e01b8152600490fd5b60405163d92e233d60e01b8152600490fd5b62000acb9062001aef620038cf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562002d17575b505062000e4757565b5f80516020620045708339815191525416141590505f8062002d0e565b9062002d3f62003ae7565b91820180921162001e6a571090565b476099548060801c820391821162001e6a578162002d766001600160801b0380931662001cc4565b908162002da2575b5050811562001d6e57620019cf9162002d9c91609e54169062003782565b62003b2b565b919250908181111562002dba57035b905f8062002d7e565b50505f62002db1565b62002dcd62002d4e565b91609f5492830180931162001e6a578083111562002e1e5762002df292039062003782565b90609e548060801c80155f1462002e095750508190565b6001600160801b03620019cf9216846200254a565b5050505f905f90565b90604051604081018181106001600160401b038211176200062d5760405291546001600160a01b038116835260a01c6020830152565b609a545f9485949390918084108015906200300b575b62002ffe578362002fc7575f5b609a5f526001600160a01b031662002ea85f8051602062004550833981519152860162002e27565b805190979062002ec1906001600160a01b031662000476565b9862002ee862002edc6020809b01516001600160601b031690565b6001600160601b031690565b94838110801562002fbc575b62002faa5791600193979a9562002f1762002f24939488035b838c039062003782565b809201988703916200254a565b0197019380861180159062002f9f575b62002f9457609a5f52829062002f5a5f8051602062004550833981519152870162002e27565b805190890151969992966001600160a01b03909116946001939262002f249290916001600160601b039091169062002f1790880362002f0d565b945050509250509190565b508185101562002f34565b60405163e8722f8f60e01b8152600490fd5b50808b111562002ef4565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031662002e80565b505093505050505f905f90565b50841562002e73565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562000609575f9162003083575b506200307157565b60405163e775715160e01b8152600490fd5b620030a0915060203d60201162000cbd5762000cac818362000a9a565b5f62003069565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200315c5760d354905b620030f2620030ea60408301836200211b565b369162000ae9565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526200313f8162000a7e565b5190206040519161190160f01b8352600283015260228201522090565b6200316662003b67565b90620030d7565b600411156200317857565b634e487b7160e01b5f52602160045260245ffd5b62003198838362003c37565b50620031a7819592956200316d565b15938462003251575b508315620031bf575b50505090565b5f929350908291604051620031fa8162001f966020820194630b135d3f60e11b998a87526024840152604060448401526064830190620018bf565b51915afa906200320962002253565b8262003242575b8262003222575b50505f8080620031b9565b6200323991925060208082518301019101620026bb565b145f8062003217565b91506020825110159162003210565b6001600160a01b0383811691161493505f620031b0565b6001600160801b03908181116200327d571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541462003329576002835581471062003311575f918291829182916001600160a01b03165af1620032f262002253565b5015620032ff5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b038216811580156200336e575b156200335f5750905090565b620019cf9260801c916200254a565b50801562003353565b6098546001600160801b0381169082158015620033cf575b156200339a57505090565b60801c90620033ab8282856200254a565b9282156200216f5709620033bc5790565b6001810180911115620019cf5762001e48565b5081156200338f565b61020680546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b6200342962003014565b6001600160a01b031680156200347257606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610207602052604090205460ff166200063357565b9190620034b262003014565b6001600160a01b03831690811562002cb65780156200356c5780620034dd6200141360985460801c90565b0193620034e962001e39565b85116200355a57620028db94620035189162003512620035098562003377565b97889362003268565b62003732565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926200358c62003014565b6001600160a01b03821691821562002cb65781156200356c5781620035b76200141360985460801c90565b01620035c262001e39565b81116200355a57620028db956200361162003555927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003512620036088862003377565b9a8b9362003268565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f5261019f8060205260405f2054155f1462001d6e5761019e8054600160401b8110156200062d5760018101808355811015620022405783907fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b015554915f5260205260405f2055600190565b805f526101a18060205260405f2054155f1462001d6e576101a08054600160401b8110156200062d5760018101808355811015620022405783907f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c4015554915f5260205260405f2055600190565b9190916001600160801b038080941691160191821162001e6a57565b6200373d8262003268565b60985490620037576001600160801b039182841662003716565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015620024b2575090565b609a5490600160401b8210156200062d576001820180609a558210156200224057609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206200455083398151915290910155565b91909180158015620038c6575b620038b4576200380862003ae7565b90810180911162001e6a576001600160a01b0380821162003894576001600160601b039081851162003874579062000acb93946200385d6200386e936200384e62000abc565b95166001600160a01b03168552565b166001600160601b03166020830152565b62003790565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b508215620037f9565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615620038ff57565b604051631afcd79f60e31b8152600490fd5b6200391b620038cf565b80156200393357600181016200392e5750565b609d55565b6040516331278a8760e01b8152600490fd5b6200394f620038cf565b6801bc16d674ec8000006200396362001e39565b1062003933576200397362003b67565b60d355565b62003982620038cf565b6001600160a01b031680620039945750565b61013780546001600160a01b0319169091179055565b620039b4620038cf565b620039be620038cf565b620039c8620038cf565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341062003a045762001d383430620034a6565b60405163ea2559bb60e01b8152600490fd5b908160209103126200035f575160ff811681036200035f5790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948162003ac1575b5062003a8357604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f8051602062004570833981519152840362003aa85762000acb92935062003fd3565b604051632a87526960e21b815260048101859052602490fd5b62003adf91955060203d60201162000db35762000da3818362000a9a565b935f62003a5c565b609a548062003af557505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031662000476565b609e54908160801c8115801562003b5e575b1562003b495750905090565b6001600160801b03620019cf9316916200254a565b50801562003b3d565b6e5661756c7456616c696461746f727360881b602060405162003b8a8162000a62565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176200062d5760405251902090565b815191906041830362003c6a5762003c639250602082015190606060408401519301515f1a906200407b565b9192909190565b50505f9160029190565b906030116200035f5790603090565b909291928360b0116200035f5783116200035f5760b0019160af190190565b906090116200035f5760300190606090565b9060c4116200035f5760900190603490565b909392938483116200035f5784116200035f578101920390565b35906020811062003cef575090565b5f199060200360031b1b1690565b95949362003d2f62003d3e9362003d206060969460808b5260808b019062002059565b9089820360208b0152620018bf565b91878303604089015262002071565b930152565b9695949062003d3e9362003d2062003d2f926060979560808c5260808c019162002071565b906020620019cf92818152019062002059565b916020620019cf93818152019162002071565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062003dd7575050505050505050565b8262003de891018092878762003cc6565b9062003df5828262003c74565b9162003e0e62003e0785808462003c83565b9062004100565b9062003e3362003e2c62003e23878462003ca2565b97909362003cb4565b9062003ce0565b948c3b156200035f578c5f926801bc16d674ec80000060409562003e6f87519a8b96879586946304512a2360e31b86528d8d6004880162003d43565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19462003eb49262003ec4575b50519283928362003d7b565b0390a16001819301929062003dc5565b806200061f62003ed49262000a32565b5f62003ea8565b816030116200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169162003f2062003e0782808562003c83565b62003f2c828462003ca2565b94909260b0116200035f57803b156200035f5762003f75946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162003cfd565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192620029989262003fbc575b506040519182918262003d68565b806200061f62003fcc9262000a32565b5f62003fae565b90813b156200405a575f805160206200457083398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156200403e5762001d389162004216565b5050346200404857565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411620040f5579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1562000609575f516001600160a01b03811615620040eb57905f905f90565b505f906001905f90565b5050505f9160039190565b60148203620041b4576bffffffffffffffffffffffff1991903582811691601481106200419e575b5050905060601c6200414a62001343825f5261019f60205260405f2054151590565b6200418c5760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c830152620019cf908290810162001f96565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004128565b604051639be7315960e01b8152600490fd5b60018060a01b03165f52609c60205260405f2090815481810390811162001e6a57620041f3925562003268565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f80620019cf93602081519101845af46200423062002253565b9190620042485750805115620032ff57805190602001fd5b815115806200427d575b6200425b575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200425256fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003344da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220e2d517320a9fadaaddd17a211bfed4486c2c06086c6439e680db393c4e762f5a64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101562000026575b36156200001a575f80fd5b62000024620024b7565b005b5f3560e01c806301e1d114146200034e57806307a2d13a1462000348578063096ae80d14620003425780630b10b201146200033c57806314c4184b146200033657806318f7295014620003305780631a7ff553146200032a5780632cdf740114620003245780633229fa95146200031e57806333194c0a14620003185780633a98ef391462000312578063439fab91146200030c5780634690484014620003065780634f1ef286146200030057806352d1902d14620002fa57806353156f2814620002f457806354fd4d5014620002ee5780635c60da1b14620002e85780635cfc1a5114620002e257806360d60e6e14620002dc57806372b410a814620002d6578063754c388814620002d057806376b58b9014620002ca5780637b6341c614620002c45780637fd6f15c14620002be57806383d430d514620002b85780638697d2c214620002b25780638ceab9aa14620002ac578063a045dd0c14620002a6578063a49a1e7d14620002a0578063ac9650d8146200029a578063ad3cb1cc1462000294578063b1f0e7c7146200028e578063b45a1eb51462000288578063c5aecb221462000282578063c6e6f592146200027c578063d0a64ddc1462000276578063d83ad00c1462000270578063e74b981b146200026a578063ee3bd5df1462000264578063f04da65b146200025e578063f132f5d31462000258578063f45bf3d21462000252578063f851a440146200024c5763f9609f08036200000f5762001c94565b62001c6b565b62001c26565b62001bb9565b62001b7a565b62001b52565b62001b1d565b62001af5565b62001ac0565b62001a9e565b62001a80565b62001a46565b62001a1d565b620019d2565b6200194d565b62001843565b62001802565b620015ff565b62001367565b62001162565b6200113c565b62001078565b6200101c565b62000fab565b62000f15565b62000ef3565b62000ed5565b62000e9e565b62000e81565b62000e59565b62000dec565b62000b24565b620009f4565b62000847565b620007bd565b62000781565b62000751565b62000733565b620006fa565b6200067f565b62000645565b62000456565b620003c1565b62000385565b62000363565b5f9103126200035f57565b5f80fd5b346200035f575f3660031901126200035f57602060985460801c604051908152f35b346200035f5760203660031901126200035f576020620003a760043562001cc4565b604051908152f35b6001600160a01b038116036200035f57565b346200035f5760203660031901126200035f57600435620003e281620003af565b61019d805490916001600160a01b03908116908216811462000444577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e892816020936200042e620025ce565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200035f575f3660031901126200035f57620004826200047662002496565b6001600160a01b031690565b330362000633576040516102c8808201908282106001600160401b038311176200062d578291620004f3916200428884396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff0801562000609576001600160a01b0390811690813b156200035f5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af1801562000609576200060f575b506040516351d5709b60e11b815291602083600481845afa91821562000609577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f93620005cc575b506200059b9083166200363a565b50620005a781620036a8565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200059b919350620005f99060203d60201162000601575b620005f0818362000a9a565b81019062001cf8565b92906200058d565b503d620005e4565b62001ced565b806200061f620006269262000a32565b8062000354565b5f62000543565b62000a1e565b604051634ca8886760e01b8152600490fd5b346200035f575f3660031901126200035f57610206546040516001600160a01b039091168152602090f35b908160809103126200035f5790565b60603660031901126200035f576004356200069a81620003af565b602435620006a881620003af565b604435906001600160401b0382116200035f57602092620006dc620006d6620003a794369060040162000670565b62001d10565b620006e73362003484565b620006f28162003484565b34906200357e565b346200035f5760203660031901126200035f576004356001600160401b0381116200035f57620006d66200002491369060040162000670565b346200035f575f3660031901126200035f576020620003a762001d3b565b346200035f575f3660031901126200035f5760206200076f62001d74565b6040516001600160a01b039091168152f35b346200035f575f3660031901126200035f5760206040517f903c7cfddba46ee63384d0bf7016d55c117fc01332779257355a1400c68e97d18152f35b346200035f575f3660031901126200035f5760206001600160801b0360985416604051908152f35b9181601f840112156200035f578235916001600160401b0383116200035f57602083818601950101116200035f57565b60206003198201126200035f57600435906001600160401b0382116200035f576200084391600401620007e5565b9091565b620008523662000815565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c168015620009df575b620009cd5768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa92831562000609575f93620009a9575b50604051636f4fa30f60e01b8152938285600481335afa90811562000609576200091b9562000915945f9362000980575b50506200090d919281019062001db0565b908362002bba565b62002cc8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2908060208101620005c7565b6200090d93509081620009a192903d106200060157620005f0818362000a9a565b915f620008fc565b620009c5919350823d84116200060157620005f0818362000a9a565b915f620008cb565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000884565b346200035f575f3660031901126200035f576065546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200062d57604052565b606081019081106001600160401b038211176200062d57604052565b604081019081106001600160401b038211176200062d57604052565b608081019081106001600160401b038211176200062d57604052565b90601f801991011681019081106001600160401b038211176200062d57604052565b6040519062000acb8262000a62565b565b6001600160401b0381116200062d57601f01601f191660200190565b92919262000af78262000acd565b9162000b07604051938462000a9a565b8294818452818301116200035f578281602093845f960137010152565b6040806003193601126200035f57600490813562000b4281620003af565b6024356001600160401b0381116200035f57366023820112156200035f5762000b75903690602481870135910162000ae9565b9162000b8062002cd7565b80519262000bbb8462000bac60209363439fab9160e01b858401528460248401526044830190620018bf565b03601f19810186528562000a9a565b62000bc562002cd7565b62000bcf620025ce565b6001600160a01b0383811680159291908790841562000dbb575b841562000d33575b841562000cc5575b5050821562000c25575b505062000c165762000024838362003a31565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821562000609575f9262000c91575b5050155f8062000c03565b62000cb59250803d1062000cbd575b62000cac818362000a9a565b81019062001f3f565b5f8062000c86565b503d62000ca0565b855163054fd4d560e41b81529294508391839182905afa908115620006095760039160ff915f9162000cff575b5016141591865f62000bf9565b62000d249150843d861162000d2b575b62000d1b818362000a9a565b81019062003a16565b5f62000cf2565b503d62000d0f565b935050835163198ca60560e11b815282818981875afa908115620006095788917f903c7cfddba46ee63384d0bf7016d55c117fc01332779257355a1400c68e97d1915f9162000d87575b5014159362000bf1565b62000dac9150853d871162000db3575b62000da3818362000a9a565b810190620026bb565b5f62000d7d565b503d62000d97565b5f805160206200457083398151915254909450849062000de4906001600160a01b031662000476565b149362000be9565b346200035f575f3660031901126200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300362000e475760206040515f80516020620045708339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200035f576001600160a01b0362000e7762001d74565b1633036200063357005b346200035f575f3660031901126200035f57602060405160028152f35b346200035f575f3660031901126200035f575f8051602062004570833981519152546040516001600160a01b039091168152602090f35b346200035f575f3660031901126200035f576020620003a762001e39565b346200035f5760203660031901126200035f576020620003a760043562001e70565b346200035f575f3660031901126200035f57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801562000609576020915f9162000f89575b506040519015158152f35b62000fa49150823d841162000cbd5762000cac818362000a9a565b5f62000f7e565b346200035f5760203660031901126200035f5760043562000fcc81620003af565b62000fd6620025ce565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200035f5760803660031901126200035f5762001074620010576004356200104581620003af565b60643590604435906024359062001f65565b604080519384526020840192909252908201529081906060820190565b0390f35b346200035f575f3660031901126200035f576040518061019e805480845260208094019081925f527fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b905f5b8682821062001127578686620010dd8288038362000a9a565b60405192839281840190828552518091526040840192915f5b8281106200110657505050500390f35b83516001600160a01b031685528695509381019392810192600101620010f6565b835485529093019260019283019201620010c4565b346200035f575f3660031901126200035f57602061ffff60655460a01c16604051908152f35b346200035f576003196040368201126200035f5760049081356001600160401b038082116200035f5760a08285019383360301126200035f576024359081116200035f57620011b59036908501620007e5565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200035f5760405163837d444160e01b8152905f9082908183816200120b8c828f0162002091565b03925af18015620006095762001350575b506200122762003014565b62001231620023c5565b908116331415918262001319575b5050905062001308576044019160c46200125a84846200211b565b90500480158015620012ed575b620012dd57620012816200127a62001d3b565b9162002175565b11620012ce575060c46200129683836200211b565b9050145f14620012b7576200002491620012b0916200211b565b9062003edb565b6200002491620012c7916200211b565b9062003d8e565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50620012fa84846200211b565b905060c48202141562001267565b604051634ca8886760e01b81528390fd5b6200134392506200133c62001347946200133388620030a7565b92369162000ae9565b916200318c565b1590565b805f806200123f565b806200061f620013609262000a32565b5f6200121c565b346200035f5760603660031901126200035f576004356024356200139060443582843362001f65565b9192620013be7f00000000000000000000000000000000000000000000000000000000000000008262001e5c565b42108015620015f6575b8015620015ed575b620015db577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb569362001425866200141f620014136099546001600160801b031690565b6001600160801b031690565b62002d34565b156200153957620014656200144a6200143e8662003268565b60995460801c6200218f565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91620014ac91906200149b60808262000a9a565b5190205f52609b60205260405f2090565b555f9360018311620014e8575b50505050620014c982336200329c565b604080519485526020850191909152830152339180606081015b0390a2005b6200152e92939450620014fc908862001e5c565b60408051336020820190815291810193909352606083018290526080958601835290949091906200149b908262000a9a565b555f808080620014b9565b6200154362003014565b6200158462001568620015568662003268565b609e546001600160801b03166200218f565b6001600160801b03166001600160801b0319609e541617609e55565b620015be620015a3620015978562003268565b609e5460801c6200218f565b6001600160801b03609e549181199060801b16911617609e55565b620015d5620015d084609f5462001e5c565b609f55565b62001465565b604051630e3d8e8d60e11b8152600490fd5b508215620013d0565b508115620013c8565b346200035f576040806003193601126200035f57602435906004356200162583620003af565b6200162f62003014565b8015620017f1576001600160a01b038316908115620017e057620016538162001cc4565b908115620017cf57620016668262003b2b565b620016718362003268565b60985460801c9062001683916200218f565b620016a3906001600160801b036098549181199060801b16911617609855565b620016af8233620041c6565b609e54958660801c8281609f5490620016c89162001e5c565b98620016d48762003268565b620016e8916001600160801b031662003716565b62001709906001600160801b03166001600160801b0319609e541617609e55565b620017149162001e5c565b6200171f9062003268565b6200173f906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906200177260808262000a9a565b51902062001788905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200035f575f3660031901126200035f5761019d546020906001600160a01b03908116806200183c5750805f5416905b60405191168152f35b9062001833565b346200035f57620014e37f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf620018793662000815565b929062001885620025ce565b604051918291602083523395602084019162002071565b5f5b838110620018ae5750505f910152565b81810151838201526020016200189e565b90602091620018da815180928185528580860191016200189c565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106200191c5750505050505090565b90919293949584806200193c600193603f198682030187528a51620018bf565b98019301930191949392906200190b565b346200035f5760203660031901126200035f576001600160401b036004358181116200035f57366023820112156200035f5780600401359182116200035f573660248360051b830101116200035f5762001074916024620019af920162002304565b60405191829182620018e6565b906020620019cf928181520190620018bf565b90565b346200035f575f3660031901126200035f5762001074604051620019f68162000a62565b60058152640352e302e360dc1b6020820152604051918291602083526020830190620018bf565b346200035f575f3660031901126200035f5760206200076f620023c5565b801515036200035f57565b346200035f5760403660031901126200035f576200002460043562001a6b81620003af565b6024359062001a7a8262001a3b565b620023fc565b346200035f575f3660031901126200035f5760206200076f62002496565b346200035f5760203660031901126200035f576020620003a76004356200333b565b346200035f5760203660031901126200035f576200002460043562001ae581620003af565b62001aef620025ce565b620033d8565b346200035f575f3660031901126200035f5760206001600160801b0360995416604051908152f35b346200035f5760203660031901126200035f576200002460043562001b4281620003af565b62001b4c620025ce565b6200341f565b346200035f575f3660031901126200035f5760206001600160801b03609e5416604051908152f35b346200035f5760203660031901126200035f5760043562001b9b81620003af565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346200035f5760203660031901126200035f5760043562001bda81620003af565b61019c805490916001600160a01b03908116908216811462000444577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d92816020936200042e620025ce565b346200035f5760203660031901126200035f5760043562001c4781620003af565b60018060a01b03165f52610207602052602060ff60405f2054166040519015158152f35b346200035f575f3660031901126200035f575f546040516001600160a01b039091168152602090f35b60403660031901126200035f576020620003a760043562001cb581620003af565b60243590620006dc82620003af565b6098546001600160801b038116908162001cdd57505090565b91620019cf9260801c906200254a565b6040513d5f823e3d90fd5b908160209103126200035f5751620019cf81620003af565b62001d1f62001d2791620026e7565b91906200289f565b62001d2e57565b62001d3862002a73565b50565b476099546001600160801b0362001d5481831662001cc4565b90609e5416019060801c01908181115f1462001d6e570390565b50505f90565b610137546001600160a01b0316801562001d8b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b906020828203126200035f5781356001600160401b03928382116200035f5701916060838303126200035f576040519262001deb8462000a46565b80358452602081013561ffff811681036200035f57602085015260408101359182116200035f57019080601f830112156200035f5781602062001e319335910162000ae9565b604082015290565b609d5480620019cf57505f1990565b634e487b7160e01b5f52601160045260245ffd5b9190820180921162001e6a57565b62001e48565b6001600160801b036099541662001e8662003ae7565b90810180911162001e6a57811062001ec05762001eb0609f5462001ea962002d4e565b9062001e5c565b111562001ebb575f90565b5f1990565b609a90609a549182915f905b84821062001ee85750505081101562001ee25790565b505f1990565b909193808316906001818518811c830180931162001e6a575f8790525f80516020620045508339815191528301546001600160a01b031684101562001f33575050935b919062001ecc565b90959101925062001f2b565b908160209103126200035f5751620019cf8162001a3b565b9190820391821162001e6a57565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919062001fa581608081015b03601f19810183528262000a9a565b5190205f52609b60205260405f20549182156200201a576001600160801b03609954169062001fd362003ae7565b91820180921162001e6a57839183101562002005579162001ff49262002e5d565b90915b82810390811162001e6a5792565b5090620020129162002dc3565b909162001ff7565b5050505f905f905f90565b9035601e19823603018112156200035f5701602081359101916001600160401b0382116200035f5781360383136200035f57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620019cf92602081528235602082015260208301356040820152620020d2620020c1604085018562002025565b84606085015260c084019162002071565b906200210b620020ff620020ea606087018762002025565b601f1985870381016080870152959162002071565b94608081019062002025565b9390928286030191015262002071565b903590601e19813603018212156200035f57018035906001600160401b0382116200035f576020019181360383136200035f57565b634e487b7160e01b5f52601260045260245ffd5b81156200216f570490565b62002150565b906801bc16d674ec800000918083029283040362001e6a57565b6001600160801b03918216908216039190821162001e6a57565b6001600160401b0381116200062d5760051b60200190565b90620021cd82620021a9565b620021dc604051918262000a9a565b8281528092620021ef601f1991620021a9565b01905f5b8281106200220057505050565b806060602080938501015201620021f3565b634e487b7160e01b5f52603260045260245ffd5b908210156200224057620008439160051b8101906200211b565b62002212565b908092918237015f815290565b3d1562002282573d90620022678262000acd565b9162002277604051938462000a9a565b82523d5f602084013e565b606090565b6020818303126200035f578051906001600160401b0382116200035f570181601f820112156200035f578051620022be8162000acd565b92620022ce604051948562000a9a565b818452602082840101116200035f57620019cf91602080850191016200189c565b8051821015620022405760209160051b010190565b9190916200231283620021c1565b925f5b8181106200232257505050565b5f806200233183858762002226565b604093916200234585518093819362002246565b0390305af4906200235562002253565b9115620023825750906001916200236d8288620022ef565b526200237a8187620022ef565b500162002315565b9060448151106200035f57620023c1620023ab6004928381015160248091830101910162002287565b925162461bcd60e51b81529283928301620019bc565b0390fd5b60d2546001600160a01b031680620019cf57507f000000000000000000000000000000000000000000000000000000000000000090565b610206546001600160a01b0391908216330362000633576001600160a01b0381165f90815261020760205260409020549215159260ff161515831462002491576001600160a01b0381165f9081526102076020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b61019c546001600160a01b0390811680620024b257505f541690565b905090565b620024c23362003484565b62001d383433620034a6565b90808202905f19818409908280831092039180830392146200253f5761271090828211156200252d577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514620025bf57848311156200252d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620019cf925062002164565b5f546001600160a01b031633036200063357565b908160609103126200035f5780519160406020830151920151620019cf8162001a3b565b81835290916001600160fb1b0383116200035f5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200035f57604083015260408101356200265d81620003af565b6001600160a01b031660608381019190915281013536829003601e19018112156200035f5701602081359101906001600160401b0381116200035f578060051b360382136200035f5760a083608080620019cf960152019162002606565b908160209103126200035f575190565b9190915f838201938412911290801582169115161762001e6a57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906200271490600483016200262b565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831562000609575f915f905f9562002852575b508415620027f757816200276362001d74565b16917f0000000000000000000000000000000000000000000000000000000000000000168214620027ef57509060205f92600460405180958193634641257d60e01b83525af19081156200060957620027c5925f92620027c9575b50620026cb565b9190565b620027e791925060203d60201162000db35762000da3818362000a9a565b905f620027be565b9081620027fd575b50509190565b803b156200035f57604051636ee3193160e11b815260048101929092525f908290602490829084905af1801562000609576200283b575b80620027f7565b806200061f6200284b9262000a32565b5f62002834565b919450506200287d915060603d60601162002886575b62002874818362000a9a565b810190620025e2565b93905f62002750565b503d62002868565b600160ff1b811462001e6a575f0390565b801562001d3857620028b76200141360985460801c90565b5f8212620029b75781620028cb9162001e5c565b90620028f6620028db8362003268565b6001600160801b036098549181199060801b16911617609855565b6200290d6065549161ffff8360a01c1690620024ce565b80156200249157807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936200294e620014136098546001600160801b031690565b806200299d5750506200299890925b6001600160a01b03169162002973848462003732565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6200299892620029b0920390846200254a565b926200295d565b90620029c3906200288e565b620029da62001413609e546001600160801b031690565b8062002a06575b5080620029ec575050565b62002a00620028db9162000acb9362001f57565b62003268565b9062002a697f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9162002a596200156862002a4d62002a45888862001e5c565b87856200254a565b80809403960362003268565b6040519081529081906020820190565b0390a15f620029e1565b609954906001600160801b03821691821562002bb45760801c62002aae62002a9c824762001f57565b62002aa78562001cc4565b9062003782565b90811562002bad5762002ac1826200333b565b93841562002ba5578262002b1a6200144a62002a0062000acb96620028db9662002b1462002af862002a008d62002b999a62001f57565b6001600160801b03166001600160801b03196099541617609955565b62001e5c565b62002b268187620037ec565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162002a0062002b7d62002b6b8862003268565b6098546001600160801b03166200218f565b6001600160801b03166001600160801b03196098541617609855565b60985460801c6200218f565b505f93505050565b505f925050565b505f9150565b62002bc4620038cf565b604083015162002bd3620038cf565b6001600160a01b038216801562002cb6576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528062002c2f33946020830190620018bf565b0390a260208301519262002c42620038cf565b61271061ffff85161162002ca45762002c9a9362002c6462002c8a936200341f565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555162003911565b62002c9462003945565b62003978565b62000acb620039aa565b604051638a81d3b360e01b8152600490fd5b60405163d92e233d60e01b8152600490fd5b62000acb9062001aef620038cf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562002d17575b505062000e4757565b5f80516020620045708339815191525416141590505f8062002d0e565b9062002d3f62003ae7565b91820180921162001e6a571090565b476099548060801c820391821162001e6a578162002d766001600160801b0380931662001cc4565b908162002da2575b5050811562001d6e57620019cf9162002d9c91609e54169062003782565b62003b2b565b919250908181111562002dba57035b905f8062002d7e565b50505f62002db1565b62002dcd62002d4e565b91609f5492830180931162001e6a578083111562002e1e5762002df292039062003782565b90609e548060801c80155f1462002e095750508190565b6001600160801b03620019cf9216846200254a565b5050505f905f90565b90604051604081018181106001600160401b038211176200062d5760405291546001600160a01b038116835260a01c6020830152565b609a545f9485949390918084108015906200300b575b62002ffe578362002fc7575f5b609a5f526001600160a01b031662002ea85f8051602062004550833981519152860162002e27565b805190979062002ec1906001600160a01b031662000476565b9862002ee862002edc6020809b01516001600160601b031690565b6001600160601b031690565b94838110801562002fbc575b62002faa5791600193979a9562002f1762002f24939488035b838c039062003782565b809201988703916200254a565b0197019380861180159062002f9f575b62002f9457609a5f52829062002f5a5f8051602062004550833981519152870162002e27565b805190890151969992966001600160a01b03909116946001939262002f249290916001600160601b039091169062002f1790880362002f0d565b945050509250509190565b508185101562002f34565b60405163e8722f8f60e01b8152600490fd5b50808b111562002ef4565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031662002e80565b505093505050505f905f90565b50841562002e73565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562000609575f9162003083575b506200307157565b60405163e775715160e01b8152600490fd5b620030a0915060203d60201162000cbd5762000cac818362000a9a565b5f62003069565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200315c5760d354905b620030f2620030ea60408301836200211b565b369162000ae9565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526200313f8162000a7e565b5190206040519161190160f01b8352600283015260228201522090565b6200316662003b67565b90620030d7565b600411156200317857565b634e487b7160e01b5f52602160045260245ffd5b62003198838362003c37565b50620031a7819592956200316d565b15938462003251575b508315620031bf575b50505090565b5f929350908291604051620031fa8162001f966020820194630b135d3f60e11b998a87526024840152604060448401526064830190620018bf565b51915afa906200320962002253565b8262003242575b8262003222575b50505f8080620031b9565b6200323991925060208082518301019101620026bb565b145f8062003217565b91506020825110159162003210565b6001600160a01b0383811691161493505f620031b0565b6001600160801b03908181116200327d571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541462003329576002835581471062003311575f918291829182916001600160a01b03165af1620032f262002253565b5015620032ff5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b038216811580156200336e575b156200335f5750905090565b620019cf9260801c916200254a565b50801562003353565b6098546001600160801b0381169082158015620033cf575b156200339a57505090565b60801c90620033ab8282856200254a565b9282156200216f5709620033bc5790565b6001810180911115620019cf5762001e48565b5081156200338f565b61020680546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b6200342962003014565b6001600160a01b031680156200347257606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610207602052604090205460ff166200063357565b9190620034b262003014565b6001600160a01b03831690811562002cb65780156200356c5780620034dd6200141360985460801c90565b0193620034e962001e39565b85116200355a57620028db94620035189162003512620035098562003377565b97889362003268565b62003732565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926200358c62003014565b6001600160a01b03821691821562002cb65781156200356c5781620035b76200141360985460801c90565b01620035c262001e39565b81116200355a57620028db956200361162003555927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003512620036088862003377565b9a8b9362003268565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f5261019f8060205260405f2054155f1462001d6e5761019e8054600160401b8110156200062d5760018101808355811015620022405783907fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b015554915f5260205260405f2055600190565b805f526101a18060205260405f2054155f1462001d6e576101a08054600160401b8110156200062d5760018101808355811015620022405783907f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c4015554915f5260205260405f2055600190565b9190916001600160801b038080941691160191821162001e6a57565b6200373d8262003268565b60985490620037576001600160801b039182841662003716565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015620024b2575090565b609a5490600160401b8210156200062d576001820180609a558210156200224057609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206200455083398151915290910155565b91909180158015620038c6575b620038b4576200380862003ae7565b90810180911162001e6a576001600160a01b0380821162003894576001600160601b039081851162003874579062000acb93946200385d6200386e936200384e62000abc565b95166001600160a01b03168552565b166001600160601b03166020830152565b62003790565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b508215620037f9565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615620038ff57565b604051631afcd79f60e31b8152600490fd5b6200391b620038cf565b80156200393357600181016200392e5750565b609d55565b6040516331278a8760e01b8152600490fd5b6200394f620038cf565b6801bc16d674ec8000006200396362001e39565b1062003933576200397362003b67565b60d355565b62003982620038cf565b6001600160a01b031680620039945750565b61013780546001600160a01b0319169091179055565b620039b4620038cf565b620039be620038cf565b620039c8620038cf565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341062003a045762001d383430620034a6565b60405163ea2559bb60e01b8152600490fd5b908160209103126200035f575160ff811681036200035f5790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948162003ac1575b5062003a8357604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f8051602062004570833981519152840362003aa85762000acb92935062003fd3565b604051632a87526960e21b815260048101859052602490fd5b62003adf91955060203d60201162000db35762000da3818362000a9a565b935f62003a5c565b609a548062003af557505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031662000476565b609e54908160801c8115801562003b5e575b1562003b495750905090565b6001600160801b03620019cf9316916200254a565b50801562003b3d565b6e5661756c7456616c696461746f727360881b602060405162003b8a8162000a62565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176200062d5760405251902090565b815191906041830362003c6a5762003c639250602082015190606060408401519301515f1a906200407b565b9192909190565b50505f9160029190565b906030116200035f5790603090565b909291928360b0116200035f5783116200035f5760b0019160af190190565b906090116200035f5760300190606090565b9060c4116200035f5760900190603490565b909392938483116200035f5784116200035f578101920390565b35906020811062003cef575090565b5f199060200360031b1b1690565b95949362003d2f62003d3e9362003d206060969460808b5260808b019062002059565b9089820360208b0152620018bf565b91878303604089015262002071565b930152565b9695949062003d3e9362003d2062003d2f926060979560808c5260808c019162002071565b906020620019cf92818152019062002059565b916020620019cf93818152019162002071565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062003dd7575050505050505050565b8262003de891018092878762003cc6565b9062003df5828262003c74565b9162003e0e62003e0785808462003c83565b9062004100565b9062003e3362003e2c62003e23878462003ca2565b97909362003cb4565b9062003ce0565b948c3b156200035f578c5f926801bc16d674ec80000060409562003e6f87519a8b96879586946304512a2360e31b86528d8d6004880162003d43565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19462003eb49262003ec4575b50519283928362003d7b565b0390a16001819301929062003dc5565b806200061f62003ed49262000a32565b5f62003ea8565b816030116200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169162003f2062003e0782808562003c83565b62003f2c828462003ca2565b94909260b0116200035f57803b156200035f5762003f75946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162003cfd565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192620029989262003fbc575b506040519182918262003d68565b806200061f62003fcc9262000a32565b5f62003fae565b90813b156200405a575f805160206200457083398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156200403e5762001d389162004216565b5050346200404857565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411620040f5579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1562000609575f516001600160a01b03811615620040eb57905f905f90565b505f906001905f90565b5050505f9160039190565b60148203620041b4576bffffffffffffffffffffffff1991903582811691601481106200419e575b5050905060601c6200414a62001343825f5261019f60205260405f2054151590565b6200418c5760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c830152620019cf908290810162001f96565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004128565b604051639be7315960e01b8152600490fd5b60018060a01b03165f52609c60205260405f2090815481810390811162001e6a57620041f3925562003268565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f80620019cf93602081519101845af46200423062002253565b9190620042485750805115620032ff57805190602001fd5b815115806200427d575b6200425b575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200425256fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003344da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220e2d517320a9fadaaddd17a211bfed4486c2c06086c6439e680db393c4e762f5a64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthRestakeErc20Vault.json b/test/shared/artifacts/EthRestakeErc20Vault.json deleted file mode 100644 index 16c49df0..00000000 --- a/test/shared/artifacts/EthRestakeErc20Vault.json +++ /dev/null @@ -1,1672 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthRestakeErc20Vault", - "sourceName": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "eigenPodOwnerImplementation", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101c0346200016d57601f620052e938819003918201601f19168301916001600160401b03831184841017620001715780849260e0946040528339810103126200016d576200004e8162000185565b906200005d6020820162000185565b906200006c6040820162000185565b6200007a6060830162000185565b90620000896080840162000185565b9360c06200009a60a0860162000185565b9401519560805260a05260c0523060e052620000b56200019a565b610100934685526101209384526101404681526101609182526101809283526101a0938452620000e46200019a565b604051946150af96876200023a883960805187818161135a0152818161161301528181612d0f015261363f015260a0518761102d015260c05187818161432a0152614480015260e0518781816111d901526132f10152518661247401525185612a5e015251846136bd015251836117ec01525182818161244f0152612d5c015251816107e90152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200016d57565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1662000227576001600160401b036002600160401b031982821601620001e857505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101562000026575b36156200001a575f80fd5b6200002462002aa2565b005b5f3560e01c806301e1d11414620003d257806306fdde0314620003cc57806307a2d13a14620003c6578063095ea7b314620003c0578063096ae80d14620003ba5780630b10b20114620003b457806318160ddd146200037e57806318f7295014620003ae5780631a7ff55314620003a857806323b872dd14620003a25780632cdf7401146200039c578063313ce56714620003965780633229fa95146200039057806333194c0a146200038a5780633644e51514620003845780633a98ef39146200037e578063439fab9114620003785780634690484014620003725780634f1ef286146200036c57806352d1902d146200036657806353156f28146200036057806354fd4d50146200035a5780635c60da1b14620003545780635cfc1a51146200034e57806360d60e6e146200034857806370a0823114620002b857806372b410a81462000342578063754c3888146200033c57806376b58b9014620003365780637b6341c614620003305780637ecebe00146200032a5780637fd6f15c146200032457806383d430d5146200031e5780638697d2c214620003185780638ceab9aa146200031257806395d89b41146200030c578063a045dd0c1462000306578063a49a1e7d1462000300578063a9059cbb14620002fa578063ac9650d814620002f4578063ad3cb1cc14620002ee578063b1f0e7c714620002e8578063c5aecb2214620002e2578063c6e6f59214620002dc578063d505accf14620002d6578063d83ad00c14620002d0578063dd62ed3e14620002ca578063e74b981b14620002c4578063ee3bd5df14620002be578063f04da65b14620002b8578063f132f5d314620002b2578063f851a44014620002ac5763f9609f08036200000f5762002324565b620022fa565b6200228d565b620012ee565b62002265565b62002230565b620021e8565b62002196565b62001f6e565b62001f40565b62001f22565b62001f04565b62001eb9565b62001e4a565b62001da8565b62001d4f565b62001d0d565b62001c5b565b62001a58565b620017bb565b620015b6565b62001590565b62001551565b6200148d565b62001435565b620013c3565b6200132d565b620012cc565b620012ae565b62001277565b6200125a565b62001232565b620011c5565b62000efd565b62000e4b565b62000c18565b6200096b565b62000b98565b62000b5c565b62000b2c565b62000b0f565b62000af1565b62000a40565b62000a07565b620009a2565b62000782565b620006ed565b62000645565b62000609565b6200052c565b620003e7565b5f910312620003e357565b5f80fd5b34620003e3575f366003190112620003e357602060cf5460801c604051908152f35b90600182811c9216801562000439575b60208310146200042557565b634e487b7160e01b5f52602260045260245ffd5b91607f169162000419565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200046c57604052565b62000444565b604081019081106001600160401b038211176200046c57604052565b608081019081106001600160401b038211176200046c57604052565b90601f801991011681019081106001600160401b038211176200046c57604052565b5f5b838110620004de5750505f910152565b8181015183820152602001620004ce565b906020916200050a81518092818552858086019101620004cc565b601f01601f1916010190565b90602062000529928181520190620004ef565b90565b34620003e3575f366003190112620003e3576040515f80546200054f8162000409565b80845290602090600190818116908115620005dc575060011462000592575b6200058e856200058181870382620004aa565b6040519182918262000516565b0390f35b5f80805293505f8051602062004ffa8339815191525b838510620005c85750505050810160200162000581826200058e6200056e565b8054868601840152938201938101620005a8565b8695506200058e969350602092506200058194915060ff191682840152151560051b82010192936200056e565b34620003e3576020366003190112620003e35760206200062b6004356200233e565b604051908152f35b6001600160a01b03811603620003e357565b34620003e3576040366003190112620003e357600435620006668162000633565b6001600160a01b03811690602435908215620006db57620006a38291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b34620003e3576020366003190112620003e3576004356200070e8162000633565b610206805490916001600160a01b03908116908216811462000770577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e892816020936200075a62002bc4565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b34620003e3575f366003190112620003e357620007ae620007a262002a80565b6001600160a01b031690565b330362000959576040516102c8808201908282106001600160401b038311176200046c5782916200081f9162004d3284396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff0801562000935576001600160a01b0390811690813b15620003e35760405163439fab9160e01b8152602060048201525f602482018190528160448183875af1801562000935576200093b575b506040516351d5709b60e11b815291602083600481845afa91821562000935577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f93620008f8575b50620008c790831662003be2565b50620008d38162003c50565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b620008c7919350620009259060203d6020116200092d575b6200091c8183620004aa565b81019062002372565b9290620008b9565b503d62000910565b62002367565b806200094b620009529262000458565b80620003d8565b5f6200086f565b604051634ca8886760e01b8152600490fd5b34620003e3575f366003190112620003e35760206001600160801b0360cf5416604051908152f35b90816080910312620003e35790565b6060366003190112620003e357600435620009bd8162000633565b602435620009cb8162000633565b604435906001600160401b038211620003e357602092620009ff620009f96200062b94369060040162000993565b6200238a565b349062003b26565b34620003e3576020366003190112620003e3576004356001600160401b038111620003e357620009f96200002491369060040162000993565b34620003e3576060366003190112620003e35760043562000a618162000633565b60243562000a6f8162000633565b6001600160a01b0382165f818152600260209081526040808320338452909152902090926044359291546001810162000abc575b5062000ab093506200306d565b60405160018152602090f35b83810390811162000aeb575f94855260026020908152604080872033885290915285205562000ab09362000aa3565b620023da565b34620003e3575f366003190112620003e35760206200062b620023fc565b34620003e3575f366003190112620003e357602060405160128152f35b34620003e3575f366003190112620003e357602062000b4a62002435565b6040516001600160a01b039091168152f35b34620003e3575f366003190112620003e35760206040517f778168b2049c66a50853dfa28c8d05dfb083907876871d6640cd612be7e580f28152f35b34620003e3575f366003190112620003e35760206200062b62002471565b9181601f84011215620003e3578235916001600160401b038311620003e35760208381860195010111620003e357565b6020600319820112620003e357600435906001600160401b038211620003e35762000c149160040162000bb6565b9091565b62000c233662000be6565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c16801562000e36575b62000e255768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020908185600481335afa94851562000935575f9562000e01575b508351636f4fa30f60e01b8152908282600481335afa91821562000935575f9262000ddd575b508301948284870312620003e35783356001600160401b0394858211620003e3570160a081880312620003e35762000cfd62000e75565b938135855262000d0f818301620024a9565b9085015285810135858111620003e3578762000d2d918301620024b9565b868501526060810135858111620003e3578762000d4c918301620024b9565b60608501526080810135948511620003e3577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29662000d9c9562000d919201620024b9565b608084015262003214565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff00000000000000001916905551600281528060208101620008f3565b62000df9919250833d85116200092d576200091c8183620004aa565b905f62000cc6565b62000e1d919550823d84116200092d576200091c8183620004aa565b935f62000ca0565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000c5a565b34620003e3575f366003190112620003e357609c546040516001600160a01b039091168152602090f35b6040519060a082018281106001600160401b038211176200046c57604052565b6040519062000ea48262000472565b565b6001600160401b0381116200046c57601f01601f191660200190565b92919262000ed08262000ea6565b9162000ee06040519384620004aa565b829481845281830111620003e3578281602093845f960137010152565b604080600319360112620003e357600490813562000f1b8162000633565b6024356001600160401b038111620003e35736602382011215620003e35762000f4e903690602481870135910162000ec2565b9162000f59620032e7565b80519262000f948462000f8560209363439fab9160e01b858401528460248401526044830190620004ef565b03601f198101865285620004aa565b62000f9e620032e7565b62000fa862002bc4565b6001600160a01b0383811680159291908790841562001194575b84156200110c575b84156200109e575b5050821562000ffe575b505062000fef5762000024838362003fbd565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821562000935575f926200106a575b5050155f8062000fdc565b6200108e9250803d1062001096575b620010858183620004aa565b810190620025d1565b5f806200105f565b503d62001079565b855163054fd4d560e41b81529294508391839182905afa908115620009355760039160ff915f91620010d8575b5016141591865f62000fd2565b620010fd9150843d861162001104575b620010f48183620004aa565b81019062003fa5565b5f620010cb565b503d620010e8565b935050835163198ca60560e11b815282818981875afa908115620009355788917f778168b2049c66a50853dfa28c8d05dfb083907876871d6640cd612be7e580f2915f9162001160575b5014159362000fca565b620011859150853d87116200118c575b6200117c8183620004aa565b81019062002cb0565b5f62001156565b503d62001170565b5f805160206200501a833981519152549094508490620011bd906001600160a01b0316620007a2565b149362000fc2565b34620003e3575f366003190112620003e3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620012205760206040515f805160206200501a8339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112620003e3576001600160a01b036200125062002435565b1633036200095957005b34620003e3575f366003190112620003e357602060405160028152f35b34620003e3575f366003190112620003e3575f805160206200501a833981519152546040516001600160a01b039091168152602090f35b34620003e3575f366003190112620003e35760206200062b620024d7565b34620003e3576020366003190112620003e35760206200062b600435620024f4565b34620003e3576020366003190112620003e3576004356200130f8162000633565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b34620003e3575f366003190112620003e357604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801562000935576020915f91620013a1575b506040519015158152f35b620013bc9150823d84116200109657620010858183620004aa565b5f62001396565b34620003e3576020366003190112620003e357600435620013e48162000633565b620013ee62002bc4565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b34620003e3576080366003190112620003e3576200058e620014706004356200145e8162000633565b606435906044359060243590620025e8565b604080519384526020840192909252908201529081906060820190565b34620003e3575f366003190112620003e35760405180610207805480845260208094019081925f527f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2905f5b868282106200153c578686620014f282880383620004aa565b60405192839281840190828552518091526040840192915f5b8281106200151b57505050500390f35b83516001600160a01b0316855286955093810193928101926001016200150b565b835485529093019260019283019201620014d9565b34620003e3576020366003190112620003e357600435620015728162000633565b60018060a01b03165f526003602052602060405f2054604051908152f35b34620003e3575f366003190112620003e357602061ffff609c5460a01c16604051908152f35b34620003e357600319604036820112620003e35760049081356001600160401b03808211620003e35760a0828501938336030112620003e357602435908111620003e35762001609903690850162000bb6565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b15620003e35760405163837d444160e01b8152905f9082908183816200165f8c828f0162002714565b03925af180156200093557620017a4575b506200167b62003624565b6200168562002a48565b90811633141591826200176d575b505090506200175c576044019160c4620016ae84846200279e565b9050048015801562001741575b6200173157620016d5620016ce620023fc565b91620027f8565b1162001722575060c4620016ea83836200279e565b9050145f146200170b57620000249162001704916200279e565b9062004475565b62000024916200171b916200279e565b9062004328565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506200174e84846200279e565b905060c482021415620016bb565b604051634ca8886760e01b81528390fd5b620017979250620017906200179b946200178788620036b7565b92369162000ec2565b916200379d565b1590565b805f8062001693565b806200094b620017b49262000458565b5f62001670565b34620003e3576060366003190112620003e357600435602435620017e4604435828433620025e8565b9192620018127f000000000000000000000000000000000000000000000000000000000000000082620024e6565b4210801562001a4f575b801562001a46575b62001a34577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936200187986620018736200186760d0546001600160801b031690565b6001600160801b031690565b62003344565b156200199257620018b96200189e620018928662003879565b60d05460801c62002812565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91620019009190620018ef608082620004aa565b5190205f5260d260205260405f2090565b555f93600183116200193c575b505050506200191d8233620038ad565b604080519485526020850191909152830152339180606081015b0390a2005b6200198792939450620019509088620024e6565b60408051336020820190815291810193909352606083018290529094909190620018ef9082608081015b03908101835282620004aa565b555f8080806200190d565b6200199c62003624565b620019dd620019c1620019af8662003879565b60d5546001600160801b031662002812565b6001600160801b03166001600160801b031960d554161760d555565b62001a17620019fc620019f08562003879565b60d55460801c62002812565b6001600160801b0360d5549181199060801b1691161760d555565b62001a2e62001a298460d654620024e6565b60d655565b620018b9565b604051630e3d8e8d60e11b8152600490fd5b50821562001824565b5081156200181c565b34620003e357604080600319360112620003e3576024359060043562001a7e8362000633565b62001a8862003624565b801562001c4a576001600160a01b03831690811562001c395762001aac816200233e565b90811562001c285762001abf82620040c5565b62001aca8362003879565b60cf5460801c9062001adc9162002812565b62001afc906001600160801b0360cf549181199060801b1691161760cf55565b62001b08823362004c6c565b60d554958660801c828160d6549062001b2191620024e6565b9862001b2d8762003879565b62001b41916001600160801b03166200456d565b62001b62906001600160801b03166001600160801b031960d554161760d555565b62001b6d91620024e6565b62001b789062003879565b62001b98906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529062001bcb608082620004aa565b51902062001be1905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b34620003e3575f366003190112620003e3576040515f6001805462001c808162000409565b8085529160209160018116908115620005dc575060011462001caf576200058e856200058181870382620004aa565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851062001cf95750505050810160200162000581826200058e6200056e565b805486860184015293820193810162001cd9565b34620003e3575f366003190112620003e357610206546020906001600160a01b039081168062001d4857508060375416905b60405191168152f35b9062001d3f565b34620003e357620019377f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf62001d853662000be6565b929062001d9162002bc4565b6040519182916020835233956020840191620026f4565b34620003e3576040366003190112620003e35762001dd860043562001dcd8162000633565b60243590336200306d565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831062001e195750505050505090565b909192939495848062001e39600193603f198682030187528a51620004ef565b980193019301919493929062001e08565b34620003e3576020366003190112620003e3576001600160401b03600435818111620003e35736602382011215620003e3578060040135918211620003e3573660248360051b83010111620003e3576200058e91602462001eac920162002987565b6040519182918262001de3565b34620003e3575f366003190112620003e3576200058e60405162001edd8162000472565b60058152640352e302e360dc1b6020820152604051918291602083526020830190620004ef565b34620003e3575f366003190112620003e357602062000b4a62002a48565b34620003e3575f366003190112620003e357602062000b4a62002a80565b34620003e3576020366003190112620003e35760206200062b6004356200394c565b60ff811603620003e357565b34620003e35760e0366003190112620003e35760043562001f8f8162000633565b60243562001f9d8162000633565b60443590606435926084359062001fb48262001f62565b6001600160a01b03838116959092908615620006db5742811062002184576020915f916200197a620020b089878a6200207162001ff062002471565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039162002087601f1993848101835282620004aa565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa1562000935575f5192828416801590811562002176575b506200216457620021558591620021407f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b556040519384521691602090a3005b6040516323389ba560e21b8152600490fd5b905083831614155f620020f8565b604051631ab7da6b60e01b8152600490fd5b34620003e3575f366003190112620003e35760206001600160801b0360d05416604051908152f35b6040906003190112620003e357600435620021d98162000633565b90602435620005298162000633565b34620003e357602062002227620021ff36620021be565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b34620003e3576020366003190112620003e35762000024600435620022558162000633565b6200225f62002bc4565b620039e9565b34620003e3575f366003190112620003e35760206001600160801b0360d55416604051908152f35b34620003e3576020366003190112620003e357600435620022ae8162000633565b610205805490916001600160a01b03908116908216811462000770577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d92816020936200075a62002bc4565b34620003e3575f366003190112620003e3576037546040516001600160a01b039091168152602090f35b60206200062b6200233536620021be565b90349062003b26565b60cf546001600160801b03811690816200235757505090565b91620005299260801c9062002b40565b6040513d5f823e3d90fd5b90816020910312620003e35751620005298162000633565b62002399620023a19162002cdc565b919062002e94565b620023a857565b620023b2620045ff565b80620023bc575b50565b5f906040519081525f805160206200503a83398151915260203092a3565b634e487b7160e01b5f52601160045260245ffd5b9190820391821162000aeb57565b4760d0546001600160801b03620024158183166200233e565b9060d55416019060801c01908181115f146200242f570390565b50505f90565b61016e546001600160a01b031680156200244c5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036200249f5760045490565b62000529620030df565b359061ffff82168203620003e357565b9080601f83011215620003e357816020620005299335910162000ec2565b60d454806200052957505f1990565b9190820180921162000aeb57565b6001600160801b0360d054166200250a62004073565b90810180911162000aeb57811062002544576200253460d6546200252d6200335e565b90620024e6565b11156200253f575f90565b5f1990565b60d19060d1549182915f905b8482106200256c57505050811015620025665790565b505f1990565b909193808316906001818518811c830180931162000aeb575f8790525f805160206200505a8339815191528301546001600160a01b0316841015620025b7575050935b919062002550565b909591019250620025af565b51908115158203620003e357565b90816020910312620003e3576200052990620025c3565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200262881608081015b03601f198101835282620004aa565b5190205f5260d260205260405f20549182156200269d576001600160801b0360d05416906200265662004073565b91820180921162000aeb57839183101562002688579162002677926200346d565b90915b82810390811162000aeb5792565b50906200269591620033d3565b90916200267a565b5050505f905f905f90565b9035601e1982360301811215620003e35701602081359101916001600160401b038211620003e3578136038313620003e357565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620005299260208152823560208201526020830135604082015262002755620027446040850185620026a8565b84606085015260c0840191620026f4565b906200278e620027826200276d6060870187620026a8565b601f19858703810160808701529591620026f4565b946080810190620026a8565b93909282860301910152620026f4565b903590601e1981360301821215620003e357018035906001600160401b038211620003e357602001918136038313620003e357565b634e487b7160e01b5f52601260045260245ffd5b8115620027f2570490565b620027d3565b906801bc16d674ec800000918083029283040362000aeb57565b6001600160801b03918216908216039190821162000aeb57565b6001600160401b0381116200046c5760051b60200190565b9062002850826200282c565b6200285f6040519182620004aa565b828152809262002872601f19916200282c565b01905f5b8281106200288357505050565b80606060208093850101520162002876565b634e487b7160e01b5f52603260045260245ffd5b90821015620028c35762000c149160051b8101906200279e565b62002895565b908092918237015f815290565b3d1562002905573d90620028ea8262000ea6565b91620028fa6040519384620004aa565b82523d5f602084013e565b606090565b602081830312620003e3578051906001600160401b038211620003e3570181601f82011215620003e3578051620029418162000ea6565b92620029516040519485620004aa565b81845260208284010111620003e357620005299160208085019101620004cc565b8051821015620028c35760209160051b010190565b919091620029958362002844565b925f5b818110620029a557505050565b5f80620029b4838587620028a9565b60409391620029c8855180938193620028c9565b0390305af490620029d8620028d6565b911562002a05575090600191620029f0828862002972565b52620029fd818762002972565b500162002998565b906044815110620003e35762002a4462002a2e600492838101516024809183010191016200290a565b925162461bcd60e51b8152928392830162000516565b0390fd5b610109546001600160a01b0316806200052957507f000000000000000000000000000000000000000000000000000000000000000090565b610205546001600160a01b039081168062002a9d57506037541690565b905090565b335f5261020a60205260405f20541562002ab857565b620023b9343362003a4e565b90808202905f198184099082808310920391808303921462002b3557612710908282111562002b23577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f198482099383808610950394808603951462002bb5578483111562002b2357829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620005299250620027e7565b6037546001600160a01b031633036200095957565b90816060910312620003e35780519162000529604060208401519301620025c3565b81835290916001600160fb1b038311620003e35760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103620003e3576040830152604081013562002c528162000633565b6001600160a01b031660608381019190915281013536829003601e1901811215620003e35701602081359101906001600160401b038111620003e3578060051b36038213620003e35760a08360808062000529960152019162002bfb565b90816020910312620003e3575190565b9190915f838201938412911290801582169115161762000aeb57565b6040516325f56f1160e01b81526001600160a01b0392916060908290819062002d09906004830162002c20565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831562000935575f915f905f9562002e47575b50841562002dec578162002d5862002435565b16917f000000000000000000000000000000000000000000000000000000000000000016821462002de457509060205f92600460405180958193634641257d60e01b83525af1908115620009355762002dba925f9262002dbe575b5062002cc0565b9190565b62002ddc91925060203d6020116200118c576200117c8183620004aa565b905f62002db3565b908162002df2575b50509190565b803b15620003e357604051636ee3193160e11b815260048101929092525f908290602490829084905af18015620009355762002e30575b8062002dec565b806200094b62002e409262000458565b5f62002e29565b9194505062002e72915060603d60601162002e7b575b62002e698183620004aa565b81019062002bd9565b93905f62002d45565b503d62002e5d565b600160ff1b811462000aeb575f0390565b8015620023b95762002eac6200186760cf5460801c90565b5f821262002fb1578162002ec091620024e6565b9062002eeb62002ed08362003879565b6001600160801b0360cf549181199060801b1691161760cf55565b62002f02609c549161ffff8360a01c169062002ac4565b801562002fac57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362002f436200186760cf546001600160801b031690565b8062002f9257505062002f8d90925b6001600160a01b03169162002f68848462004589565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b62002f8d9262002fa59203908462002b40565b9262002f52565b505050565b9062002fbd9062002e83565b62002fd46200186760d5546001600160801b031690565b8062003000575b508062002fe6575050565b62002ffa62002ed09162000ea493620023ee565b62003879565b90620030637f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9162003053620019c1620030476200303f8888620024e6565b878562002b40565b80809403960362003879565b6040519081529081906020820190565b0390a15f62002fdb565b6001600160a01b03908116919082158015620030d4575b620006db57825f5260d360205260405f209081549285840393841162000aeb575f805160206200503a83398151915293602093551693845f5260d3825260405f20818154019055604051908152a3565b508082161562003084565b6040515f905f5490620030f28262000409565b9283825260209384830193600190866001821691825f14620031f2575050600114620031aa575b5050918162003133620031a49362002619950382620004aa565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f8051602062004ffa8339815191525b828410620031dc57505050820101816200313362003119565b80548685018601528794909301928101620031c3565b60ff1916875292151560051b8501909201925083915062003133905062003119565b91906200322062003cbe565b6080820151906200323062003cbe565b6001600160a01b0384168015620006db57620032dd94620032cc93620032b0926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806200329d33946020830190620004ef565b0390a2602085015161ffff169062003d00565b620032bc835162003d56565b620032c662003d8a565b62003dbe565b606060408201519101519062003df0565b62000ea462003f39565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562003327575b50506200122057565b5f805160206200501a8339815191525416141590505f806200331e565b906200334f62004073565b91820180921162000aeb571090565b4760d0548060801c820391821162000aeb5781620033866001600160801b038093166200233e565b9081620033b2575b505081156200242f576200052991620033ac9160d5541690620040b7565b620040c5565b9192509081811115620033ca57035b905f806200338e565b50505f620033c1565b620033dd6200335e565b9160d65492830180931162000aeb57808311156200342e5762003402920390620040b7565b9060d5548060801c80155f14620034195750508190565b6001600160801b036200052992168462002b40565b5050505f905f90565b90604051604081018181106001600160401b038211176200046c5760405291546001600160a01b038116835260a01c6020830152565b60d1545f9485949390918084108015906200361b575b6200360e5783620035d7575f5b60d15f526001600160a01b0316620034b85f805160206200505a833981519152860162003437565b8051909790620034d1906001600160a01b0316620007a2565b98620034f8620034ec6020809b01516001600160601b031690565b6001600160601b031690565b948381108015620035cc575b620035ba5791600193979a956200352762003534939488035b838c0390620040b7565b8092019887039162002b40565b01970193808611801590620035af575b620035a45760d15f5282906200356a5f805160206200505a833981519152870162003437565b805190890151969992966001600160a01b039091169460019392620035349290916001600160601b0390911690620035279088036200351d565b945050509250509190565b508185101562003544565b60405163e8722f8f60e01b8152600490fd5b50808b111562003504565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b031662003490565b505093505050505f905f90565b50841562003483565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562000935575f9162003693575b506200368157565b60405163e775715160e01b8152600490fd5b620036b0915060203d6020116200109657620010858183620004aa565b5f62003679565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200376d5761010a54905b62003703620036fb60408301836200279e565b369162000ec2565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815262003750816200048e565b5190206040519161190160f01b8352600283015260228201522090565b6200377762004101565b90620036e8565b600411156200378957565b634e487b7160e01b5f52602160045260245ffd5b620037a98383620041d1565b50620037b8819592956200377e565b15938462003862575b508315620037d0575b50505090565b5f9293509082916040516200380b81620026196020820194630b135d3f60e11b998a87526024840152604060448401526064830190620004ef565b51915afa906200381a620028d6565b8262003853575b8262003833575b50505f8080620037ca565b6200384a9192506020808251830101910162002cb0565b145f8062003828565b91506020825110159162003821565b6001600160a01b0383811691161493505f620037c1565b6001600160801b03908181116200388e571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146200393a576002835581471062003922575f918291829182916001600160a01b03165af162003903620028d6565b5015620039105760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b038216811580156200397f575b15620039705750905090565b620005299260801c9162002b40565b50801562003964565b60cf546001600160801b0381169082158015620039e0575b15620039ab57505090565b60801c90620039bc82828562002b40565b928215620027f25709620039cd5790565b60018101809111156200052957620023da565b508115620039a0565b620039f362003624565b6001600160a01b0316801562003a3c57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b919062003a5a62003624565b6001600160a01b038316908115620006db57801562003b14578062003a856200186760cf5460801c90565b019362003a91620024d7565b851162003b025762002ed09462003ac09162003aba62003ab18562003988565b97889362003879565b62004589565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b9092919262003b3462003624565b6001600160a01b038216918215620006db57811562003b14578162003b5f6200186760cf5460801c90565b0162003b6a620024d7565b811162003b025762002ed09562003bb962003afd927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003aba62003bb08862003988565b9a8b9362003879565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f526102088060205260405f2054155f146200242f576102078054600160401b8110156200046c5760018101808355811015620028c35783907f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2015554915f5260205260405f2055600190565b805f5261020a8060205260405f2054155f146200242f576102098054600160401b8110156200046c5760018101808355811015620028c35783907f99e87348be6dc95028197b5a6b69c6a7a15df569de2f3d37542e8f40b8bae486015554915f5260205260405f2055600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562003cee57565b604051631afcd79f60e31b8152600490fd5b62003d0a62003cbe565b61271061ffff83161162003d445762003d2390620039e9565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b62003d6062003cbe565b801562003d78576001810162003d735750565b60d455565b6040516331278a8760e01b8152600490fd5b62003d9462003cbe565b6801bc16d674ec80000062003da8620024d7565b1062003d785762003db862004101565b61010a55565b62003dc862003cbe565b6001600160a01b03168062003dda5750565b61016e80546001600160a01b0319169091179055565b62003dfa62003cbe565b601e815111801562003f2d575b62003f1b5762003e1662003cbe565b8051906001600160401b0382116200046c5762003e3f8262003e395f5462000409565b62004746565b602090816001601f85111462003ea05750918062003e799262003e8195945f9262003e94575b50508160011b915f199060031b1c19161790565b5f556200481b565b62000ea462003e8f620030df565b600455565b015190505f8062003e65565b5f80529190601f1984165f8051602062004ffa833981519152935f905b82821062003f0257505091600193918562003e819796941062003ee9575b505050811b015f556200481b565b01515f1960f88460031b161c191690555f808062003edb565b8060018697829497870151815501960194019062003ebd565b604051632d3f993760e21b8152600490fd5b50600a82511162003e07565b62003f4362003cbe565b62003f4d62003cbe565b62003f5762003cbe565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341062003f9357620023b9343062003a4e565b60405163ea2559bb60e01b8152600490fd5b90816020910312620003e35751620005298162001f62565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816200404d575b506200400f57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206200501a8339815191528403620040345762000ea492935062004906565b604051632a87526960e21b815260048101859052602490fd5b6200406b91955060203d6020116200118c576200117c8183620004aa565b935f62003fe8565b60d154806200408157505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316620007a2565b908082101562002a9d575090565b60d554908160801c81158015620040f8575b15620040e35750905090565b6001600160801b036200052993169162002b40565b508015620040d7565b6e5661756c7456616c696461746f727360881b6020604051620041248162000472565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176200046c5760405251902090565b81519190604183036200420457620041fd9250602082015190606060408401519301515f1a90620049ae565b9192909190565b50505f9160029190565b90603011620003e35790603090565b909291928360b011620003e3578311620003e35760b0019160af190190565b90609011620003e35760300190606090565b9060c411620003e35760900190603490565b90939293848311620003e3578411620003e3578101920390565b35906020811062004289575090565b5f199060200360031b1b1690565b959493620042c9620042d893620042ba6060969460808b5260808b0190620026dc565b9089820360208b0152620004ef565b918783036040890152620026f4565b930152565b96959490620042d893620042ba620042c9926060979560808c5260808c0191620026f4565b90602062000529928181520190620026dc565b91602062000529938181520191620026f4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062004371575050505050505050565b826200438291018092878762004260565b906200438f82826200420e565b91620043a8620043a18580846200421d565b9062004a46565b90620043cd620043c6620043bd87846200423c565b9790936200424e565b906200427a565b948c3b15620003e3578c5f926801bc16d674ec8000006040956200440987519a8b96879586946304512a2360e31b86528d8d60048801620042dd565b03925af190811562000935577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1946200444e926200445e575b50519283928362004315565b0390a1600181930192906200435f565b806200094b6200446e9262000458565b5f62004442565b81603011620003e3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691620044ba620043a18280856200421d565b620044c682846200423c565b94909260b011620003e357803b15620003e3576200450f946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162004297565b03925af190811562000935577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19262002f8d9262004556575b506040519182918262004302565b806200094b620045669262000458565b5f62004548565b9190916001600160801b038080941691160191821162000aeb57565b5f805160206200503a83398151915260205f92620045a78562003879565b60cf5490620045c16001600160801b03918284166200456d565b6fffffffffffffffffffffffffffffffff1990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b038216918215620047405760801c6200463a620046288247620023ee565b62004633856200233e565b90620040b7565b90811562004739576200464d826200394c565b938415620047315782620046a66200189e62002ffa62000ea49662002ed096620046a06200468462002ffa8d620047259a620023ee565b6001600160801b03166001600160801b031960d054161760d055565b620024e6565b620046b2818762004b68565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162002ffa62004709620046f78862003879565b60cf546001600160801b031662002812565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c62002812565b505f93505050565b505f925050565b505f9150565b601f811162004753575050565b5f80525f8051602062004ffa833981519152906020601f840160051c830193106200479a575b601f0160051c01905b8181106200478e575050565b5f815560010162004782565b909150819062004779565b90601f8211620047b3575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931062004810575b601f0160051c01905b8181106200480557505050565b5f81558201620047f8565b9091508190620047ef565b9081516001600160401b0381116200046c57600190620048478162004841845462000409565b620047a5565b602080601f83116001146200487f575081906200487b9394955f9262003e945750508160011b915f199060031b1c19161790565b9055565b90601f19831695620048b260015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b888210620048ee5750508385969710620048d5575b505050811b019055565b01515f1960f88460031b161c191690555f8080620048cb565b808785968294968601518155019501930190620048b6565b90813b156200498d575f805160206200501a83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156200497157620023b99162004c4b565b5050346200497b57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162004a3b579062004a096020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1562000935575f516001600160a01b0381161562004a3157905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362004afa576bffffffffffffffffffffffff19919035828116916014811062004ae4575b5050905060601c62004a9062001797825f5261020860205260405f2054151590565b62004ad25760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c83015262000529908290810162002619565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004a6e565b604051639be7315960e01b8152600490fd5b60d15490600160401b8210156200046c57600182018060d155821015620028c35760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206200505a83398151915290910155565b9190918015801562004c42575b62004c305762004b8462004073565b90810180911162000aeb576001600160a01b0380821162004c10576001600160601b039081851162004bf0579062000ea4939462004bd962004bea9362004bca62000e95565b95166001600160a01b03168552565b166001600160601b03166020830152565b62004b0c565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562004b75565b5f806200052993602081519101845af462004c65620028d6565b9162004cdb565b6001600160a01b03165f81815260d36020526040902080548381039190821162000aeb575f935f805160206200503a833981519152926020925562004cb18162003879565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b9062004cf257508051156200391057805190602001fd5b8151158062004d27575b62004d05575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562004cfc56fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c63430008160033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a2646970667358221220b68208d0deab7c9c59eb855ba27d59d822fe3b48d9358094385ee0075b985d1464736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101562000026575b36156200001a575f80fd5b6200002462002aa2565b005b5f3560e01c806301e1d11414620003d257806306fdde0314620003cc57806307a2d13a14620003c6578063095ea7b314620003c0578063096ae80d14620003ba5780630b10b20114620003b457806318160ddd146200037e57806318f7295014620003ae5780631a7ff55314620003a857806323b872dd14620003a25780632cdf7401146200039c578063313ce56714620003965780633229fa95146200039057806333194c0a146200038a5780633644e51514620003845780633a98ef39146200037e578063439fab9114620003785780634690484014620003725780634f1ef286146200036c57806352d1902d146200036657806353156f28146200036057806354fd4d50146200035a5780635c60da1b14620003545780635cfc1a51146200034e57806360d60e6e146200034857806370a0823114620002b857806372b410a81462000342578063754c3888146200033c57806376b58b9014620003365780637b6341c614620003305780637ecebe00146200032a5780637fd6f15c146200032457806383d430d5146200031e5780638697d2c214620003185780638ceab9aa146200031257806395d89b41146200030c578063a045dd0c1462000306578063a49a1e7d1462000300578063a9059cbb14620002fa578063ac9650d814620002f4578063ad3cb1cc14620002ee578063b1f0e7c714620002e8578063c5aecb2214620002e2578063c6e6f59214620002dc578063d505accf14620002d6578063d83ad00c14620002d0578063dd62ed3e14620002ca578063e74b981b14620002c4578063ee3bd5df14620002be578063f04da65b14620002b8578063f132f5d314620002b2578063f851a44014620002ac5763f9609f08036200000f5762002324565b620022fa565b6200228d565b620012ee565b62002265565b62002230565b620021e8565b62002196565b62001f6e565b62001f40565b62001f22565b62001f04565b62001eb9565b62001e4a565b62001da8565b62001d4f565b62001d0d565b62001c5b565b62001a58565b620017bb565b620015b6565b62001590565b62001551565b6200148d565b62001435565b620013c3565b6200132d565b620012cc565b620012ae565b62001277565b6200125a565b62001232565b620011c5565b62000efd565b62000e4b565b62000c18565b6200096b565b62000b98565b62000b5c565b62000b2c565b62000b0f565b62000af1565b62000a40565b62000a07565b620009a2565b62000782565b620006ed565b62000645565b62000609565b6200052c565b620003e7565b5f910312620003e357565b5f80fd5b34620003e3575f366003190112620003e357602060cf5460801c604051908152f35b90600182811c9216801562000439575b60208310146200042557565b634e487b7160e01b5f52602260045260245ffd5b91607f169162000419565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200046c57604052565b62000444565b604081019081106001600160401b038211176200046c57604052565b608081019081106001600160401b038211176200046c57604052565b90601f801991011681019081106001600160401b038211176200046c57604052565b5f5b838110620004de5750505f910152565b8181015183820152602001620004ce565b906020916200050a81518092818552858086019101620004cc565b601f01601f1916010190565b90602062000529928181520190620004ef565b90565b34620003e3575f366003190112620003e3576040515f80546200054f8162000409565b80845290602090600190818116908115620005dc575060011462000592575b6200058e856200058181870382620004aa565b6040519182918262000516565b0390f35b5f80805293505f8051602062004ffa8339815191525b838510620005c85750505050810160200162000581826200058e6200056e565b8054868601840152938201938101620005a8565b8695506200058e969350602092506200058194915060ff191682840152151560051b82010192936200056e565b34620003e3576020366003190112620003e35760206200062b6004356200233e565b604051908152f35b6001600160a01b03811603620003e357565b34620003e3576040366003190112620003e357600435620006668162000633565b6001600160a01b03811690602435908215620006db57620006a38291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b34620003e3576020366003190112620003e3576004356200070e8162000633565b610206805490916001600160a01b03908116908216811462000770577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e892816020936200075a62002bc4565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b34620003e3575f366003190112620003e357620007ae620007a262002a80565b6001600160a01b031690565b330362000959576040516102c8808201908282106001600160401b038311176200046c5782916200081f9162004d3284396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff0801562000935576001600160a01b0390811690813b15620003e35760405163439fab9160e01b8152602060048201525f602482018190528160448183875af1801562000935576200093b575b506040516351d5709b60e11b815291602083600481845afa91821562000935577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f93620008f8575b50620008c790831662003be2565b50620008d38162003c50565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b620008c7919350620009259060203d6020116200092d575b6200091c8183620004aa565b81019062002372565b9290620008b9565b503d62000910565b62002367565b806200094b620009529262000458565b80620003d8565b5f6200086f565b604051634ca8886760e01b8152600490fd5b34620003e3575f366003190112620003e35760206001600160801b0360cf5416604051908152f35b90816080910312620003e35790565b6060366003190112620003e357600435620009bd8162000633565b602435620009cb8162000633565b604435906001600160401b038211620003e357602092620009ff620009f96200062b94369060040162000993565b6200238a565b349062003b26565b34620003e3576020366003190112620003e3576004356001600160401b038111620003e357620009f96200002491369060040162000993565b34620003e3576060366003190112620003e35760043562000a618162000633565b60243562000a6f8162000633565b6001600160a01b0382165f818152600260209081526040808320338452909152902090926044359291546001810162000abc575b5062000ab093506200306d565b60405160018152602090f35b83810390811162000aeb575f94855260026020908152604080872033885290915285205562000ab09362000aa3565b620023da565b34620003e3575f366003190112620003e35760206200062b620023fc565b34620003e3575f366003190112620003e357602060405160128152f35b34620003e3575f366003190112620003e357602062000b4a62002435565b6040516001600160a01b039091168152f35b34620003e3575f366003190112620003e35760206040517f778168b2049c66a50853dfa28c8d05dfb083907876871d6640cd612be7e580f28152f35b34620003e3575f366003190112620003e35760206200062b62002471565b9181601f84011215620003e3578235916001600160401b038311620003e35760208381860195010111620003e357565b6020600319820112620003e357600435906001600160401b038211620003e35762000c149160040162000bb6565b9091565b62000c233662000be6565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c16801562000e36575b62000e255768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020908185600481335afa94851562000935575f9562000e01575b508351636f4fa30f60e01b8152908282600481335afa91821562000935575f9262000ddd575b508301948284870312620003e35783356001600160401b0394858211620003e3570160a081880312620003e35762000cfd62000e75565b938135855262000d0f818301620024a9565b9085015285810135858111620003e3578762000d2d918301620024b9565b868501526060810135858111620003e3578762000d4c918301620024b9565b60608501526080810135948511620003e3577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29662000d9c9562000d919201620024b9565b608084015262003214565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff00000000000000001916905551600281528060208101620008f3565b62000df9919250833d85116200092d576200091c8183620004aa565b905f62000cc6565b62000e1d919550823d84116200092d576200091c8183620004aa565b935f62000ca0565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000c5a565b34620003e3575f366003190112620003e357609c546040516001600160a01b039091168152602090f35b6040519060a082018281106001600160401b038211176200046c57604052565b6040519062000ea48262000472565b565b6001600160401b0381116200046c57601f01601f191660200190565b92919262000ed08262000ea6565b9162000ee06040519384620004aa565b829481845281830111620003e3578281602093845f960137010152565b604080600319360112620003e357600490813562000f1b8162000633565b6024356001600160401b038111620003e35736602382011215620003e35762000f4e903690602481870135910162000ec2565b9162000f59620032e7565b80519262000f948462000f8560209363439fab9160e01b858401528460248401526044830190620004ef565b03601f198101865285620004aa565b62000f9e620032e7565b62000fa862002bc4565b6001600160a01b0383811680159291908790841562001194575b84156200110c575b84156200109e575b5050821562000ffe575b505062000fef5762000024838362003fbd565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821562000935575f926200106a575b5050155f8062000fdc565b6200108e9250803d1062001096575b620010858183620004aa565b810190620025d1565b5f806200105f565b503d62001079565b855163054fd4d560e41b81529294508391839182905afa908115620009355760039160ff915f91620010d8575b5016141591865f62000fd2565b620010fd9150843d861162001104575b620010f48183620004aa565b81019062003fa5565b5f620010cb565b503d620010e8565b935050835163198ca60560e11b815282818981875afa908115620009355788917f778168b2049c66a50853dfa28c8d05dfb083907876871d6640cd612be7e580f2915f9162001160575b5014159362000fca565b620011859150853d87116200118c575b6200117c8183620004aa565b81019062002cb0565b5f62001156565b503d62001170565b5f805160206200501a833981519152549094508490620011bd906001600160a01b0316620007a2565b149362000fc2565b34620003e3575f366003190112620003e3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620012205760206040515f805160206200501a8339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112620003e3576001600160a01b036200125062002435565b1633036200095957005b34620003e3575f366003190112620003e357602060405160028152f35b34620003e3575f366003190112620003e3575f805160206200501a833981519152546040516001600160a01b039091168152602090f35b34620003e3575f366003190112620003e35760206200062b620024d7565b34620003e3576020366003190112620003e35760206200062b600435620024f4565b34620003e3576020366003190112620003e3576004356200130f8162000633565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b34620003e3575f366003190112620003e357604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801562000935576020915f91620013a1575b506040519015158152f35b620013bc9150823d84116200109657620010858183620004aa565b5f62001396565b34620003e3576020366003190112620003e357600435620013e48162000633565b620013ee62002bc4565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b34620003e3576080366003190112620003e3576200058e620014706004356200145e8162000633565b606435906044359060243590620025e8565b604080519384526020840192909252908201529081906060820190565b34620003e3575f366003190112620003e35760405180610207805480845260208094019081925f527f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2905f5b868282106200153c578686620014f282880383620004aa565b60405192839281840190828552518091526040840192915f5b8281106200151b57505050500390f35b83516001600160a01b0316855286955093810193928101926001016200150b565b835485529093019260019283019201620014d9565b34620003e3576020366003190112620003e357600435620015728162000633565b60018060a01b03165f526003602052602060405f2054604051908152f35b34620003e3575f366003190112620003e357602061ffff609c5460a01c16604051908152f35b34620003e357600319604036820112620003e35760049081356001600160401b03808211620003e35760a0828501938336030112620003e357602435908111620003e35762001609903690850162000bb6565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b15620003e35760405163837d444160e01b8152905f9082908183816200165f8c828f0162002714565b03925af180156200093557620017a4575b506200167b62003624565b6200168562002a48565b90811633141591826200176d575b505090506200175c576044019160c4620016ae84846200279e565b9050048015801562001741575b6200173157620016d5620016ce620023fc565b91620027f8565b1162001722575060c4620016ea83836200279e565b9050145f146200170b57620000249162001704916200279e565b9062004475565b62000024916200171b916200279e565b9062004328565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506200174e84846200279e565b905060c482021415620016bb565b604051634ca8886760e01b81528390fd5b620017979250620017906200179b946200178788620036b7565b92369162000ec2565b916200379d565b1590565b805f8062001693565b806200094b620017b49262000458565b5f62001670565b34620003e3576060366003190112620003e357600435602435620017e4604435828433620025e8565b9192620018127f000000000000000000000000000000000000000000000000000000000000000082620024e6565b4210801562001a4f575b801562001a46575b62001a34577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936200187986620018736200186760d0546001600160801b031690565b6001600160801b031690565b62003344565b156200199257620018b96200189e620018928662003879565b60d05460801c62002812565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91620019009190620018ef608082620004aa565b5190205f5260d260205260405f2090565b555f93600183116200193c575b505050506200191d8233620038ad565b604080519485526020850191909152830152339180606081015b0390a2005b6200198792939450620019509088620024e6565b60408051336020820190815291810193909352606083018290529094909190620018ef9082608081015b03908101835282620004aa565b555f8080806200190d565b6200199c62003624565b620019dd620019c1620019af8662003879565b60d5546001600160801b031662002812565b6001600160801b03166001600160801b031960d554161760d555565b62001a17620019fc620019f08562003879565b60d55460801c62002812565b6001600160801b0360d5549181199060801b1691161760d555565b62001a2e62001a298460d654620024e6565b60d655565b620018b9565b604051630e3d8e8d60e11b8152600490fd5b50821562001824565b5081156200181c565b34620003e357604080600319360112620003e3576024359060043562001a7e8362000633565b62001a8862003624565b801562001c4a576001600160a01b03831690811562001c395762001aac816200233e565b90811562001c285762001abf82620040c5565b62001aca8362003879565b60cf5460801c9062001adc9162002812565b62001afc906001600160801b0360cf549181199060801b1691161760cf55565b62001b08823362004c6c565b60d554958660801c828160d6549062001b2191620024e6565b9862001b2d8762003879565b62001b41916001600160801b03166200456d565b62001b62906001600160801b03166001600160801b031960d554161760d555565b62001b6d91620024e6565b62001b789062003879565b62001b98906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529062001bcb608082620004aa565b51902062001be1905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b34620003e3575f366003190112620003e3576040515f6001805462001c808162000409565b8085529160209160018116908115620005dc575060011462001caf576200058e856200058181870382620004aa565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851062001cf95750505050810160200162000581826200058e6200056e565b805486860184015293820193810162001cd9565b34620003e3575f366003190112620003e357610206546020906001600160a01b039081168062001d4857508060375416905b60405191168152f35b9062001d3f565b34620003e357620019377f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf62001d853662000be6565b929062001d9162002bc4565b6040519182916020835233956020840191620026f4565b34620003e3576040366003190112620003e35762001dd860043562001dcd8162000633565b60243590336200306d565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831062001e195750505050505090565b909192939495848062001e39600193603f198682030187528a51620004ef565b980193019301919493929062001e08565b34620003e3576020366003190112620003e3576001600160401b03600435818111620003e35736602382011215620003e3578060040135918211620003e3573660248360051b83010111620003e3576200058e91602462001eac920162002987565b6040519182918262001de3565b34620003e3575f366003190112620003e3576200058e60405162001edd8162000472565b60058152640352e302e360dc1b6020820152604051918291602083526020830190620004ef565b34620003e3575f366003190112620003e357602062000b4a62002a48565b34620003e3575f366003190112620003e357602062000b4a62002a80565b34620003e3576020366003190112620003e35760206200062b6004356200394c565b60ff811603620003e357565b34620003e35760e0366003190112620003e35760043562001f8f8162000633565b60243562001f9d8162000633565b60443590606435926084359062001fb48262001f62565b6001600160a01b03838116959092908615620006db5742811062002184576020915f916200197a620020b089878a6200207162001ff062002471565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039162002087601f1993848101835282620004aa565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa1562000935575f5192828416801590811562002176575b506200216457620021558591620021407f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b556040519384521691602090a3005b6040516323389ba560e21b8152600490fd5b905083831614155f620020f8565b604051631ab7da6b60e01b8152600490fd5b34620003e3575f366003190112620003e35760206001600160801b0360d05416604051908152f35b6040906003190112620003e357600435620021d98162000633565b90602435620005298162000633565b34620003e357602062002227620021ff36620021be565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b34620003e3576020366003190112620003e35762000024600435620022558162000633565b6200225f62002bc4565b620039e9565b34620003e3575f366003190112620003e35760206001600160801b0360d55416604051908152f35b34620003e3576020366003190112620003e357600435620022ae8162000633565b610205805490916001600160a01b03908116908216811462000770577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d92816020936200075a62002bc4565b34620003e3575f366003190112620003e3576037546040516001600160a01b039091168152602090f35b60206200062b6200233536620021be565b90349062003b26565b60cf546001600160801b03811690816200235757505090565b91620005299260801c9062002b40565b6040513d5f823e3d90fd5b90816020910312620003e35751620005298162000633565b62002399620023a19162002cdc565b919062002e94565b620023a857565b620023b2620045ff565b80620023bc575b50565b5f906040519081525f805160206200503a83398151915260203092a3565b634e487b7160e01b5f52601160045260245ffd5b9190820391821162000aeb57565b4760d0546001600160801b03620024158183166200233e565b9060d55416019060801c01908181115f146200242f570390565b50505f90565b61016e546001600160a01b031680156200244c5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036200249f5760045490565b62000529620030df565b359061ffff82168203620003e357565b9080601f83011215620003e357816020620005299335910162000ec2565b60d454806200052957505f1990565b9190820180921162000aeb57565b6001600160801b0360d054166200250a62004073565b90810180911162000aeb57811062002544576200253460d6546200252d6200335e565b90620024e6565b11156200253f575f90565b5f1990565b60d19060d1549182915f905b8482106200256c57505050811015620025665790565b505f1990565b909193808316906001818518811c830180931162000aeb575f8790525f805160206200505a8339815191528301546001600160a01b0316841015620025b7575050935b919062002550565b909591019250620025af565b51908115158203620003e357565b90816020910312620003e3576200052990620025c3565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200262881608081015b03601f198101835282620004aa565b5190205f5260d260205260405f20549182156200269d576001600160801b0360d05416906200265662004073565b91820180921162000aeb57839183101562002688579162002677926200346d565b90915b82810390811162000aeb5792565b50906200269591620033d3565b90916200267a565b5050505f905f905f90565b9035601e1982360301811215620003e35701602081359101916001600160401b038211620003e3578136038313620003e357565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620005299260208152823560208201526020830135604082015262002755620027446040850185620026a8565b84606085015260c0840191620026f4565b906200278e620027826200276d6060870187620026a8565b601f19858703810160808701529591620026f4565b946080810190620026a8565b93909282860301910152620026f4565b903590601e1981360301821215620003e357018035906001600160401b038211620003e357602001918136038313620003e357565b634e487b7160e01b5f52601260045260245ffd5b8115620027f2570490565b620027d3565b906801bc16d674ec800000918083029283040362000aeb57565b6001600160801b03918216908216039190821162000aeb57565b6001600160401b0381116200046c5760051b60200190565b9062002850826200282c565b6200285f6040519182620004aa565b828152809262002872601f19916200282c565b01905f5b8281106200288357505050565b80606060208093850101520162002876565b634e487b7160e01b5f52603260045260245ffd5b90821015620028c35762000c149160051b8101906200279e565b62002895565b908092918237015f815290565b3d1562002905573d90620028ea8262000ea6565b91620028fa6040519384620004aa565b82523d5f602084013e565b606090565b602081830312620003e3578051906001600160401b038211620003e3570181601f82011215620003e3578051620029418162000ea6565b92620029516040519485620004aa565b81845260208284010111620003e357620005299160208085019101620004cc565b8051821015620028c35760209160051b010190565b919091620029958362002844565b925f5b818110620029a557505050565b5f80620029b4838587620028a9565b60409391620029c8855180938193620028c9565b0390305af490620029d8620028d6565b911562002a05575090600191620029f0828862002972565b52620029fd818762002972565b500162002998565b906044815110620003e35762002a4462002a2e600492838101516024809183010191016200290a565b925162461bcd60e51b8152928392830162000516565b0390fd5b610109546001600160a01b0316806200052957507f000000000000000000000000000000000000000000000000000000000000000090565b610205546001600160a01b039081168062002a9d57506037541690565b905090565b335f5261020a60205260405f20541562002ab857565b620023b9343362003a4e565b90808202905f198184099082808310920391808303921462002b3557612710908282111562002b23577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f198482099383808610950394808603951462002bb5578483111562002b2357829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620005299250620027e7565b6037546001600160a01b031633036200095957565b90816060910312620003e35780519162000529604060208401519301620025c3565b81835290916001600160fb1b038311620003e35760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103620003e3576040830152604081013562002c528162000633565b6001600160a01b031660608381019190915281013536829003601e1901811215620003e35701602081359101906001600160401b038111620003e3578060051b36038213620003e35760a08360808062000529960152019162002bfb565b90816020910312620003e3575190565b9190915f838201938412911290801582169115161762000aeb57565b6040516325f56f1160e01b81526001600160a01b0392916060908290819062002d09906004830162002c20565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831562000935575f915f905f9562002e47575b50841562002dec578162002d5862002435565b16917f000000000000000000000000000000000000000000000000000000000000000016821462002de457509060205f92600460405180958193634641257d60e01b83525af1908115620009355762002dba925f9262002dbe575b5062002cc0565b9190565b62002ddc91925060203d6020116200118c576200117c8183620004aa565b905f62002db3565b908162002df2575b50509190565b803b15620003e357604051636ee3193160e11b815260048101929092525f908290602490829084905af18015620009355762002e30575b8062002dec565b806200094b62002e409262000458565b5f62002e29565b9194505062002e72915060603d60601162002e7b575b62002e698183620004aa565b81019062002bd9565b93905f62002d45565b503d62002e5d565b600160ff1b811462000aeb575f0390565b8015620023b95762002eac6200186760cf5460801c90565b5f821262002fb1578162002ec091620024e6565b9062002eeb62002ed08362003879565b6001600160801b0360cf549181199060801b1691161760cf55565b62002f02609c549161ffff8360a01c169062002ac4565b801562002fac57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362002f436200186760cf546001600160801b031690565b8062002f9257505062002f8d90925b6001600160a01b03169162002f68848462004589565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b62002f8d9262002fa59203908462002b40565b9262002f52565b505050565b9062002fbd9062002e83565b62002fd46200186760d5546001600160801b031690565b8062003000575b508062002fe6575050565b62002ffa62002ed09162000ea493620023ee565b62003879565b90620030637f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9162003053620019c1620030476200303f8888620024e6565b878562002b40565b80809403960362003879565b6040519081529081906020820190565b0390a15f62002fdb565b6001600160a01b03908116919082158015620030d4575b620006db57825f5260d360205260405f209081549285840393841162000aeb575f805160206200503a83398151915293602093551693845f5260d3825260405f20818154019055604051908152a3565b508082161562003084565b6040515f905f5490620030f28262000409565b9283825260209384830193600190866001821691825f14620031f2575050600114620031aa575b5050918162003133620031a49362002619950382620004aa565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f8051602062004ffa8339815191525b828410620031dc57505050820101816200313362003119565b80548685018601528794909301928101620031c3565b60ff1916875292151560051b8501909201925083915062003133905062003119565b91906200322062003cbe565b6080820151906200323062003cbe565b6001600160a01b0384168015620006db57620032dd94620032cc93620032b0926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806200329d33946020830190620004ef565b0390a2602085015161ffff169062003d00565b620032bc835162003d56565b620032c662003d8a565b62003dbe565b606060408201519101519062003df0565b62000ea462003f39565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562003327575b50506200122057565b5f805160206200501a8339815191525416141590505f806200331e565b906200334f62004073565b91820180921162000aeb571090565b4760d0548060801c820391821162000aeb5781620033866001600160801b038093166200233e565b9081620033b2575b505081156200242f576200052991620033ac9160d5541690620040b7565b620040c5565b9192509081811115620033ca57035b905f806200338e565b50505f620033c1565b620033dd6200335e565b9160d65492830180931162000aeb57808311156200342e5762003402920390620040b7565b9060d5548060801c80155f14620034195750508190565b6001600160801b036200052992168462002b40565b5050505f905f90565b90604051604081018181106001600160401b038211176200046c5760405291546001600160a01b038116835260a01c6020830152565b60d1545f9485949390918084108015906200361b575b6200360e5783620035d7575f5b60d15f526001600160a01b0316620034b85f805160206200505a833981519152860162003437565b8051909790620034d1906001600160a01b0316620007a2565b98620034f8620034ec6020809b01516001600160601b031690565b6001600160601b031690565b948381108015620035cc575b620035ba5791600193979a956200352762003534939488035b838c0390620040b7565b8092019887039162002b40565b01970193808611801590620035af575b620035a45760d15f5282906200356a5f805160206200505a833981519152870162003437565b805190890151969992966001600160a01b039091169460019392620035349290916001600160601b0390911690620035279088036200351d565b945050509250509190565b508185101562003544565b60405163e8722f8f60e01b8152600490fd5b50808b111562003504565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b031662003490565b505093505050505f905f90565b50841562003483565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562000935575f9162003693575b506200368157565b60405163e775715160e01b8152600490fd5b620036b0915060203d6020116200109657620010858183620004aa565b5f62003679565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200376d5761010a54905b62003703620036fb60408301836200279e565b369162000ec2565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815262003750816200048e565b5190206040519161190160f01b8352600283015260228201522090565b6200377762004101565b90620036e8565b600411156200378957565b634e487b7160e01b5f52602160045260245ffd5b620037a98383620041d1565b50620037b8819592956200377e565b15938462003862575b508315620037d0575b50505090565b5f9293509082916040516200380b81620026196020820194630b135d3f60e11b998a87526024840152604060448401526064830190620004ef565b51915afa906200381a620028d6565b8262003853575b8262003833575b50505f8080620037ca565b6200384a9192506020808251830101910162002cb0565b145f8062003828565b91506020825110159162003821565b6001600160a01b0383811691161493505f620037c1565b6001600160801b03908181116200388e571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146200393a576002835581471062003922575f918291829182916001600160a01b03165af162003903620028d6565b5015620039105760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b038216811580156200397f575b15620039705750905090565b620005299260801c9162002b40565b50801562003964565b60cf546001600160801b0381169082158015620039e0575b15620039ab57505090565b60801c90620039bc82828562002b40565b928215620027f25709620039cd5790565b60018101809111156200052957620023da565b508115620039a0565b620039f362003624565b6001600160a01b0316801562003a3c57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b919062003a5a62003624565b6001600160a01b038316908115620006db57801562003b14578062003a856200186760cf5460801c90565b019362003a91620024d7565b851162003b025762002ed09462003ac09162003aba62003ab18562003988565b97889362003879565b62004589565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b9092919262003b3462003624565b6001600160a01b038216918215620006db57811562003b14578162003b5f6200186760cf5460801c90565b0162003b6a620024d7565b811162003b025762002ed09562003bb962003afd927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003aba62003bb08862003988565b9a8b9362003879565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f526102088060205260405f2054155f146200242f576102078054600160401b8110156200046c5760018101808355811015620028c35783907f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2015554915f5260205260405f2055600190565b805f5261020a8060205260405f2054155f146200242f576102098054600160401b8110156200046c5760018101808355811015620028c35783907f99e87348be6dc95028197b5a6b69c6a7a15df569de2f3d37542e8f40b8bae486015554915f5260205260405f2055600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562003cee57565b604051631afcd79f60e31b8152600490fd5b62003d0a62003cbe565b61271061ffff83161162003d445762003d2390620039e9565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b62003d6062003cbe565b801562003d78576001810162003d735750565b60d455565b6040516331278a8760e01b8152600490fd5b62003d9462003cbe565b6801bc16d674ec80000062003da8620024d7565b1062003d785762003db862004101565b61010a55565b62003dc862003cbe565b6001600160a01b03168062003dda5750565b61016e80546001600160a01b0319169091179055565b62003dfa62003cbe565b601e815111801562003f2d575b62003f1b5762003e1662003cbe565b8051906001600160401b0382116200046c5762003e3f8262003e395f5462000409565b62004746565b602090816001601f85111462003ea05750918062003e799262003e8195945f9262003e94575b50508160011b915f199060031b1c19161790565b5f556200481b565b62000ea462003e8f620030df565b600455565b015190505f8062003e65565b5f80529190601f1984165f8051602062004ffa833981519152935f905b82821062003f0257505091600193918562003e819796941062003ee9575b505050811b015f556200481b565b01515f1960f88460031b161c191690555f808062003edb565b8060018697829497870151815501960194019062003ebd565b604051632d3f993760e21b8152600490fd5b50600a82511162003e07565b62003f4362003cbe565b62003f4d62003cbe565b62003f5762003cbe565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341062003f9357620023b9343062003a4e565b60405163ea2559bb60e01b8152600490fd5b90816020910312620003e35751620005298162001f62565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816200404d575b506200400f57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206200501a8339815191528403620040345762000ea492935062004906565b604051632a87526960e21b815260048101859052602490fd5b6200406b91955060203d6020116200118c576200117c8183620004aa565b935f62003fe8565b60d154806200408157505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316620007a2565b908082101562002a9d575090565b60d554908160801c81158015620040f8575b15620040e35750905090565b6001600160801b036200052993169162002b40565b508015620040d7565b6e5661756c7456616c696461746f727360881b6020604051620041248162000472565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176200046c5760405251902090565b81519190604183036200420457620041fd9250602082015190606060408401519301515f1a90620049ae565b9192909190565b50505f9160029190565b90603011620003e35790603090565b909291928360b011620003e3578311620003e35760b0019160af190190565b90609011620003e35760300190606090565b9060c411620003e35760900190603490565b90939293848311620003e3578411620003e3578101920390565b35906020811062004289575090565b5f199060200360031b1b1690565b959493620042c9620042d893620042ba6060969460808b5260808b0190620026dc565b9089820360208b0152620004ef565b918783036040890152620026f4565b930152565b96959490620042d893620042ba620042c9926060979560808c5260808c0191620026f4565b90602062000529928181520190620026dc565b91602062000529938181520191620026f4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062004371575050505050505050565b826200438291018092878762004260565b906200438f82826200420e565b91620043a8620043a18580846200421d565b9062004a46565b90620043cd620043c6620043bd87846200423c565b9790936200424e565b906200427a565b948c3b15620003e3578c5f926801bc16d674ec8000006040956200440987519a8b96879586946304512a2360e31b86528d8d60048801620042dd565b03925af190811562000935577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1946200444e926200445e575b50519283928362004315565b0390a1600181930192906200435f565b806200094b6200446e9262000458565b5f62004442565b81603011620003e3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691620044ba620043a18280856200421d565b620044c682846200423c565b94909260b011620003e357803b15620003e3576200450f946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162004297565b03925af190811562000935577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19262002f8d9262004556575b506040519182918262004302565b806200094b620045669262000458565b5f62004548565b9190916001600160801b038080941691160191821162000aeb57565b5f805160206200503a83398151915260205f92620045a78562003879565b60cf5490620045c16001600160801b03918284166200456d565b6fffffffffffffffffffffffffffffffff1990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b038216918215620047405760801c6200463a620046288247620023ee565b62004633856200233e565b90620040b7565b90811562004739576200464d826200394c565b938415620047315782620046a66200189e62002ffa62000ea49662002ed096620046a06200468462002ffa8d620047259a620023ee565b6001600160801b03166001600160801b031960d054161760d055565b620024e6565b620046b2818762004b68565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162002ffa62004709620046f78862003879565b60cf546001600160801b031662002812565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c62002812565b505f93505050565b505f925050565b505f9150565b601f811162004753575050565b5f80525f8051602062004ffa833981519152906020601f840160051c830193106200479a575b601f0160051c01905b8181106200478e575050565b5f815560010162004782565b909150819062004779565b90601f8211620047b3575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931062004810575b601f0160051c01905b8181106200480557505050565b5f81558201620047f8565b9091508190620047ef565b9081516001600160401b0381116200046c57600190620048478162004841845462000409565b620047a5565b602080601f83116001146200487f575081906200487b9394955f9262003e945750508160011b915f199060031b1c19161790565b9055565b90601f19831695620048b260015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b888210620048ee5750508385969710620048d5575b505050811b019055565b01515f1960f88460031b161c191690555f8080620048cb565b808785968294968601518155019501930190620048b6565b90813b156200498d575f805160206200501a83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156200497157620023b99162004c4b565b5050346200497b57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162004a3b579062004a096020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1562000935575f516001600160a01b0381161562004a3157905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362004afa576bffffffffffffffffffffffff19919035828116916014811062004ae4575b5050905060601c62004a9062001797825f5261020860205260405f2054151590565b62004ad25760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c83015262000529908290810162002619565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004a6e565b604051639be7315960e01b8152600490fd5b60d15490600160401b8210156200046c57600182018060d155821015620028c35760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206200505a83398151915290910155565b9190918015801562004c42575b62004c305762004b8462004073565b90810180911162000aeb576001600160a01b0380821162004c10576001600160601b039081851162004bf0579062000ea4939462004bd962004bea9362004bca62000e95565b95166001600160a01b03168552565b166001600160601b03166020830152565b62004b0c565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562004b75565b5f806200052993602081519101845af462004c65620028d6565b9162004cdb565b6001600160a01b03165f81815260d36020526040902080548381039190821162000aeb575f935f805160206200503a833981519152926020925562004cb18162003879565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b9062004cf257508051156200391057805190602001fd5b8151158062004d27575b62004d05575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562004cfc56fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c63430008160033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a2646970667358221220b68208d0deab7c9c59eb855ba27d59d822fe3b48d9358094385ee0075b985d1464736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthRestakePrivErc20Vault.json b/test/shared/artifacts/EthRestakePrivErc20Vault.json deleted file mode 100644 index ab002c24..00000000 --- a/test/shared/artifacts/EthRestakePrivErc20Vault.json +++ /dev/null @@ -1,1779 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthRestakePrivErc20Vault", - "sourceName": "contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "eigenPodOwnerImplementation", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101c0346200016d57601f6200558138819003918201601f19168301916001600160401b03831184841017620001715780849260e0946040528339810103126200016d576200004e8162000185565b906200005d6020820162000185565b906200006c6040820162000185565b6200007a6060830162000185565b90620000896080840162000185565b9360c06200009a60a0860162000185565b9401519560805260a05260c0523060e052620000b56200019a565b610100934685526101209384526101404681526101609182526101809283526101a0938452620000e46200019a565b6040519461534796876200023a88396080518781816113a20152818161165b01528181612f1d015261386d015260a05187611075015260c0518781816145c20152614718015260e051878181611221015261351f015251866125d301525185612c5f015251846138eb015251836118340152518281816125ae0152612f6a015251816108310152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200016d57565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1662000227576001600160401b036002600160401b031982821601620001e857505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101562000026575b36156200001a575f80fd5b6200002462002ca3565b005b5f3560e01c806301e1d114146200041a57806306fdde03146200041457806307a2d13a146200040e578063095ea7b31462000408578063096ae80d14620004025780630b10b20114620003fc5780630d392cd914620003f657806318160ddd14620003ba57806318f7295014620003f05780631a7ff55314620003ea57806322758a4a14620003e457806323b872dd14620003de5780632cdf740114620003d8578063313ce56714620003d25780633229fa9514620003cc57806333194c0a14620003c65780633644e51514620003c05780633a98ef3914620003ba578063439fab9114620003b45780634690484014620003ae5780634f1ef28614620003a857806352d1902d14620003a257806353156f28146200039c57806354fd4d5014620003965780635c60da1b14620003905780635cfc1a51146200038a57806360d60e6e146200038457806370a0823114620002f457806372b410a8146200037e578063754c3888146200037857806376b58b9014620003725780637b6341c6146200036c5780637ecebe0014620003665780637fd6f15c146200036057806383d430d5146200035a5780638697d2c214620003545780638ceab9aa146200034e57806395d89b411462000348578063a045dd0c1462000342578063a49a1e7d146200033c578063a9059cbb1462000336578063ac9650d81462000330578063ad3cb1cc146200032a578063b1f0e7c71462000324578063c5aecb22146200031e578063c6e6f5921462000318578063d505accf1462000312578063d83ad00c146200030c578063dd62ed3e1462000306578063e74b981b1462000300578063ee3bd5df14620002fa578063f04da65b14620002f4578063f132f5d314620002ee578063f6a6830f14620002e8578063f851a44014620002e2578063f9609f0814620002dc5763f98f5b92036200000f57620023ce565b620023b1565b62002387565b62002342565b620022d5565b62001336565b620022ad565b62002278565b62002230565b620021de565b62001fb6565b62001f88565b62001f6a565b62001f4c565b62001f01565b62001e92565b62001df0565b62001d97565b62001d55565b62001ca3565b62001aa0565b62001803565b620015fe565b620015d8565b62001599565b620014d5565b6200147d565b6200140b565b62001375565b62001314565b620012f6565b620012bf565b620012a2565b6200127a565b6200120d565b62000f45565b62000e93565b62000ce6565b620009f8565b62000c66565b62000c2a565b62000bfa565b62000bdd565b62000bbf565b62000b0e565b62000ae3565b62000aaa565b62000a2f565b620009be565b620007ca565b62000735565b6200068d565b62000651565b62000574565b6200042f565b5f9103126200042b57565b5f80fd5b346200042b575f3660031901126200042b57602060cf5460801c604051908152f35b90600182811c9216801562000481575b60208310146200046d57565b634e487b7160e01b5f52602260045260245ffd5b91607f169162000461565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111620004b457604052565b6200048c565b604081019081106001600160401b03821117620004b457604052565b608081019081106001600160401b03821117620004b457604052565b90601f801991011681019081106001600160401b03821117620004b457604052565b5f5b838110620005265750505f910152565b818101518382015260200162000516565b90602091620005528151809281855285808601910162000514565b601f01601f1916010190565b9060206200057192818152019062000537565b90565b346200042b575f3660031901126200042b576040515f8054620005978162000451565b80845290602090600190818116908115620006245750600114620005da575b620005d685620005c981870382620004f2565b604051918291826200055e565b0390f35b5f80805293505f80516020620052928339815191525b8385106200061057505050508101602001620005c982620005d6620005b6565b8054868601840152938201938101620005f0565b869550620005d696935060209250620005c994915060ff191682840152151560051b8201019293620005b6565b346200042b5760203660031901126200042b5760206200067360043562002403565b604051908152f35b6001600160a01b038116036200042b57565b346200042b5760403660031901126200042b57600435620006ae816200067b565b6001600160a01b038116906024359082156200072357620006eb8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b346200042b5760203660031901126200042b5760043562000756816200067b565b610206805490916001600160a01b039081169082168114620007b8577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e89281602093620007a262002dd0565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200042b575f3660031901126200042b57620007f6620007ea62002c81565b6001600160a01b031690565b3303620009a1576040516102c8808201908282106001600160401b03831117620004b4578291620008679162004fca84396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff080156200097d576001600160a01b0390811690813b156200042b5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af180156200097d5762000983575b506040516351d5709b60e11b815291602083600481845afa9182156200097d577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f9362000940575b506200090f90831662003e7a565b506200091b8162003ee8565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200090f9193506200096d9060203d60201162000975575b620009648183620004f2565b81019062002437565b929062000901565b503d62000958565b6200242c565b80620009936200099a92620004a0565b8062000420565b5f620008b7565b604051634ca8886760e01b8152600490fd5b801515036200042b57565b346200042b5760403660031901126200042b5762000024600435620009e3816200067b565b60243590620009f282620009b3565b6200244f565b346200042b575f3660031901126200042b5760206001600160801b0360cf5416604051908152f35b908160809103126200042b5790565b60603660031901126200042b5760043562000a4a816200067b565b60243562000a58816200067b565b604435906001600160401b0382116200042b5760209262000a8c62000a866200067394369060040162000a20565b620024e9565b62000a973362003c7c565b62000aa28162003c7c565b349062003dbe565b346200042b5760203660031901126200042b576004356001600160401b0381116200042b5762000a866200002491369060040162000a20565b346200042b575f3660031901126200042b5761026f546040516001600160a01b039091168152602090f35b346200042b5760603660031901126200042b5760043562000b2f816200067b565b60243562000b3d816200067b565b6001600160a01b0382165f818152600260209081526040808320338452909152902090926044359291546001810162000b8a575b5062000b7e935062003276565b60405160018152602090f35b83810390811162000bb9575f94855260026020908152604080872033885290915285205562000b7e9362000b71565b62002539565b346200042b575f3660031901126200042b576020620006736200255b565b346200042b575f3660031901126200042b57602060405160128152f35b346200042b575f3660031901126200042b57602062000c1862002594565b6040516001600160a01b039091168152f35b346200042b575f3660031901126200042b5760206040517f737a47bb3e695a159ef397f75d47c2ca71c770e380ac29b104d3b82ee61be3c88152f35b346200042b575f3660031901126200042b57602062000673620025d0565b9181601f840112156200042b578235916001600160401b0383116200042b57602083818601950101116200042b57565b60206003198201126200042b57600435906001600160401b0382116200042b5762000ce29160040162000c84565b9091565b62000cf13662000cb4565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16801562000e7e575b62000e6c5768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156200097d575f9362000e48575b50604051636f4fa30f60e01b8152938285600481335afa9081156200097d5762000dba9562000db4945f9362000e1f575b505062000dac919281019062002636565b908362003433565b62003506565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016200093b565b62000dac9350908162000e4092903d106200097557620009648183620004f2565b915f62000d9b565b62000e64919350823d84116200097557620009648183620004f2565b915f62000d6a565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000d23565b346200042b575f3660031901126200042b57609c546040516001600160a01b039091168152602090f35b6040519060a082018281106001600160401b03821117620004b457604052565b6040519062000eec82620004ba565b565b6001600160401b038111620004b457601f01601f191660200190565b92919262000f188262000eee565b9162000f286040519384620004f2565b8294818452818301116200042b578281602093845f960137010152565b6040806003193601126200042b57600490813562000f63816200067b565b6024356001600160401b0381116200042b57366023820112156200042b5762000f96903690602481870135910162000f0a565b9162000fa162003515565b80519262000fdc8462000fcd60209363439fab9160e01b85840152846024840152604483019062000537565b03601f198101865285620004f2565b62000fe662003515565b62000ff062002dd0565b6001600160a01b03838116801592919087908415620011dc575b841562001154575b8415620010e6575b5050821562001046575b5050620010375762000024838362004255565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156200097d575f92620010b2575b5050155f8062001024565b620010d69250803d10620010de575b620010cd8183620004f2565b810190620027d1565b5f80620010a7565b503d620010c1565b855163054fd4d560e41b81529294508391839182905afa9081156200097d5760039160ff915f9162001120575b5016141591865f6200101a565b620011459150843d86116200114c575b6200113c8183620004f2565b8101906200423d565b5f62001113565b503d62001130565b935050835163198ca60560e11b815282818981875afa9081156200097d5788917f737a47bb3e695a159ef397f75d47c2ca71c770e380ac29b104d3b82ee61be3c8915f91620011a8575b5014159362001012565b620011cd9150853d8711620011d4575b620011c48183620004f2565b81019062002ebe565b5f6200119e565b503d620011b8565b5f80516020620052b283398151915254909450849062001205906001600160a01b0316620007ea565b14936200100a565b346200042b575f3660031901126200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620012685760206040515f80516020620052b28339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200042b576001600160a01b036200129862002594565b163303620009a157005b346200042b575f3660031901126200042b57602060405160028152f35b346200042b575f3660031901126200042b575f80516020620052b2833981519152546040516001600160a01b039091168152602090f35b346200042b575f3660031901126200042b57602062000673620026e5565b346200042b5760203660031901126200042b5760206200067360043562002702565b346200042b5760203660031901126200042b5760043562001357816200067b565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156200097d576020915f91620013e9575b506040519015158152f35b620014049150823d8411620010de57620010cd8183620004f2565b5f620013de565b346200042b5760203660031901126200042b576004356200142c816200067b565b6200143662002dd0565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200042b5760803660031901126200042b57620005d6620014b8600435620014a6816200067b565b606435906044359060243590620027e9565b604080519384526020840192909252908201529081906060820190565b346200042b575f3660031901126200042b5760405180610207805480845260208094019081925f527f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2905f5b86828210620015845786866200153a82880383620004f2565b60405192839281840190828552518091526040840192915f5b8281106200156357505050500390f35b83516001600160a01b03168552869550938101939281019260010162001553565b83548552909301926001928301920162001521565b346200042b5760203660031901126200042b57600435620015ba816200067b565b60018060a01b03165f526003602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57602061ffff609c5460a01c16604051908152f35b346200042b576003196040368201126200042b5760049081356001600160401b038082116200042b5760a08285019383360301126200042b576024359081116200042b5762001651903690850162000c84565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200042b5760405163837d444160e01b8152905f908290818381620016a78c828f0162002915565b03925af180156200097d57620017ec575b50620016c362003852565b620016cd62002c49565b9081163314159182620017b5575b50509050620017a4576044019160c4620016f684846200299f565b9050048015801562001789575b62001779576200171d620017166200255b565b91620029f9565b116200176a575060c46200173283836200299f565b9050145f14620017535762000024916200174c916200299f565b906200470d565b620000249162001763916200299f565b90620045c0565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506200179684846200299f565b905060c48202141562001703565b604051634ca8886760e01b81528390fd5b620017df9250620017d8620017e394620017cf88620038e5565b92369162000f0a565b91620039cb565b1590565b805f80620016db565b8062000993620017fc92620004a0565b5f620016b8565b346200042b5760603660031901126200042b576004356024356200182c604435828433620027e9565b91926200185a7f000000000000000000000000000000000000000000000000000000000000000082620026f4565b4210801562001a97575b801562001a8e575b62001a7c577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693620018c186620018bb620018af60d0546001600160801b031690565b6001600160801b031690565b62003572565b15620019da5762001901620018e6620018da8662003aa7565b60d05460801c62002a13565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f9162001948919062001937608082620004f2565b5190205f5260d260205260405f2090565b555f936001831162001984575b5050505062001965823362003adb565b604080519485526020850191909152830152339180606081015b0390a2005b620019cf92939450620019989088620026f4565b60408051336020820190815291810193909352606083018290529094909190620019379082608081015b03908101835282620004f2565b555f80808062001955565b620019e462003852565b62001a2562001a09620019f78662003aa7565b60d5546001600160801b031662002a13565b6001600160801b03166001600160801b031960d554161760d555565b62001a5f62001a4462001a388562003aa7565b60d55460801c62002a13565b6001600160801b0360d5549181199060801b1691161760d555565b62001a7662001a718460d654620026f4565b60d655565b62001901565b604051630e3d8e8d60e11b8152600490fd5b5082156200186c565b50811562001864565b346200042b576040806003193601126200042b576024359060043562001ac6836200067b565b62001ad062003852565b801562001c92576001600160a01b03831690811562001c815762001af48162002403565b90811562001c705762001b07826200435d565b62001b128362003aa7565b60cf5460801c9062001b249162002a13565b62001b44906001600160801b0360cf549181199060801b1691161760cf55565b62001b50823362004f04565b60d554958660801c828160d6549062001b6991620026f4565b9862001b758762003aa7565b62001b89916001600160801b031662004805565b62001baa906001600160801b03166001600160801b031960d554161760d555565b62001bb591620026f4565b62001bc09062003aa7565b62001be0906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529062001c13608082620004f2565b51902062001c29905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200042b575f3660031901126200042b576040515f6001805462001cc88162000451565b808552916020916001811690811562000624575060011462001cf757620005d685620005c981870382620004f2565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851062001d4157505050508101602001620005c982620005d6620005b6565b805486860184015293820193810162001d21565b346200042b575f3660031901126200042b57610206546020906001600160a01b039081168062001d9057508060375416905b60405191168152f35b9062001d87565b346200042b576200197f7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf62001dcd3662000cb4565b929062001dd962002dd0565b6040519182916020835233956020840191620028f5565b346200042b5760403660031901126200042b5762001e2060043562001e15816200067b565b602435903362003276565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831062001e615750505050505090565b909192939495848062001e81600193603f198682030187528a5162000537565b980193019301919493929062001e50565b346200042b5760203660031901126200042b576001600160401b036004358181116200042b57366023820112156200042b5780600401359182116200042b573660248360051b830101116200042b57620005d691602462001ef4920162002b88565b6040519182918262001e2b565b346200042b575f3660031901126200042b57620005d660405162001f2581620004ba565b60058152640352e302e360dc1b602082015260405191829160208352602083019062000537565b346200042b575f3660031901126200042b57602062000c1862002c49565b346200042b575f3660031901126200042b57602062000c1862002c81565b346200042b5760203660031901126200042b5760206200067360043562003b7a565b60ff8116036200042b57565b346200042b5760e03660031901126200042b5760043562001fd7816200067b565b60243562001fe5816200067b565b60443590606435926084359062001ffc8262001faa565b6001600160a01b038381169590929086156200072357428110620021cc576020915f91620019c2620020f889878a620020b962002038620025d0565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b0391620020cf601f1993848101835282620004f2565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa156200097d575f51928284168015908115620021be575b50620021ac576200219d8591620021887f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b556040519384521691602090a3005b6040516323389ba560e21b8152600490fd5b905083831614155f62002140565b604051631ab7da6b60e01b8152600490fd5b346200042b575f3660031901126200042b5760206001600160801b0360d05416604051908152f35b60409060031901126200042b5760043562002221816200067b565b9060243562000571816200067b565b346200042b5760206200226f620022473662002206565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346200042b5760203660031901126200042b57620000246004356200229d816200067b565b620022a762002dd0565b62003c17565b346200042b575f3660031901126200042b5760206001600160801b0360d55416604051908152f35b346200042b5760203660031901126200042b57600435620022f6816200067b565b610205805490916001600160a01b039081169082168114620007b8577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d9281602093620007a262002dd0565b346200042b5760203660031901126200042b5760043562002363816200067b565b60018060a01b03165f52610270602052602060ff60405f2054166040519015158152f35b346200042b575f3660031901126200042b576037546040516001600160a01b039091168152602090f35b602062000673620023c23662002206565b9062000a973362003c7c565b346200042b5760203660031901126200042b5762000024600435620023f3816200067b565b620023fd62002dd0565b62003c9f565b60cf546001600160801b03811690816200241c57505090565b91620005719260801c9062002d4c565b6040513d5f823e3d90fd5b908160209103126200042b575162000571816200067b565b61026f546001600160a01b03919082163303620009a1576001600160a01b0381165f90815261027060205260409020549215159260ff1615158314620024e4576001600160a01b0381165f9081526102706020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b620024f8620025009162002eea565b9190620030a2565b6200250757565b6200251162004897565b806200251b575b50565b5f906040519081525f80516020620052d283398151915260203092a3565b634e487b7160e01b5f52601160045260245ffd5b9190820391821162000bb957565b4760d0546001600160801b036200257481831662002403565b9060d55416019060801c01908181115f146200258e570390565b50505f90565b61016e546001600160a01b03168015620025ab5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003620025fe5760045490565b62000571620032fe565b359061ffff821682036200042b57565b9080601f830112156200042b57816020620005719335910162000f0a565b906020828203126200042b5781356001600160401b03928382116200042b57019060a0828203126200042b576200266c62000ebd565b92823584526200267f6020840162002608565b602085015260408301358181116200042b57826200269f91850162002618565b604085015260608301358181116200042b5782620026bf91850162002618565b606085015260808301359081116200042b57620026dd920162002618565b608082015290565b60d454806200057157505f1990565b9190820180921162000bb957565b6001600160801b0360d05416620027186200430b565b90810180911162000bb957811062002752576200274260d6546200273b6200358c565b90620026f4565b11156200274d575f90565b5f1990565b60d19060d1549182915f905b8482106200277a57505050811015620027745790565b505f1990565b909193808316906001818518811c830180931162000bb9575f8790525f80516020620052f28339815191528301546001600160a01b0316841015620027c5575050935b91906200275e565b909591019250620027bd565b908160209103126200042b57516200057181620009b3565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200282981608081015b03601f198101835282620004f2565b5190205f5260d260205260405f20549182156200289e576001600160801b0360d0541690620028576200430b565b91820180921162000bb957839183101562002889579162002878926200369b565b90915b82810390811162000bb95792565b5090620028969162003601565b90916200287b565b5050505f905f905f90565b9035601e19823603018112156200042b5701602081359101916001600160401b0382116200042b5781360383136200042b57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620005719260208152823560208201526020830135604082015262002956620029456040850185620028a9565b84606085015260c0840191620028f5565b906200298f620029836200296e6060870187620028a9565b601f19858703810160808701529591620028f5565b946080810190620028a9565b93909282860301910152620028f5565b903590601e19813603018212156200042b57018035906001600160401b0382116200042b576020019181360383136200042b57565b634e487b7160e01b5f52601260045260245ffd5b8115620029f3570490565b620029d4565b906801bc16d674ec800000918083029283040362000bb957565b6001600160801b03918216908216039190821162000bb957565b6001600160401b038111620004b45760051b60200190565b9062002a518262002a2d565b62002a606040519182620004f2565b828152809262002a73601f199162002a2d565b01905f5b82811062002a8457505050565b80606060208093850101520162002a77565b634e487b7160e01b5f52603260045260245ffd5b9082101562002ac45762000ce29160051b8101906200299f565b62002a96565b908092918237015f815290565b3d1562002b06573d9062002aeb8262000eee565b9162002afb6040519384620004f2565b82523d5f602084013e565b606090565b6020818303126200042b578051906001600160401b0382116200042b570181601f820112156200042b57805162002b428162000eee565b9262002b526040519485620004f2565b818452602082840101116200042b5762000571916020808501910162000514565b805182101562002ac45760209160051b010190565b91909162002b968362002a45565b925f5b81811062002ba657505050565b5f8062002bb583858762002aaa565b6040939162002bc985518093819362002aca565b0390305af49062002bd962002ad7565b911562002c0657509060019162002bf1828862002b73565b5262002bfe818762002b73565b500162002b99565b9060448151106200042b5762002c4562002c2f6004928381015160248091830101910162002b0b565b925162461bcd60e51b815292839283016200055e565b0390fd5b610109546001600160a01b0316806200057157507f000000000000000000000000000000000000000000000000000000000000000090565b610205546001600160a01b039081168062002c9e57506037541690565b905090565b335f5261020a60205260405f20541562002cb957565b62002cc43362003c7c565b62002518343362003ce6565b90808202905f198184099082808310920391808303921462002d4157612710908282111562002d2f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f198482099383808610950394808603951462002dc1578483111562002d2f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620005719250620029e8565b6037546001600160a01b03163303620009a157565b908160609103126200042b57805191604060208301519201516200057181620009b3565b81835290916001600160fb1b0383116200042b5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200042b576040830152604081013562002e60816200067b565b6001600160a01b031660608381019190915281013536829003601e19018112156200042b5701602081359101906001600160401b0381116200042b578060051b360382136200042b5760a08360808062000571960152019162002e09565b908160209103126200042b575190565b9190915f838201938412911290801582169115161762000bb957565b6040516325f56f1160e01b81526001600160a01b0392916060908290819062002f17906004830162002e2e565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156200097d575f915f905f9562003055575b50841562002ffa578162002f6662002594565b16917f000000000000000000000000000000000000000000000000000000000000000016821462002ff257509060205f92600460405180958193634641257d60e01b83525af19081156200097d5762002fc8925f9262002fcc575b5062002ece565b9190565b62002fea91925060203d602011620011d457620011c48183620004f2565b905f62002fc1565b908162003000575b50509190565b803b156200042b57604051636ee3193160e11b815260048101929092525f908290602490829084905af180156200097d576200303e575b8062002ffa565b80620009936200304e92620004a0565b5f62003037565b9194505062003080915060603d60601162003089575b620030778183620004f2565b81019062002de5565b93905f62002f53565b503d6200306b565b600160ff1b811462000bb9575f0390565b80156200251857620030ba620018af60cf5460801c90565b5f8212620031ba5781620030ce91620026f4565b90620030f9620030de8362003aa7565b6001600160801b0360cf549181199060801b1691161760cf55565b62003110609c549161ffff8360a01c169062002cd0565b8015620024e457807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362003151620018af60cf546001600160801b031690565b80620031a05750506200319b90925b6001600160a01b03169162003176848462004821565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6200319b92620031b39203908462002d4c565b9262003160565b90620031c69062003091565b620031dd620018af60d5546001600160801b031690565b8062003209575b5080620031ef575050565b62003203620030de9162000eec936200254d565b62003aa7565b906200326c7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916200325c62001a0962003250620032488888620026f4565b878562002d4c565b80809403960362003aa7565b6040519081529081906020820190565b0390a15f620031e4565b90620032828262003c7c565b6200328d8162003c7c565b6001600160a01b039182169182158015620032f3575b6200072357825f5260d360205260405f209081549285840393841162000bb9575f80516020620052d283398151915293602093551693845f5260d3825260405f20818154019055604051908152a3565b5080821615620032a3565b6040515f905f5490620033118262000451565b9283825260209384830193600190866001821691825f1462003411575050600114620033c9575b5050918162003352620033c3936200281a950382620004f2565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020620052928339815191525b828410620033fb57505050820101816200335262003338565b80548685018601528794909301928101620033e2565b60ff1916875292151560051b8501909201925083915062003352905062003338565b91906200343f62003f56565b6080820151906200344f62003f56565b6001600160a01b03841680156200072357620034fc94620034eb93620034cf926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280620034bc3394602083019062000537565b0390a2602085015161ffff169062003f98565b620034db835162003fee565b620034e562004022565b62004056565b606060408201519101519062004088565b62000eec620041d1565b62000eec90620023fd62003f56565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562003555575b50506200126857565b5f80516020620052b28339815191525416141590505f806200354c565b906200357d6200430b565b91820180921162000bb9571090565b4760d0548060801c820391821162000bb95781620035b46001600160801b0380931662002403565b9081620035e0575b505081156200258e576200057191620035da9160d55416906200434f565b6200435d565b9192509081811115620035f857035b905f80620035bc565b50505f620035ef565b6200360b6200358c565b9160d65492830180931162000bb957808311156200365c57620036309203906200434f565b9060d5548060801c80155f14620036475750508190565b6001600160801b036200057192168462002d4c565b5050505f905f90565b90604051604081018181106001600160401b03821117620004b45760405291546001600160a01b038116835260a01c6020830152565b60d1545f94859493909180841080159062003849575b6200383c578362003805575f5b60d15f526001600160a01b0316620036e65f80516020620052f2833981519152860162003665565b8051909790620036ff906001600160a01b0316620007ea565b98620037266200371a6020809b01516001600160601b031690565b6001600160601b031690565b948381108015620037fa575b620037e85791600193979a956200375562003762939488035b838c03906200434f565b8092019887039162002d4c565b01970193808611801590620037dd575b620037d25760d15f528290620037985f80516020620052f2833981519152870162003665565b805190890151969992966001600160a01b039091169460019392620037629290916001600160601b0390911690620037559088036200374b565b945050509250509190565b508185101562003772565b60405163e8722f8f60e01b8152600490fd5b50808b111562003732565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316620036be565b505093505050505f905f90565b508415620036b1565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156200097d575f91620038c1575b50620038af57565b60405163e775715160e01b8152600490fd5b620038de915060203d602011620010de57620010cd8183620004f2565b5f620038a7565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200399b5761010a54905b620039316200392960408301836200299f565b369162000f0a565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526200397e81620004d6565b5190206040519161190160f01b8352600283015260228201522090565b620039a562004399565b9062003916565b60041115620039b757565b634e487b7160e01b5f52602160045260245ffd5b620039d7838362004469565b50620039e681959295620039ac565b15938462003a90575b508315620039fe575b50505090565b5f92935090829160405162003a39816200281a6020820194630b135d3f60e11b998a8752602484015260406044840152606483019062000537565b51915afa9062003a4862002ad7565b8262003a81575b8262003a61575b50505f8080620039f8565b62003a789192506020808251830101910162002ebe565b145f8062003a56565b91506020825110159162003a4f565b6001600160a01b0383811691161493505f620039ef565b6001600160801b039081811162003abc571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541462003b68576002835581471062003b50575f918291829182916001600160a01b03165af162003b3162002ad7565b501562003b3e5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b0382168115801562003bad575b1562003b9e5750905090565b620005719260801c9162002d4c565b50801562003b92565b60cf546001600160801b038116908215801562003c0e575b1562003bd957505090565b60801c9062003bea82828562002d4c565b928215620029f3570962003bfb5790565b6001810180911115620005715762002539565b50811562003bce565b62003c2162003852565b6001600160a01b0316801562003c6a57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610270602052604090205460ff1615620009a157565b61026f80546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b919062003cf262003852565b6001600160a01b0383169081156200072357801562003dac578062003d1d620018af60cf5460801c90565b019362003d29620026e5565b851162003d9a57620030de9462003d589162003d5262003d498562003bb6565b97889362003aa7565b62004821565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b9092919262003dcc62003852565b6001600160a01b0382169182156200072357811562003dac578162003df7620018af60cf5460801c90565b0162003e02620026e5565b811162003d9a57620030de9562003e5162003d95927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003d5262003e488862003bb6565b9a8b9362003aa7565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f526102088060205260405f2054155f146200258e576102078054600160401b811015620004b4576001810180835581101562002ac45783907f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2015554915f5260205260405f2055600190565b805f5261020a8060205260405f2054155f146200258e576102098054600160401b811015620004b4576001810180835581101562002ac45783907f99e87348be6dc95028197b5a6b69c6a7a15df569de2f3d37542e8f40b8bae486015554915f5260205260405f2055600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562003f8657565b604051631afcd79f60e31b8152600490fd5b62003fa262003f56565b61271061ffff83161162003fdc5762003fbb9062003c17565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b62003ff862003f56565b80156200401057600181016200400b5750565b60d455565b6040516331278a8760e01b8152600490fd5b6200402c62003f56565b6801bc16d674ec80000062004040620026e5565b1062004010576200405062004399565b61010a55565b6200406062003f56565b6001600160a01b031680620040725750565b61016e80546001600160a01b0319169091179055565b6200409262003f56565b601e8151118015620041c5575b620041b357620040ae62003f56565b8051906001600160401b038211620004b457620040d782620040d15f5462000451565b620049de565b602090816001601f851114620041385750918062004111926200411995945f926200412c575b50508160011b915f199060031b1c19161790565b5f5562004ab3565b62000eec62004127620032fe565b600455565b015190505f80620040fd565b5f80529190601f1984165f8051602062005292833981519152935f905b8282106200419a575050916001939185620041199796941062004181575b505050811b015f5562004ab3565b01515f1960f88460031b161c191690555f808062004173565b8060018697829497870151815501960194019062004155565b604051632d3f993760e21b8152600490fd5b50600a8251116200409f565b620041db62003f56565b620041e562003f56565b620041ef62003f56565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca0034106200422b5762002518343062003ce6565b60405163ea2559bb60e01b8152600490fd5b908160209103126200042b5751620005718162001faa565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481620042e5575b50620042a757604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020620052b28339815191528403620042cc5762000eec92935062004b9e565b604051632a87526960e21b815260048101859052602490fd5b6200430391955060203d602011620011d457620011c48183620004f2565b935f62004280565b60d154806200431957505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316620007ea565b908082101562002c9e575090565b60d554908160801c8115801562004390575b156200437b5750905090565b6001600160801b036200057193169162002d4c565b5080156200436f565b6e5661756c7456616c696461746f727360881b6020604051620043bc81620004ba565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117620004b45760405251902090565b81519190604183036200449c57620044959250602082015190606060408401519301515f1a9062004c46565b9192909190565b50505f9160029190565b906030116200042b5790603090565b909291928360b0116200042b5783116200042b5760b0019160af190190565b906090116200042b5760300190606090565b9060c4116200042b5760900190603490565b909392938483116200042b5784116200042b578101920390565b35906020811062004521575090565b5f199060200360031b1b1690565b959493620045616200457093620045526060969460808b5260808b0190620028dd565b9089820360208b015262000537565b918783036040890152620028f5565b930152565b9695949062004570936200455262004561926060979560808c5260808c0191620028f5565b90602062000571928181520190620028dd565b91602062000571938181520191620028f5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062004609575050505050505050565b826200461a910180928787620044f8565b90620046278282620044a6565b916200464062004639858084620044b5565b9062004cde565b90620046656200465e620046558784620044d4565b979093620044e6565b9062004512565b948c3b156200042b578c5f926801bc16d674ec800000604095620046a187519a8b96879586946304512a2360e31b86528d8d6004880162004575565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194620046e692620046f6575b505192839283620045ad565b0390a160018193019290620045f7565b80620009936200470692620004a0565b5f620046da565b816030116200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916200475262004639828085620044b5565b6200475e8284620044d4565b94909260b0116200042b57803b156200042b57620047a7946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b600487016200452f565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926200319b92620047ee575b50604051918291826200459a565b8062000993620047fe92620004a0565b5f620047e0565b9190916001600160801b038080941691160191821162000bb957565b5f80516020620052d283398151915260205f926200483f8562003aa7565b60cf5490620048596001600160801b039182841662004805565b6fffffffffffffffffffffffffffffffff1990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b038216918215620049d85760801c620048d2620048c082476200254d565b620048cb8562002403565b906200434f565b908115620049d157620048e58262003b7a565b938415620049c957826200493e620018e66200320362000eec96620030de96620049386200491c620032038d620049bd9a6200254d565b6001600160801b03166001600160801b031960d054161760d055565b620026f4565b6200494a818762004e00565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162003203620049a16200498f8862003aa7565b60cf546001600160801b031662002a13565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c62002a13565b505f93505050565b505f925050565b505f9150565b601f8111620049eb575050565b5f80525f8051602062005292833981519152906020601f840160051c8301931062004a32575b601f0160051c01905b81811062004a26575050565b5f815560010162004a1a565b909150819062004a11565b90601f821162004a4b575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931062004aa8575b601f0160051c01905b81811062004a9d57505050565b5f8155820162004a90565b909150819062004a87565b9081516001600160401b038111620004b45760019062004adf8162004ad9845462000451565b62004a3d565b602080601f831160011462004b175750819062004b139394955f926200412c5750508160011b915f199060031b1c19161790565b9055565b90601f1983169562004b4a60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821062004b86575050838596971062004b6d575b505050811b019055565b01515f1960f88460031b161c191690555f808062004b63565b80878596829496860151815501950193019062004b4e565b90813b1562004c25575f80516020620052b283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562004c0957620025189162004ee3565b50503462004c1357565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162004cd3579062004ca16020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156200097d575f516001600160a01b0381161562004cc957905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362004d92576bffffffffffffffffffffffff19919035828116916014811062004d7c575b5050905060601c62004d28620017df825f5261020860205260405f2054151590565b62004d6a5760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c8301526200057190829081016200281a565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004d06565b604051639be7315960e01b8152600490fd5b60d15490600160401b821015620004b457600182018060d15582101562002ac45760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020620052f283398151915290910155565b9190918015801562004eda575b62004ec85762004e1c6200430b565b90810180911162000bb9576001600160a01b0380821162004ea8576001600160601b039081851162004e88579062000eec939462004e7162004e829362004e6262000edd565b95166001600160a01b03168552565b166001600160601b03166020830152565b62004da4565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562004e0d565b5f806200057193602081519101845af462004efd62002ad7565b9162004f73565b6001600160a01b03165f81815260d36020526040902080548381039190821162000bb9575f935f80516020620052d2833981519152926020925562004f498162003aa7565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b9062004f8a575080511562003b3e57805190602001fd5b8151158062004fbf575b62004f9d575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562004f9456fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c63430008160033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a264697066735822122001b3bd813422a1da22237ac6d5a0a6c0b2c53c6871ce454c434c474b90bc284764736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101562000026575b36156200001a575f80fd5b6200002462002ca3565b005b5f3560e01c806301e1d114146200041a57806306fdde03146200041457806307a2d13a146200040e578063095ea7b31462000408578063096ae80d14620004025780630b10b20114620003fc5780630d392cd914620003f657806318160ddd14620003ba57806318f7295014620003f05780631a7ff55314620003ea57806322758a4a14620003e457806323b872dd14620003de5780632cdf740114620003d8578063313ce56714620003d25780633229fa9514620003cc57806333194c0a14620003c65780633644e51514620003c05780633a98ef3914620003ba578063439fab9114620003b45780634690484014620003ae5780634f1ef28614620003a857806352d1902d14620003a257806353156f28146200039c57806354fd4d5014620003965780635c60da1b14620003905780635cfc1a51146200038a57806360d60e6e146200038457806370a0823114620002f457806372b410a8146200037e578063754c3888146200037857806376b58b9014620003725780637b6341c6146200036c5780637ecebe0014620003665780637fd6f15c146200036057806383d430d5146200035a5780638697d2c214620003545780638ceab9aa146200034e57806395d89b411462000348578063a045dd0c1462000342578063a49a1e7d146200033c578063a9059cbb1462000336578063ac9650d81462000330578063ad3cb1cc146200032a578063b1f0e7c71462000324578063c5aecb22146200031e578063c6e6f5921462000318578063d505accf1462000312578063d83ad00c146200030c578063dd62ed3e1462000306578063e74b981b1462000300578063ee3bd5df14620002fa578063f04da65b14620002f4578063f132f5d314620002ee578063f6a6830f14620002e8578063f851a44014620002e2578063f9609f0814620002dc5763f98f5b92036200000f57620023ce565b620023b1565b62002387565b62002342565b620022d5565b62001336565b620022ad565b62002278565b62002230565b620021de565b62001fb6565b62001f88565b62001f6a565b62001f4c565b62001f01565b62001e92565b62001df0565b62001d97565b62001d55565b62001ca3565b62001aa0565b62001803565b620015fe565b620015d8565b62001599565b620014d5565b6200147d565b6200140b565b62001375565b62001314565b620012f6565b620012bf565b620012a2565b6200127a565b6200120d565b62000f45565b62000e93565b62000ce6565b620009f8565b62000c66565b62000c2a565b62000bfa565b62000bdd565b62000bbf565b62000b0e565b62000ae3565b62000aaa565b62000a2f565b620009be565b620007ca565b62000735565b6200068d565b62000651565b62000574565b6200042f565b5f9103126200042b57565b5f80fd5b346200042b575f3660031901126200042b57602060cf5460801c604051908152f35b90600182811c9216801562000481575b60208310146200046d57565b634e487b7160e01b5f52602260045260245ffd5b91607f169162000461565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111620004b457604052565b6200048c565b604081019081106001600160401b03821117620004b457604052565b608081019081106001600160401b03821117620004b457604052565b90601f801991011681019081106001600160401b03821117620004b457604052565b5f5b838110620005265750505f910152565b818101518382015260200162000516565b90602091620005528151809281855285808601910162000514565b601f01601f1916010190565b9060206200057192818152019062000537565b90565b346200042b575f3660031901126200042b576040515f8054620005978162000451565b80845290602090600190818116908115620006245750600114620005da575b620005d685620005c981870382620004f2565b604051918291826200055e565b0390f35b5f80805293505f80516020620052928339815191525b8385106200061057505050508101602001620005c982620005d6620005b6565b8054868601840152938201938101620005f0565b869550620005d696935060209250620005c994915060ff191682840152151560051b8201019293620005b6565b346200042b5760203660031901126200042b5760206200067360043562002403565b604051908152f35b6001600160a01b038116036200042b57565b346200042b5760403660031901126200042b57600435620006ae816200067b565b6001600160a01b038116906024359082156200072357620006eb8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b346200042b5760203660031901126200042b5760043562000756816200067b565b610206805490916001600160a01b039081169082168114620007b8577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e89281602093620007a262002dd0565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200042b575f3660031901126200042b57620007f6620007ea62002c81565b6001600160a01b031690565b3303620009a1576040516102c8808201908282106001600160401b03831117620004b4578291620008679162004fca84396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff080156200097d576001600160a01b0390811690813b156200042b5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af180156200097d5762000983575b506040516351d5709b60e11b815291602083600481845afa9182156200097d577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f9362000940575b506200090f90831662003e7a565b506200091b8162003ee8565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200090f9193506200096d9060203d60201162000975575b620009648183620004f2565b81019062002437565b929062000901565b503d62000958565b6200242c565b80620009936200099a92620004a0565b8062000420565b5f620008b7565b604051634ca8886760e01b8152600490fd5b801515036200042b57565b346200042b5760403660031901126200042b5762000024600435620009e3816200067b565b60243590620009f282620009b3565b6200244f565b346200042b575f3660031901126200042b5760206001600160801b0360cf5416604051908152f35b908160809103126200042b5790565b60603660031901126200042b5760043562000a4a816200067b565b60243562000a58816200067b565b604435906001600160401b0382116200042b5760209262000a8c62000a866200067394369060040162000a20565b620024e9565b62000a973362003c7c565b62000aa28162003c7c565b349062003dbe565b346200042b5760203660031901126200042b576004356001600160401b0381116200042b5762000a866200002491369060040162000a20565b346200042b575f3660031901126200042b5761026f546040516001600160a01b039091168152602090f35b346200042b5760603660031901126200042b5760043562000b2f816200067b565b60243562000b3d816200067b565b6001600160a01b0382165f818152600260209081526040808320338452909152902090926044359291546001810162000b8a575b5062000b7e935062003276565b60405160018152602090f35b83810390811162000bb9575f94855260026020908152604080872033885290915285205562000b7e9362000b71565b62002539565b346200042b575f3660031901126200042b576020620006736200255b565b346200042b575f3660031901126200042b57602060405160128152f35b346200042b575f3660031901126200042b57602062000c1862002594565b6040516001600160a01b039091168152f35b346200042b575f3660031901126200042b5760206040517f737a47bb3e695a159ef397f75d47c2ca71c770e380ac29b104d3b82ee61be3c88152f35b346200042b575f3660031901126200042b57602062000673620025d0565b9181601f840112156200042b578235916001600160401b0383116200042b57602083818601950101116200042b57565b60206003198201126200042b57600435906001600160401b0382116200042b5762000ce29160040162000c84565b9091565b62000cf13662000cb4565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16801562000e7e575b62000e6c5768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156200097d575f9362000e48575b50604051636f4fa30f60e01b8152938285600481335afa9081156200097d5762000dba9562000db4945f9362000e1f575b505062000dac919281019062002636565b908362003433565b62003506565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016200093b565b62000dac9350908162000e4092903d106200097557620009648183620004f2565b915f62000d9b565b62000e64919350823d84116200097557620009648183620004f2565b915f62000d6a565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101562000d23565b346200042b575f3660031901126200042b57609c546040516001600160a01b039091168152602090f35b6040519060a082018281106001600160401b03821117620004b457604052565b6040519062000eec82620004ba565b565b6001600160401b038111620004b457601f01601f191660200190565b92919262000f188262000eee565b9162000f286040519384620004f2565b8294818452818301116200042b578281602093845f960137010152565b6040806003193601126200042b57600490813562000f63816200067b565b6024356001600160401b0381116200042b57366023820112156200042b5762000f96903690602481870135910162000f0a565b9162000fa162003515565b80519262000fdc8462000fcd60209363439fab9160e01b85840152846024840152604483019062000537565b03601f198101865285620004f2565b62000fe662003515565b62000ff062002dd0565b6001600160a01b03838116801592919087908415620011dc575b841562001154575b8415620010e6575b5050821562001046575b5050620010375762000024838362004255565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156200097d575f92620010b2575b5050155f8062001024565b620010d69250803d10620010de575b620010cd8183620004f2565b810190620027d1565b5f80620010a7565b503d620010c1565b855163054fd4d560e41b81529294508391839182905afa9081156200097d5760039160ff915f9162001120575b5016141591865f6200101a565b620011459150843d86116200114c575b6200113c8183620004f2565b8101906200423d565b5f62001113565b503d62001130565b935050835163198ca60560e11b815282818981875afa9081156200097d5788917f737a47bb3e695a159ef397f75d47c2ca71c770e380ac29b104d3b82ee61be3c8915f91620011a8575b5014159362001012565b620011cd9150853d8711620011d4575b620011c48183620004f2565b81019062002ebe565b5f6200119e565b503d620011b8565b5f80516020620052b283398151915254909450849062001205906001600160a01b0316620007ea565b14936200100a565b346200042b575f3660031901126200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620012685760206040515f80516020620052b28339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200042b576001600160a01b036200129862002594565b163303620009a157005b346200042b575f3660031901126200042b57602060405160028152f35b346200042b575f3660031901126200042b575f80516020620052b2833981519152546040516001600160a01b039091168152602090f35b346200042b575f3660031901126200042b57602062000673620026e5565b346200042b5760203660031901126200042b5760206200067360043562002702565b346200042b5760203660031901126200042b5760043562001357816200067b565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156200097d576020915f91620013e9575b506040519015158152f35b620014049150823d8411620010de57620010cd8183620004f2565b5f620013de565b346200042b5760203660031901126200042b576004356200142c816200067b565b6200143662002dd0565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200042b5760803660031901126200042b57620005d6620014b8600435620014a6816200067b565b606435906044359060243590620027e9565b604080519384526020840192909252908201529081906060820190565b346200042b575f3660031901126200042b5760405180610207805480845260208094019081925f527f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2905f5b86828210620015845786866200153a82880383620004f2565b60405192839281840190828552518091526040840192915f5b8281106200156357505050500390f35b83516001600160a01b03168552869550938101939281019260010162001553565b83548552909301926001928301920162001521565b346200042b5760203660031901126200042b57600435620015ba816200067b565b60018060a01b03165f526003602052602060405f2054604051908152f35b346200042b575f3660031901126200042b57602061ffff609c5460a01c16604051908152f35b346200042b576003196040368201126200042b5760049081356001600160401b038082116200042b5760a08285019383360301126200042b576024359081116200042b5762001651903690850162000c84565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200042b5760405163837d444160e01b8152905f908290818381620016a78c828f0162002915565b03925af180156200097d57620017ec575b50620016c362003852565b620016cd62002c49565b9081163314159182620017b5575b50509050620017a4576044019160c4620016f684846200299f565b9050048015801562001789575b62001779576200171d620017166200255b565b91620029f9565b116200176a575060c46200173283836200299f565b9050145f14620017535762000024916200174c916200299f565b906200470d565b620000249162001763916200299f565b90620045c0565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506200179684846200299f565b905060c48202141562001703565b604051634ca8886760e01b81528390fd5b620017df9250620017d8620017e394620017cf88620038e5565b92369162000f0a565b91620039cb565b1590565b805f80620016db565b8062000993620017fc92620004a0565b5f620016b8565b346200042b5760603660031901126200042b576004356024356200182c604435828433620027e9565b91926200185a7f000000000000000000000000000000000000000000000000000000000000000082620026f4565b4210801562001a97575b801562001a8e575b62001a7c577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693620018c186620018bb620018af60d0546001600160801b031690565b6001600160801b031690565b62003572565b15620019da5762001901620018e6620018da8662003aa7565b60d05460801c62002a13565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f9162001948919062001937608082620004f2565b5190205f5260d260205260405f2090565b555f936001831162001984575b5050505062001965823362003adb565b604080519485526020850191909152830152339180606081015b0390a2005b620019cf92939450620019989088620026f4565b60408051336020820190815291810193909352606083018290529094909190620019379082608081015b03908101835282620004f2565b555f80808062001955565b620019e462003852565b62001a2562001a09620019f78662003aa7565b60d5546001600160801b031662002a13565b6001600160801b03166001600160801b031960d554161760d555565b62001a5f62001a4462001a388562003aa7565b60d55460801c62002a13565b6001600160801b0360d5549181199060801b1691161760d555565b62001a7662001a718460d654620026f4565b60d655565b62001901565b604051630e3d8e8d60e11b8152600490fd5b5082156200186c565b50811562001864565b346200042b576040806003193601126200042b576024359060043562001ac6836200067b565b62001ad062003852565b801562001c92576001600160a01b03831690811562001c815762001af48162002403565b90811562001c705762001b07826200435d565b62001b128362003aa7565b60cf5460801c9062001b249162002a13565b62001b44906001600160801b0360cf549181199060801b1691161760cf55565b62001b50823362004f04565b60d554958660801c828160d6549062001b6991620026f4565b9862001b758762003aa7565b62001b89916001600160801b031662004805565b62001baa906001600160801b03166001600160801b031960d554161760d555565b62001bb591620026f4565b62001bc09062003aa7565b62001be0906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529062001c13608082620004f2565b51902062001c29905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200042b575f3660031901126200042b576040515f6001805462001cc88162000451565b808552916020916001811690811562000624575060011462001cf757620005d685620005c981870382620004f2565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851062001d4157505050508101602001620005c982620005d6620005b6565b805486860184015293820193810162001d21565b346200042b575f3660031901126200042b57610206546020906001600160a01b039081168062001d9057508060375416905b60405191168152f35b9062001d87565b346200042b576200197f7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf62001dcd3662000cb4565b929062001dd962002dd0565b6040519182916020835233956020840191620028f5565b346200042b5760403660031901126200042b5762001e2060043562001e15816200067b565b602435903362003276565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831062001e615750505050505090565b909192939495848062001e81600193603f198682030187528a5162000537565b980193019301919493929062001e50565b346200042b5760203660031901126200042b576001600160401b036004358181116200042b57366023820112156200042b5780600401359182116200042b573660248360051b830101116200042b57620005d691602462001ef4920162002b88565b6040519182918262001e2b565b346200042b575f3660031901126200042b57620005d660405162001f2581620004ba565b60058152640352e302e360dc1b602082015260405191829160208352602083019062000537565b346200042b575f3660031901126200042b57602062000c1862002c49565b346200042b575f3660031901126200042b57602062000c1862002c81565b346200042b5760203660031901126200042b5760206200067360043562003b7a565b60ff8116036200042b57565b346200042b5760e03660031901126200042b5760043562001fd7816200067b565b60243562001fe5816200067b565b60443590606435926084359062001ffc8262001faa565b6001600160a01b038381169590929086156200072357428110620021cc576020915f91620019c2620020f889878a620020b962002038620025d0565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b0391620020cf601f1993848101835282620004f2565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa156200097d575f51928284168015908115620021be575b50620021ac576200219d8591620021887f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b556040519384521691602090a3005b6040516323389ba560e21b8152600490fd5b905083831614155f62002140565b604051631ab7da6b60e01b8152600490fd5b346200042b575f3660031901126200042b5760206001600160801b0360d05416604051908152f35b60409060031901126200042b5760043562002221816200067b565b9060243562000571816200067b565b346200042b5760206200226f620022473662002206565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346200042b5760203660031901126200042b57620000246004356200229d816200067b565b620022a762002dd0565b62003c17565b346200042b575f3660031901126200042b5760206001600160801b0360d55416604051908152f35b346200042b5760203660031901126200042b57600435620022f6816200067b565b610205805490916001600160a01b039081169082168114620007b8577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d9281602093620007a262002dd0565b346200042b5760203660031901126200042b5760043562002363816200067b565b60018060a01b03165f52610270602052602060ff60405f2054166040519015158152f35b346200042b575f3660031901126200042b576037546040516001600160a01b039091168152602090f35b602062000673620023c23662002206565b9062000a973362003c7c565b346200042b5760203660031901126200042b5762000024600435620023f3816200067b565b620023fd62002dd0565b62003c9f565b60cf546001600160801b03811690816200241c57505090565b91620005719260801c9062002d4c565b6040513d5f823e3d90fd5b908160209103126200042b575162000571816200067b565b61026f546001600160a01b03919082163303620009a1576001600160a01b0381165f90815261027060205260409020549215159260ff1615158314620024e4576001600160a01b0381165f9081526102706020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b620024f8620025009162002eea565b9190620030a2565b6200250757565b6200251162004897565b806200251b575b50565b5f906040519081525f80516020620052d283398151915260203092a3565b634e487b7160e01b5f52601160045260245ffd5b9190820391821162000bb957565b4760d0546001600160801b036200257481831662002403565b9060d55416019060801c01908181115f146200258e570390565b50505f90565b61016e546001600160a01b03168015620025ab5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003620025fe5760045490565b62000571620032fe565b359061ffff821682036200042b57565b9080601f830112156200042b57816020620005719335910162000f0a565b906020828203126200042b5781356001600160401b03928382116200042b57019060a0828203126200042b576200266c62000ebd565b92823584526200267f6020840162002608565b602085015260408301358181116200042b57826200269f91850162002618565b604085015260608301358181116200042b5782620026bf91850162002618565b606085015260808301359081116200042b57620026dd920162002618565b608082015290565b60d454806200057157505f1990565b9190820180921162000bb957565b6001600160801b0360d05416620027186200430b565b90810180911162000bb957811062002752576200274260d6546200273b6200358c565b90620026f4565b11156200274d575f90565b5f1990565b60d19060d1549182915f905b8482106200277a57505050811015620027745790565b505f1990565b909193808316906001818518811c830180931162000bb9575f8790525f80516020620052f28339815191528301546001600160a01b0316841015620027c5575050935b91906200275e565b909591019250620027bd565b908160209103126200042b57516200057181620009b3565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200282981608081015b03601f198101835282620004f2565b5190205f5260d260205260405f20549182156200289e576001600160801b0360d0541690620028576200430b565b91820180921162000bb957839183101562002889579162002878926200369b565b90915b82810390811162000bb95792565b5090620028969162003601565b90916200287b565b5050505f905f905f90565b9035601e19823603018112156200042b5701602081359101916001600160401b0382116200042b5781360383136200042b57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620005719260208152823560208201526020830135604082015262002956620029456040850185620028a9565b84606085015260c0840191620028f5565b906200298f620029836200296e6060870187620028a9565b601f19858703810160808701529591620028f5565b946080810190620028a9565b93909282860301910152620028f5565b903590601e19813603018212156200042b57018035906001600160401b0382116200042b576020019181360383136200042b57565b634e487b7160e01b5f52601260045260245ffd5b8115620029f3570490565b620029d4565b906801bc16d674ec800000918083029283040362000bb957565b6001600160801b03918216908216039190821162000bb957565b6001600160401b038111620004b45760051b60200190565b9062002a518262002a2d565b62002a606040519182620004f2565b828152809262002a73601f199162002a2d565b01905f5b82811062002a8457505050565b80606060208093850101520162002a77565b634e487b7160e01b5f52603260045260245ffd5b9082101562002ac45762000ce29160051b8101906200299f565b62002a96565b908092918237015f815290565b3d1562002b06573d9062002aeb8262000eee565b9162002afb6040519384620004f2565b82523d5f602084013e565b606090565b6020818303126200042b578051906001600160401b0382116200042b570181601f820112156200042b57805162002b428162000eee565b9262002b526040519485620004f2565b818452602082840101116200042b5762000571916020808501910162000514565b805182101562002ac45760209160051b010190565b91909162002b968362002a45565b925f5b81811062002ba657505050565b5f8062002bb583858762002aaa565b6040939162002bc985518093819362002aca565b0390305af49062002bd962002ad7565b911562002c0657509060019162002bf1828862002b73565b5262002bfe818762002b73565b500162002b99565b9060448151106200042b5762002c4562002c2f6004928381015160248091830101910162002b0b565b925162461bcd60e51b815292839283016200055e565b0390fd5b610109546001600160a01b0316806200057157507f000000000000000000000000000000000000000000000000000000000000000090565b610205546001600160a01b039081168062002c9e57506037541690565b905090565b335f5261020a60205260405f20541562002cb957565b62002cc43362003c7c565b62002518343362003ce6565b90808202905f198184099082808310920391808303921462002d4157612710908282111562002d2f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f198482099383808610950394808603951462002dc1578483111562002d2f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620005719250620029e8565b6037546001600160a01b03163303620009a157565b908160609103126200042b57805191604060208301519201516200057181620009b3565b81835290916001600160fb1b0383116200042b5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200042b576040830152604081013562002e60816200067b565b6001600160a01b031660608381019190915281013536829003601e19018112156200042b5701602081359101906001600160401b0381116200042b578060051b360382136200042b5760a08360808062000571960152019162002e09565b908160209103126200042b575190565b9190915f838201938412911290801582169115161762000bb957565b6040516325f56f1160e01b81526001600160a01b0392916060908290819062002f17906004830162002e2e565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156200097d575f915f905f9562003055575b50841562002ffa578162002f6662002594565b16917f000000000000000000000000000000000000000000000000000000000000000016821462002ff257509060205f92600460405180958193634641257d60e01b83525af19081156200097d5762002fc8925f9262002fcc575b5062002ece565b9190565b62002fea91925060203d602011620011d457620011c48183620004f2565b905f62002fc1565b908162003000575b50509190565b803b156200042b57604051636ee3193160e11b815260048101929092525f908290602490829084905af180156200097d576200303e575b8062002ffa565b80620009936200304e92620004a0565b5f62003037565b9194505062003080915060603d60601162003089575b620030778183620004f2565b81019062002de5565b93905f62002f53565b503d6200306b565b600160ff1b811462000bb9575f0390565b80156200251857620030ba620018af60cf5460801c90565b5f8212620031ba5781620030ce91620026f4565b90620030f9620030de8362003aa7565b6001600160801b0360cf549181199060801b1691161760cf55565b62003110609c549161ffff8360a01c169062002cd0565b8015620024e457807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362003151620018af60cf546001600160801b031690565b80620031a05750506200319b90925b6001600160a01b03169162003176848462004821565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6200319b92620031b39203908462002d4c565b9262003160565b90620031c69062003091565b620031dd620018af60d5546001600160801b031690565b8062003209575b5080620031ef575050565b62003203620030de9162000eec936200254d565b62003aa7565b906200326c7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916200325c62001a0962003250620032488888620026f4565b878562002d4c565b80809403960362003aa7565b6040519081529081906020820190565b0390a15f620031e4565b90620032828262003c7c565b6200328d8162003c7c565b6001600160a01b039182169182158015620032f3575b6200072357825f5260d360205260405f209081549285840393841162000bb9575f80516020620052d283398151915293602093551693845f5260d3825260405f20818154019055604051908152a3565b5080821615620032a3565b6040515f905f5490620033118262000451565b9283825260209384830193600190866001821691825f1462003411575050600114620033c9575b5050918162003352620033c3936200281a950382620004f2565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020620052928339815191525b828410620033fb57505050820101816200335262003338565b80548685018601528794909301928101620033e2565b60ff1916875292151560051b8501909201925083915062003352905062003338565b91906200343f62003f56565b6080820151906200344f62003f56565b6001600160a01b03841680156200072357620034fc94620034eb93620034cf926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280620034bc3394602083019062000537565b0390a2602085015161ffff169062003f98565b620034db835162003fee565b620034e562004022565b62004056565b606060408201519101519062004088565b62000eec620041d1565b62000eec90620023fd62003f56565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562003555575b50506200126857565b5f80516020620052b28339815191525416141590505f806200354c565b906200357d6200430b565b91820180921162000bb9571090565b4760d0548060801c820391821162000bb95781620035b46001600160801b0380931662002403565b9081620035e0575b505081156200258e576200057191620035da9160d55416906200434f565b6200435d565b9192509081811115620035f857035b905f80620035bc565b50505f620035ef565b6200360b6200358c565b9160d65492830180931162000bb957808311156200365c57620036309203906200434f565b9060d5548060801c80155f14620036475750508190565b6001600160801b036200057192168462002d4c565b5050505f905f90565b90604051604081018181106001600160401b03821117620004b45760405291546001600160a01b038116835260a01c6020830152565b60d1545f94859493909180841080159062003849575b6200383c578362003805575f5b60d15f526001600160a01b0316620036e65f80516020620052f2833981519152860162003665565b8051909790620036ff906001600160a01b0316620007ea565b98620037266200371a6020809b01516001600160601b031690565b6001600160601b031690565b948381108015620037fa575b620037e85791600193979a956200375562003762939488035b838c03906200434f565b8092019887039162002d4c565b01970193808611801590620037dd575b620037d25760d15f528290620037985f80516020620052f2833981519152870162003665565b805190890151969992966001600160a01b039091169460019392620037629290916001600160601b0390911690620037559088036200374b565b945050509250509190565b508185101562003772565b60405163e8722f8f60e01b8152600490fd5b50808b111562003732565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316620036be565b505093505050505f905f90565b508415620036b1565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156200097d575f91620038c1575b50620038af57565b60405163e775715160e01b8152600490fd5b620038de915060203d602011620010de57620010cd8183620004f2565b5f620038a7565b604290467f0000000000000000000000000000000000000000000000000000000000000000036200399b5761010a54905b620039316200392960408301836200299f565b369162000f0a565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526200397e81620004d6565b5190206040519161190160f01b8352600283015260228201522090565b620039a562004399565b9062003916565b60041115620039b757565b634e487b7160e01b5f52602160045260245ffd5b620039d7838362004469565b50620039e681959295620039ac565b15938462003a90575b508315620039fe575b50505090565b5f92935090829160405162003a39816200281a6020820194630b135d3f60e11b998a8752602484015260406044840152606483019062000537565b51915afa9062003a4862002ad7565b8262003a81575b8262003a61575b50505f8080620039f8565b62003a789192506020808251830101910162002ebe565b145f8062003a56565b91506020825110159162003a4f565b6001600160a01b0383811691161493505f620039ef565b6001600160801b039081811162003abc571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541462003b68576002835581471062003b50575f918291829182916001600160a01b03165af162003b3162002ad7565b501562003b3e5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b0382168115801562003bad575b1562003b9e5750905090565b620005719260801c9162002d4c565b50801562003b92565b60cf546001600160801b038116908215801562003c0e575b1562003bd957505090565b60801c9062003bea82828562002d4c565b928215620029f3570962003bfb5790565b6001810180911115620005715762002539565b50811562003bce565b62003c2162003852565b6001600160a01b0316801562003c6a57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610270602052604090205460ff1615620009a157565b61026f80546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b919062003cf262003852565b6001600160a01b0383169081156200072357801562003dac578062003d1d620018af60cf5460801c90565b019362003d29620026e5565b851162003d9a57620030de9462003d589162003d5262003d498562003bb6565b97889362003aa7565b62004821565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b9092919262003dcc62003852565b6001600160a01b0382169182156200072357811562003dac578162003df7620018af60cf5460801c90565b0162003e02620026e5565b811162003d9a57620030de9562003e5162003d95927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9462003d5262003e488862003bb6565b9a8b9362003aa7565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f526102088060205260405f2054155f146200258e576102078054600160401b811015620004b4576001810180835581101562002ac45783907f1ad7755b1dd0ab14588b5852415a5ca516498ebfb507c5447b8dda56bd2668c2015554915f5260205260405f2055600190565b805f5261020a8060205260405f2054155f146200258e576102098054600160401b811015620004b4576001810180835581101562002ac45783907f99e87348be6dc95028197b5a6b69c6a7a15df569de2f3d37542e8f40b8bae486015554915f5260205260405f2055600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562003f8657565b604051631afcd79f60e31b8152600490fd5b62003fa262003f56565b61271061ffff83161162003fdc5762003fbb9062003c17565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b62003ff862003f56565b80156200401057600181016200400b5750565b60d455565b6040516331278a8760e01b8152600490fd5b6200402c62003f56565b6801bc16d674ec80000062004040620026e5565b1062004010576200405062004399565b61010a55565b6200406062003f56565b6001600160a01b031680620040725750565b61016e80546001600160a01b0319169091179055565b6200409262003f56565b601e8151118015620041c5575b620041b357620040ae62003f56565b8051906001600160401b038211620004b457620040d782620040d15f5462000451565b620049de565b602090816001601f851114620041385750918062004111926200411995945f926200412c575b50508160011b915f199060031b1c19161790565b5f5562004ab3565b62000eec62004127620032fe565b600455565b015190505f80620040fd565b5f80529190601f1984165f8051602062005292833981519152935f905b8282106200419a575050916001939185620041199796941062004181575b505050811b015f5562004ab3565b01515f1960f88460031b161c191690555f808062004173565b8060018697829497870151815501960194019062004155565b604051632d3f993760e21b8152600490fd5b50600a8251116200409f565b620041db62003f56565b620041e562003f56565b620041ef62003f56565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca0034106200422b5762002518343062003ce6565b60405163ea2559bb60e01b8152600490fd5b908160209103126200042b5751620005718162001faa565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481620042e5575b50620042a757604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020620052b28339815191528403620042cc5762000eec92935062004b9e565b604051632a87526960e21b815260048101859052602490fd5b6200430391955060203d602011620011d457620011c48183620004f2565b935f62004280565b60d154806200431957505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316620007ea565b908082101562002c9e575090565b60d554908160801c8115801562004390575b156200437b5750905090565b6001600160801b036200057193169162002d4c565b5080156200436f565b6e5661756c7456616c696461746f727360881b6020604051620043bc81620004ba565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117620004b45760405251902090565b81519190604183036200449c57620044959250602082015190606060408401519301515f1a9062004c46565b9192909190565b50505f9160029190565b906030116200042b5790603090565b909291928360b0116200042b5783116200042b5760b0019160af190190565b906090116200042b5760300190606090565b9060c4116200042b5760900190603490565b909392938483116200042b5784116200042b578101920390565b35906020811062004521575090565b5f199060200360031b1b1690565b959493620045616200457093620045526060969460808b5260808b0190620028dd565b9089820360208b015262000537565b918783036040890152620028f5565b930152565b9695949062004570936200455262004561926060979560808c5260808c0191620028f5565b90602062000571928181520190620028dd565b91602062000571938181520191620028f5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062004609575050505050505050565b826200461a910180928787620044f8565b90620046278282620044a6565b916200464062004639858084620044b5565b9062004cde565b90620046656200465e620046558784620044d4565b979093620044e6565b9062004512565b948c3b156200042b578c5f926801bc16d674ec800000604095620046a187519a8b96879586946304512a2360e31b86528d8d6004880162004575565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194620046e692620046f6575b505192839283620045ad565b0390a160018193019290620045f7565b80620009936200470692620004a0565b5f620046da565b816030116200042b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916200475262004639828085620044b5565b6200475e8284620044d4565b94909260b0116200042b57803b156200042b57620047a7946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b600487016200452f565b03925af19081156200097d577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926200319b92620047ee575b50604051918291826200459a565b8062000993620047fe92620004a0565b5f620047e0565b9190916001600160801b038080941691160191821162000bb957565b5f80516020620052d283398151915260205f926200483f8562003aa7565b60cf5490620048596001600160801b039182841662004805565b6fffffffffffffffffffffffffffffffff1990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b038216918215620049d85760801c620048d2620048c082476200254d565b620048cb8562002403565b906200434f565b908115620049d157620048e58262003b7a565b938415620049c957826200493e620018e66200320362000eec96620030de96620049386200491c620032038d620049bd9a6200254d565b6001600160801b03166001600160801b031960d054161760d055565b620026f4565b6200494a818762004e00565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162003203620049a16200498f8862003aa7565b60cf546001600160801b031662002a13565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c62002a13565b505f93505050565b505f925050565b505f9150565b601f8111620049eb575050565b5f80525f8051602062005292833981519152906020601f840160051c8301931062004a32575b601f0160051c01905b81811062004a26575050565b5f815560010162004a1a565b909150819062004a11565b90601f821162004a4b575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931062004aa8575b601f0160051c01905b81811062004a9d57505050565b5f8155820162004a90565b909150819062004a87565b9081516001600160401b038111620004b45760019062004adf8162004ad9845462000451565b62004a3d565b602080601f831160011462004b175750819062004b139394955f926200412c5750508160011b915f199060031b1c19161790565b9055565b90601f1983169562004b4a60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821062004b86575050838596971062004b6d575b505050811b019055565b01515f1960f88460031b161c191690555f808062004b63565b80878596829496860151815501950193019062004b4e565b90813b1562004c25575f80516020620052b283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562004c0957620025189162004ee3565b50503462004c1357565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162004cd3579062004ca16020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156200097d575f516001600160a01b0381161562004cc957905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362004d92576bffffffffffffffffffffffff19919035828116916014811062004d7c575b5050905060601c62004d28620017df825f5261020860205260405f2054151590565b62004d6a5760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c8301526200057190829081016200281a565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062004d06565b604051639be7315960e01b8152600490fd5b60d15490600160401b821015620004b457600182018060d15582101562002ac45760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020620052f283398151915290910155565b9190918015801562004eda575b62004ec85762004e1c6200430b565b90810180911162000bb9576001600160a01b0380821162004ea8576001600160601b039081851162004e88579062000eec939462004e7162004e829362004e6262000edd565b95166001600160a01b03168552565b166001600160601b03166020830152565b62004da4565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562004e0d565b5f806200057193602081519101845af462004efd62002ad7565b9162004f73565b6001600160a01b03165f81815260d36020526040902080548381039190821162000bb9575f935f80516020620052d2833981519152926020925562004f498162003aa7565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b9062004f8a575080511562003b3e57805190602001fd5b8151158062004fbf575b62004f9d575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562004f9456fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c63430008160033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a264697066735822122001b3bd813422a1da22237ac6d5a0a6c0b2c53c6871ce454c434c474b90bc284764736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthRestakePrivVault.json b/test/shared/artifacts/EthRestakePrivVault.json deleted file mode 100644 index a62bb30f..00000000 --- a/test/shared/artifacts/EthRestakePrivVault.json +++ /dev/null @@ -1,1467 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthRestakePrivVault", - "sourceName": "contracts/vaults/ethereum/restake/EthRestakePrivVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "eigenPodOwnerImplementation", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101a034620001e457601f620047ee38819003918201601f19168301926001600160401b0392909183851183861017620001e8578160e09284926040978852833981010312620001e4576200005481620001fc565b926200006360208301620001fc565b9362000071828401620001fc565b916200008060608501620001fc565b926200008f60808601620001fc565b9660c0620000a060a08801620001fc565b9601519360805260a05260c0523060e052610100958652610120944686526101409283526101609384526101809485527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c16620001d35780808316036200018e575b50505051936145dc9586620002128739608051868181610f8701528181611204015281816127300152613045015260a05186610c99015260c051868181613da70152613efd015260e051868181610e450152612cf701525185612474015251846130c3015251836113dd015251828181611e28015261277d015251816104bd0152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200010b565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620001e45756fe6080604052600436101562000026575b36156200001a575f80fd5b62000024620024b7565b005b5f3560e01c806301e1d114146200034e57806307a2d13a1462000348578063096ae80d14620003425780630b10b201146200033c5780630d392cd9146200033657806318f7295014620003305780631a7ff553146200032a57806322758a4a14620003245780632cdf7401146200031e5780633229fa95146200031857806333194c0a14620003125780633a98ef39146200030c578063439fab9114620003065780634690484014620003005780634f1ef28614620002fa57806352d1902d14620002f457806353156f2814620002ee57806354fd4d5014620002e85780635c60da1b14620002e25780635cfc1a5114620002dc57806360d60e6e14620002d657806372b410a814620002d0578063754c388814620002ca57806376b58b9014620002c45780637b6341c614620002be5780637fd6f15c14620002b857806383d430d514620002b25780638697d2c214620002ac5780638ceab9aa14620002a6578063a045dd0c14620002a0578063a49a1e7d146200029a578063ac9650d81462000294578063ad3cb1cc146200028e578063b1f0e7c71462000288578063c5aecb221462000282578063c6e6f592146200027c578063d83ad00c1462000276578063e74b981b1462000270578063ee3bd5df146200026a578063f04da65b1462000264578063f132f5d3146200025e578063f6a6830f1462000258578063f851a4401462000252578063f9609f08146200024c5763f98f5b92036200000f5762001c8f565b62001c5f565b62001c36565b62001bf1565b62001b84565b62001b45565b62001b1d565b62001ae8565b62001ac0565b62001a9e565b62001a80565b62001a62565b62001a17565b62001992565b62001888565b62001847565b62001644565b620013ac565b620011a7565b62001181565b620010bd565b62001061565b62000ff0565b62000f5a565b62000f38565b62000f1a565b62000ee3565b62000ec6565b62000e9e565b62000e31565b62000b69565b62000a39565b6200088c565b62000802565b620007c6565b62000796565b62000778565b6200074d565b62000714565b62000699565b62000650565b62000456565b620003c1565b62000385565b62000363565b5f9103126200035f57565b5f80fd5b346200035f575f3660031901126200035f57602060985460801c604051908152f35b346200035f5760203660031901126200035f576020620003a760043562001cc4565b604051908152f35b6001600160a01b038116036200035f57565b346200035f5760203660031901126200035f57600435620003e281620003af565b61019d805490916001600160a01b03908116908216811462000444577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e892816020936200042e620025e4565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200035f575f3660031901126200035f57620004826200047662002496565b6001600160a01b031690565b330362000633576040516102c8808201908282106001600160401b038311176200062d578291620004f3916200429f84396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff0801562000609576001600160a01b0390811690813b156200035f5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af1801562000609576200060f575b506040516351d5709b60e11b815291602083600481845afa91821562000609577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f93620005cc575b506200059b90831662003651565b50620005a781620036bf565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200059b919350620005f99060203d60201162000601575b620005f0818362000adf565b81019062001cf8565b92906200058d565b503d620005e4565b62001ced565b806200061f620006269262000a77565b8062000354565b5f62000543565b62000a63565b604051634ca8886760e01b8152600490fd5b801515036200035f57565b346200035f5760403660031901126200035f57620000246004356200067581620003af565b60243590620006848262000645565b62001d10565b908160809103126200035f5790565b60603660031901126200035f57600435620006b481620003af565b602435620006c281620003af565b604435906001600160401b0382116200035f57602092620006f6620006f0620003a79436906004016200068a565b62001daa565b620007013362003453565b6200070c8162003453565b349062003595565b346200035f5760203660031901126200035f576004356001600160401b0381116200035f57620006f0620000249136906004016200068a565b346200035f575f3660031901126200035f57610206546040516001600160a01b039091168152602090f35b346200035f575f3660031901126200035f576020620003a762001dd5565b346200035f575f3660031901126200035f576020620007b462001e0e565b6040516001600160a01b039091168152f35b346200035f575f3660031901126200035f5760206040517f333122211e64a98ebf9b5890e3a33144b1208484d235be41b9d0a827eb1b5b0c8152f35b346200035f575f3660031901126200035f5760206001600160801b0360985416604051908152f35b9181601f840112156200035f578235916001600160401b0383116200035f57602083818601950101116200035f57565b60206003198201126200035f57600435906001600160401b0382116200035f5762000888916004016200082a565b9091565b62000897366200085a565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16801562000a24575b62000a125768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa92831562000609575f93620009ee575b50604051636f4fa30f60e01b8152938285600481335afa908115620006095762000960956200095a945f93620009c5575b505062000952919281019062001e4a565b908362002bd0565b62002cde565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2908060208101620005c7565b6200095293509081620009e692903d106200060157620005f0818362000adf565b915f62000941565b62000a0a919350823d84116200060157620005f0818362000adf565b915f62000910565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015620008c9565b346200035f575f3660031901126200035f576065546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200062d57604052565b606081019081106001600160401b038211176200062d57604052565b604081019081106001600160401b038211176200062d57604052565b608081019081106001600160401b038211176200062d57604052565b90601f801991011681019081106001600160401b038211176200062d57604052565b6040519062000b108262000aa7565b565b6001600160401b0381116200062d57601f01601f191660200190565b92919262000b3c8262000b12565b9162000b4c604051938462000adf565b8294818452818301116200035f578281602093845f960137010152565b6040806003193601126200035f57600490813562000b8781620003af565b6024356001600160401b0381116200035f57366023820112156200035f5762000bba903690602481870135910162000b2e565b9162000bc562002ced565b80519262000c008462000bf160209363439fab9160e01b85840152846024840152604483019062001904565b03601f19810186528562000adf565b62000c0a62002ced565b62000c14620025e4565b6001600160a01b0383811680159291908790841562000e00575b841562000d78575b841562000d0a575b5050821562000c6a575b505062000c5b5762000024838362003a48565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821562000609575f9262000cd6575b5050155f8062000c48565b62000cfa9250803d1062000d02575b62000cf1818362000adf565b81019062001fd9565b5f8062000ccb565b503d62000ce5565b855163054fd4d560e41b81529294508391839182905afa908115620006095760039160ff915f9162000d44575b5016141591865f62000c3e565b62000d699150843d861162000d70575b62000d60818362000adf565b81019062003a2d565b5f62000d37565b503d62000d54565b935050835163198ca60560e11b815282818981875afa908115620006095788917f333122211e64a98ebf9b5890e3a33144b1208484d235be41b9d0a827eb1b5b0c915f9162000dcc575b5014159362000c36565b62000df19150853d871162000df8575b62000de8818362000adf565b810190620026d1565b5f62000dc2565b503d62000ddc565b5f805160206200458783398151915254909450849062000e29906001600160a01b031662000476565b149362000c2e565b346200035f575f3660031901126200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300362000e8c5760206040515f80516020620045878339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200035f576001600160a01b0362000ebc62001e0e565b1633036200063357005b346200035f575f3660031901126200035f57602060405160028152f35b346200035f575f3660031901126200035f575f8051602062004587833981519152546040516001600160a01b039091168152602090f35b346200035f575f3660031901126200035f576020620003a762001ed3565b346200035f5760203660031901126200035f576020620003a760043562001f0a565b346200035f575f3660031901126200035f57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801562000609576020915f9162000fce575b506040519015158152f35b62000fe99150823d841162000d025762000cf1818362000adf565b5f62000fc3565b346200035f5760203660031901126200035f576004356200101181620003af565b6200101b620025e4565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200035f5760803660031901126200035f57620010b96200109c6004356200108a81620003af565b60643590604435906024359062001fff565b604080519384526020840192909252908201529081906060820190565b0390f35b346200035f575f3660031901126200035f576040518061019e805480845260208094019081925f527fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b905f5b868282106200116c578686620011228288038362000adf565b60405192839281840190828552518091526040840192915f5b8281106200114b57505050500390f35b83516001600160a01b0316855286955093810193928101926001016200113b565b83548552909301926001928301920162001109565b346200035f575f3660031901126200035f57602061ffff60655460a01c16604051908152f35b346200035f576003196040368201126200035f5760049081356001600160401b038082116200035f5760a08285019383360301126200035f576024359081116200035f57620011fa90369085016200082a565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200035f5760405163837d444160e01b8152905f908290818381620012508c828f016200212b565b03925af18015620006095762001395575b506200126c6200302a565b620012766200245f565b90811633141591826200135e575b505090506200134d576044019160c46200129f8484620021b5565b9050048015801562001332575b6200132257620012c6620012bf62001dd5565b916200220f565b1162001313575060c4620012db8383620021b5565b9050145f14620012fc576200002491620012f591620021b5565b9062003ef2565b62000024916200130c91620021b5565b9062003da5565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506200133f8484620021b5565b905060c482021415620012ac565b604051634ca8886760e01b81528390fd5b620013889250620013816200138c946200137888620030bd565b92369162000b2e565b91620031a2565b1590565b805f8062001284565b806200061f620013a59262000a77565b5f62001261565b346200035f5760603660031901126200035f57600435602435620013d560443582843362001fff565b9192620014037f00000000000000000000000000000000000000000000000000000000000000008262001ef6565b421080156200163b575b801562001632575b62001620577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936200146a8662001464620014586099546001600160801b031690565b6001600160801b031690565b62002d4a565b156200157e57620014aa6200148f62001483866200327e565b60995460801c62002229565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91620014f19190620014e060808262000adf565b5190205f52609b60205260405f2090565b555f93600183116200152d575b505050506200150e8233620032b2565b604080519485526020850191909152830152339180606081015b0390a2005b620015739293945062001541908862001ef6565b6040805133602082019081529181019390935260608301829052608095860183529094909190620014e0908262000adf565b555f808080620014fe565b620015886200302a565b620015c9620015ad6200159b866200327e565b609e546001600160801b031662002229565b6001600160801b03166001600160801b0319609e541617609e55565b62001603620015e8620015dc856200327e565b609e5460801c62002229565b6001600160801b03609e549181199060801b16911617609e55565b6200161a6200161584609f5462001ef6565b609f55565b620014aa565b604051630e3d8e8d60e11b8152600490fd5b50821562001415565b5081156200140d565b346200035f576040806003193601126200035f57602435906004356200166a83620003af565b620016746200302a565b801562001836576001600160a01b0383169081156200182557620016988162001cc4565b9081156200181457620016ab8262003b42565b620016b6836200327e565b60985460801c90620016c89162002229565b620016e8906001600160801b036098549181199060801b16911617609855565b620016f48233620041dd565b609e54958660801c8281609f54906200170d9162001ef6565b9862001719876200327e565b6200172d916001600160801b03166200372d565b6200174e906001600160801b03166001600160801b0319609e541617609e55565b620017599162001ef6565b62001764906200327e565b62001784906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290620017b760808262000adf565b519020620017cd905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200035f575f3660031901126200035f5761019d546020906001600160a01b0390811680620018815750805f5416905b60405191168152f35b9062001878565b346200035f57620015287f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf620018be366200085a565b9290620018ca620025e4565b60405191829160208352339560208401916200210b565b5f5b838110620018f35750505f910152565b8181015183820152602001620018e3565b906020916200191f81518092818552858086019101620018e1565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310620019615750505050505090565b909192939495848062001981600193603f198682030187528a5162001904565b980193019301919493929062001950565b346200035f5760203660031901126200035f576001600160401b036004358181116200035f57366023820112156200035f5780600401359182116200035f573660248360051b830101116200035f57620010b9916024620019f492016200239e565b604051918291826200192b565b90602062001a1492818152019062001904565b90565b346200035f575f3660031901126200035f57620010b960405162001a3b8162000aa7565b60058152640352e302e360dc1b602082015260405191829160208352602083019062001904565b346200035f575f3660031901126200035f576020620007b46200245f565b346200035f575f3660031901126200035f576020620007b462002496565b346200035f5760203660031901126200035f576020620003a760043562003351565b346200035f575f3660031901126200035f5760206001600160801b0360995416604051908152f35b346200035f5760203660031901126200035f576200002460043562001b0d81620003af565b62001b17620025e4565b620033ee565b346200035f575f3660031901126200035f5760206001600160801b03609e5416604051908152f35b346200035f5760203660031901126200035f5760043562001b6681620003af565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346200035f5760203660031901126200035f5760043562001ba581620003af565b61019c805490916001600160a01b03908116908216811462000444577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d92816020936200042e620025e4565b346200035f5760203660031901126200035f5760043562001c1281620003af565b60018060a01b03165f52610207602052602060ff60405f2054166040519015158152f35b346200035f575f3660031901126200035f575f546040516001600160a01b039091168152602090f35b60403660031901126200035f576020620003a760043562001c8081620003af565b60243590620006f682620003af565b346200035f5760203660031901126200035f576200002460043562001cb481620003af565b62001cbe620025e4565b62003476565b6098546001600160801b038116908162001cdd57505090565b9162001a149260801c9062002560565b6040513d5f823e3d90fd5b908160209103126200035f575162001a1481620003af565b610206546001600160a01b0391908216330362000633576001600160a01b0381165f90815261020760205260409020549215159260ff161515831462001da5576001600160a01b0381165f9081526102076020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b62001db962001dc191620026fd565b9190620028b5565b62001dc857565b62001dd262002a89565b50565b476099546001600160801b0362001dee81831662001cc4565b90609e5416019060801c01908181115f1462001e08570390565b50505f90565b610137546001600160a01b0316801562001e255790565b507f000000000000000000000000000000000000000000000000000000000000000090565b906020828203126200035f5781356001600160401b03928382116200035f5701916060838303126200035f576040519262001e858462000a8b565b80358452602081013561ffff811681036200035f57602085015260408101359182116200035f57019080601f830112156200035f5781602062001ecb9335910162000b2e565b604082015290565b609d548062001a1457505f1990565b634e487b7160e01b5f52601160045260245ffd5b9190820180921162001f0457565b62001ee2565b6001600160801b036099541662001f2062003afe565b90810180911162001f0457811062001f5a5762001f4a609f5462001f4362002d64565b9062001ef6565b111562001f55575f90565b5f1990565b609a90609a549182915f905b84821062001f825750505081101562001f7c5790565b505f1990565b909193808316906001818518811c830180931162001f04575f8790525f80516020620045678339815191528301546001600160a01b031684101562001fcd575050935b919062001f66565b90959101925062001fc5565b908160209103126200035f575162001a148162000645565b9190820391821162001f0457565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200203f81608081015b03601f19810183528262000adf565b5190205f52609b60205260405f2054918215620020b4576001600160801b0360995416906200206d62003afe565b91820180921162001f045783918310156200209f57916200208e9262002e73565b90915b82810390811162001f045792565b5090620020ac9162002dd9565b909162002091565b5050505f905f905f90565b9035601e19823603018112156200035f5701602081359101916001600160401b0382116200035f5781360383136200035f57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a062001a14926020815282356020820152602083013560408201526200216c6200215b6040850185620020bf565b84606085015260c08401916200210b565b90620021a562002199620021846060870187620020bf565b601f198587038101608087015295916200210b565b946080810190620020bf565b939092828603019101526200210b565b903590601e19813603018212156200035f57018035906001600160401b0382116200035f576020019181360383136200035f57565b634e487b7160e01b5f52601260045260245ffd5b811562002209570490565b620021ea565b906801bc16d674ec800000918083029283040362001f0457565b6001600160801b03918216908216039190821162001f0457565b6001600160401b0381116200062d5760051b60200190565b90620022678262002243565b62002276604051918262000adf565b828152809262002289601f199162002243565b01905f5b8281106200229a57505050565b8060606020809385010152016200228d565b634e487b7160e01b5f52603260045260245ffd5b90821015620022da57620008889160051b810190620021b5565b620022ac565b908092918237015f815290565b3d156200231c573d90620023018262000b12565b9162002311604051938462000adf565b82523d5f602084013e565b606090565b6020818303126200035f578051906001600160401b0382116200035f570181601f820112156200035f578051620023588162000b12565b9262002368604051948562000adf565b818452602082840101116200035f5762001a149160208085019101620018e1565b8051821015620022da5760209160051b010190565b919091620023ac836200225b565b925f5b818110620023bc57505050565b5f80620023cb838587620022c0565b60409391620023df855180938193620022e0565b0390305af490620023ef620022ed565b91156200241c57509060019162002407828862002389565b5262002414818762002389565b5001620023af565b9060448151106200035f576200245b620024456004928381015160248091830101910162002321565b925162461bcd60e51b8152928392830162001a01565b0390fd5b60d2546001600160a01b03168062001a1457507f000000000000000000000000000000000000000000000000000000000000000090565b61019c546001600160a01b0390811680620024b257505f541690565b905090565b335f526101a160205260405f205415620024cd57565b620024d83362003453565b62001dd23433620034bd565b90808202905f19818409908280831092039180830392146200255557612710908282111562002543577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514620025d557848311156200254357829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509062001a149250620021fe565b5f546001600160a01b031633036200063357565b908160609103126200035f578051916040602083015192015162001a148162000645565b81835290916001600160fb1b0383116200035f5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200035f57604083015260408101356200267381620003af565b6001600160a01b031660608381019190915281013536829003601e19018112156200035f5701602081359101906001600160401b0381116200035f578060051b360382136200035f5760a08360808062001a1496015201916200261c565b908160209103126200035f575190565b9190915f838201938412911290801582169115161762001f0457565b6040516325f56f1160e01b81526001600160a01b039291606090829081906200272a906004830162002641565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831562000609575f915f905f9562002868575b5084156200280d57816200277962001e0e565b16917f00000000000000000000000000000000000000000000000000000000000000001682146200280557509060205f92600460405180958193634641257d60e01b83525af19081156200060957620027db925f92620027df575b50620026e1565b9190565b620027fd91925060203d60201162000df85762000de8818362000adf565b905f620027d4565b908162002813575b50509190565b803b156200035f57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015620006095762002851575b806200280d565b806200061f620028619262000a77565b5f6200284a565b9194505062002893915060603d6060116200289c575b6200288a818362000adf565b810190620025f8565b93905f62002766565b503d6200287e565b600160ff1b811462001f04575f0390565b801562001dd257620028cd6200145860985460801c90565b5f8212620029cd5781620028e19162001ef6565b906200290c620028f1836200327e565b6001600160801b036098549181199060801b16911617609855565b620029236065549161ffff8360a01c1690620024e4565b801562001da557807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362002964620014586098546001600160801b031690565b80620029b3575050620029ae90925b6001600160a01b03169162002989848462003749565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b620029ae92620029c69203908462002560565b9262002973565b90620029d990620028a4565b620029f062001458609e546001600160801b031690565b8062002a1c575b508062002a02575050565b62002a16620028f19162000b109362001ff1565b6200327e565b9062002a7f7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9162002a6f620015ad62002a6362002a5b888862001ef6565b878562002560565b8080940396036200327e565b6040519081529081906020820190565b0390a15f620029f7565b609954906001600160801b03821691821562002bca5760801c62002ac462002ab2824762001ff1565b62002abd8562001cc4565b9062003799565b90811562002bc35762002ad78262003351565b93841562002bbb578262002b306200148f62002a1662000b1096620028f19662002b2a62002b0e62002a168d62002baf9a62001ff1565b6001600160801b03166001600160801b03196099541617609955565b62001ef6565b62002b3c818762003803565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162002a1662002b9362002b81886200327e565b6098546001600160801b031662002229565b6001600160801b03166001600160801b03196098541617609855565b60985460801c62002229565b505f93505050565b505f925050565b505f9150565b62002bda620038e6565b604083015162002be9620038e6565b6001600160a01b038216801562002ccc576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528062002c453394602083019062001904565b0390a260208301519262002c58620038e6565b61271061ffff85161162002cba5762002cb09362002c7a62002ca093620033ee565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555162003928565b62002caa6200395c565b6200398f565b62000b10620039c1565b604051638a81d3b360e01b8152600490fd5b60405163d92e233d60e01b8152600490fd5b62000b109062001cbe620038e6565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562002d2d575b505062000e8c57565b5f80516020620045878339815191525416141590505f8062002d24565b9062002d5562003afe565b91820180921162001f04571090565b476099548060801c820391821162001f04578162002d8c6001600160801b0380931662001cc4565b908162002db8575b5050811562001e085762001a149162002db291609e54169062003799565b62003b42565b919250908181111562002dd057035b905f8062002d94565b50505f62002dc7565b62002de362002d64565b91609f5492830180931162001f04578083111562002e345762002e0892039062003799565b90609e548060801c80155f1462002e1f5750508190565b6001600160801b0362001a1492168462002560565b5050505f905f90565b90604051604081018181106001600160401b038211176200062d5760405291546001600160a01b038116835260a01c6020830152565b609a545f94859493909180841080159062003021575b62003014578362002fdd575f5b609a5f526001600160a01b031662002ebe5f8051602062004567833981519152860162002e3d565b805190979062002ed7906001600160a01b031662000476565b9862002efe62002ef26020809b01516001600160601b031690565b6001600160601b031690565b94838110801562002fd2575b62002fc05791600193979a9562002f2d62002f3a939488035b838c039062003799565b8092019887039162002560565b0197019380861180159062002fb5575b62002faa57609a5f52829062002f705f8051602062004567833981519152870162002e3d565b805190890151969992966001600160a01b03909116946001939262002f3a9290916001600160601b039091169062002f2d90880362002f23565b945050509250509190565b508185101562002f4a565b60405163e8722f8f60e01b8152600490fd5b50808b111562002f0a565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031662002e96565b505093505050505f905f90565b50841562002e89565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562000609575f9162003099575b506200308757565b60405163e775715160e01b8152600490fd5b620030b6915060203d60201162000d025762000cf1818362000adf565b5f6200307f565b604290467f000000000000000000000000000000000000000000000000000000000000000003620031725760d354905b62003108620031006040830183620021b5565b369162000b2e565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152620031558162000ac3565b5190206040519161190160f01b8352600283015260228201522090565b6200317c62003b7e565b90620030ed565b600411156200318e57565b634e487b7160e01b5f52602160045260245ffd5b620031ae838362003c4e565b50620031bd8195929562003183565b15938462003267575b508315620031d5575b50505090565b5f9293509082916040516200321081620020306020820194630b135d3f60e11b998a8752602484015260406044840152606483019062001904565b51915afa906200321f620022ed565b8262003258575b8262003238575b50505f8080620031cf565b6200324f91925060208082518301019101620026d1565b145f806200322d565b91506020825110159162003226565b6001600160a01b0383811691161493505f620031c6565b6001600160801b039081811162003293571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146200333f576002835581471062003327575f918291829182916001600160a01b03165af162003308620022ed565b5015620033155760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b0382168115801562003384575b15620033755750905090565b62001a149260801c9162002560565b50801562003369565b6098546001600160801b0381169082158015620033e5575b15620033b057505090565b60801c90620033c182828562002560565b928215620022095709620033d25790565b600181018091111562001a145762001ee2565b508115620033a5565b620033f86200302a565b6001600160a01b031680156200344157606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610207602052604090205460ff16156200063357565b61020680546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b9190620034c96200302a565b6001600160a01b03831690811562002ccc578015620035835780620034f46200145860985460801c90565b01936200350062001ed3565b85116200357157620028f1946200352f916200352962003520856200338d565b9788936200327e565b62003749565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192620035a36200302a565b6001600160a01b03821691821562002ccc578115620035835781620035ce6200145860985460801c90565b01620035d962001ed3565b81116200357157620028f195620036286200356c927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94620035296200361f886200338d565b9a8b936200327e565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f5261019f8060205260405f2054155f1462001e085761019e8054600160401b8110156200062d5760018101808355811015620022da5783907fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b015554915f5260205260405f2055600190565b805f526101a18060205260405f2054155f1462001e08576101a08054600160401b8110156200062d5760018101808355811015620022da5783907f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c4015554915f5260205260405f2055600190565b9190916001600160801b038080941691160191821162001f0457565b62003754826200327e565b609854906200376e6001600160801b03918284166200372d565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015620024b2575090565b609a5490600160401b8210156200062d576001820180609a55821015620022da57609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206200456783398151915290910155565b91909180158015620038dd575b620038cb576200381f62003afe565b90810180911162001f04576001600160a01b03808211620038ab576001600160601b03908185116200388b579062000b1093946200387462003885936200386562000b01565b95166001600160a01b03168552565b166001600160601b03166020830152565b620037a7565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562003810565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156200391657565b604051631afcd79f60e31b8152600490fd5b62003932620038e6565b80156200394a5760018101620039455750565b609d55565b6040516331278a8760e01b8152600490fd5b62003966620038e6565b6801bc16d674ec8000006200397a62001ed3565b106200394a576200398a62003b7e565b60d355565b62003999620038e6565b6001600160a01b031680620039ab5750565b61013780546001600160a01b0319169091179055565b620039cb620038e6565b620039d5620038e6565b620039df620038e6565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341062003a1b5762001dd23430620034bd565b60405163ea2559bb60e01b8152600490fd5b908160209103126200035f575160ff811681036200035f5790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948162003ad8575b5062003a9a57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f8051602062004587833981519152840362003abf5762000b1092935062003fea565b604051632a87526960e21b815260048101859052602490fd5b62003af691955060203d60201162000df85762000de8818362000adf565b935f62003a73565b609a548062003b0c57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031662000476565b609e54908160801c8115801562003b75575b1562003b605750905090565b6001600160801b0362001a1493169162002560565b50801562003b54565b6e5661756c7456616c696461746f727360881b602060405162003ba18162000aa7565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176200062d5760405251902090565b815191906041830362003c815762003c7a9250602082015190606060408401519301515f1a9062004092565b9192909190565b50505f9160029190565b906030116200035f5790603090565b909291928360b0116200035f5783116200035f5760b0019160af190190565b906090116200035f5760300190606090565b9060c4116200035f5760900190603490565b909392938483116200035f5784116200035f578101920390565b35906020811062003d06575090565b5f199060200360031b1b1690565b95949362003d4662003d559362003d376060969460808b5260808b0190620020f3565b9089820360208b015262001904565b9187830360408901526200210b565b930152565b9695949062003d559362003d3762003d46926060979560808c5260808c01916200210b565b90602062001a14928181520190620020f3565b91602062001a149381815201916200210b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062003dee575050505050505050565b8262003dff91018092878762003cdd565b9062003e0c828262003c8b565b9162003e2562003e1e85808462003c9a565b9062004117565b9062003e4a62003e4362003e3a878462003cb9565b97909362003ccb565b9062003cf7565b948c3b156200035f578c5f926801bc16d674ec80000060409562003e8687519a8b96879586946304512a2360e31b86528d8d6004880162003d5a565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19462003ecb9262003edb575b50519283928362003d92565b0390a16001819301929062003ddc565b806200061f62003eeb9262000a77565b5f62003ebf565b816030116200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169162003f3762003e1e82808562003c9a565b62003f43828462003cb9565b94909260b0116200035f57803b156200035f5762003f8c946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162003d14565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192620029ae9262003fd3575b506040519182918262003d7f565b806200061f62003fe39262000a77565b5f62003fc5565b90813b1562004071575f805160206200458783398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115620040555762001dd2916200422d565b5050346200405f57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116200410c579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1562000609575f516001600160a01b038116156200410257905f905f90565b505f906001905f90565b5050505f9160039190565b60148203620041cb576bffffffffffffffffffffffff199190358281169160148110620041b5575b5050905060601c6200416162001388825f5261019f60205260405f2054151590565b620041a35760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c83015262001a14908290810162002030565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f806200413f565b604051639be7315960e01b8152600490fd5b60018060a01b03165f52609c60205260405f2090815481810390811162001f04576200420a92556200327e565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f8062001a1493602081519101845af462004247620022ed565b91906200425f57508051156200331557805190602001fd5b8151158062004294575b62004272575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200426956fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003344da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220d1c8386a5d967c36f96777f42ae5bc259c8b29932d1bc8864e239f80cb9b37a164736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101562000026575b36156200001a575f80fd5b62000024620024b7565b005b5f3560e01c806301e1d114146200034e57806307a2d13a1462000348578063096ae80d14620003425780630b10b201146200033c5780630d392cd9146200033657806318f7295014620003305780631a7ff553146200032a57806322758a4a14620003245780632cdf7401146200031e5780633229fa95146200031857806333194c0a14620003125780633a98ef39146200030c578063439fab9114620003065780634690484014620003005780634f1ef28614620002fa57806352d1902d14620002f457806353156f2814620002ee57806354fd4d5014620002e85780635c60da1b14620002e25780635cfc1a5114620002dc57806360d60e6e14620002d657806372b410a814620002d0578063754c388814620002ca57806376b58b9014620002c45780637b6341c614620002be5780637fd6f15c14620002b857806383d430d514620002b25780638697d2c214620002ac5780638ceab9aa14620002a6578063a045dd0c14620002a0578063a49a1e7d146200029a578063ac9650d81462000294578063ad3cb1cc146200028e578063b1f0e7c71462000288578063c5aecb221462000282578063c6e6f592146200027c578063d83ad00c1462000276578063e74b981b1462000270578063ee3bd5df146200026a578063f04da65b1462000264578063f132f5d3146200025e578063f6a6830f1462000258578063f851a4401462000252578063f9609f08146200024c5763f98f5b92036200000f5762001c8f565b62001c5f565b62001c36565b62001bf1565b62001b84565b62001b45565b62001b1d565b62001ae8565b62001ac0565b62001a9e565b62001a80565b62001a62565b62001a17565b62001992565b62001888565b62001847565b62001644565b620013ac565b620011a7565b62001181565b620010bd565b62001061565b62000ff0565b62000f5a565b62000f38565b62000f1a565b62000ee3565b62000ec6565b62000e9e565b62000e31565b62000b69565b62000a39565b6200088c565b62000802565b620007c6565b62000796565b62000778565b6200074d565b62000714565b62000699565b62000650565b62000456565b620003c1565b62000385565b62000363565b5f9103126200035f57565b5f80fd5b346200035f575f3660031901126200035f57602060985460801c604051908152f35b346200035f5760203660031901126200035f576020620003a760043562001cc4565b604051908152f35b6001600160a01b038116036200035f57565b346200035f5760203660031901126200035f57600435620003e281620003af565b61019d805490916001600160a01b03908116908216811462000444577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e892816020936200042e620025e4565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b346200035f575f3660031901126200035f57620004826200047662002496565b6001600160a01b031690565b330362000633576040516102c8808201908282106001600160401b038311176200062d578291620004f3916200429f84396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff0801562000609576001600160a01b0390811690813b156200035f5760405163439fab9160e01b8152602060048201525f602482018190528160448183875af1801562000609576200060f575b506040516351d5709b60e11b815291602083600481845afa91821562000609577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f93620005cc575b506200059b90831662003651565b50620005a781620036bf565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b6200059b919350620005f99060203d60201162000601575b620005f0818362000adf565b81019062001cf8565b92906200058d565b503d620005e4565b62001ced565b806200061f620006269262000a77565b8062000354565b5f62000543565b62000a63565b604051634ca8886760e01b8152600490fd5b801515036200035f57565b346200035f5760403660031901126200035f57620000246004356200067581620003af565b60243590620006848262000645565b62001d10565b908160809103126200035f5790565b60603660031901126200035f57600435620006b481620003af565b602435620006c281620003af565b604435906001600160401b0382116200035f57602092620006f6620006f0620003a79436906004016200068a565b62001daa565b620007013362003453565b6200070c8162003453565b349062003595565b346200035f5760203660031901126200035f576004356001600160401b0381116200035f57620006f0620000249136906004016200068a565b346200035f575f3660031901126200035f57610206546040516001600160a01b039091168152602090f35b346200035f575f3660031901126200035f576020620003a762001dd5565b346200035f575f3660031901126200035f576020620007b462001e0e565b6040516001600160a01b039091168152f35b346200035f575f3660031901126200035f5760206040517f333122211e64a98ebf9b5890e3a33144b1208484d235be41b9d0a827eb1b5b0c8152f35b346200035f575f3660031901126200035f5760206001600160801b0360985416604051908152f35b9181601f840112156200035f578235916001600160401b0383116200035f57602083818601950101116200035f57565b60206003198201126200035f57600435906001600160401b0382116200035f5762000888916004016200082a565b9091565b62000897366200085a565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16801562000a24575b62000a125768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa92831562000609575f93620009ee575b50604051636f4fa30f60e01b8152938285600481335afa908115620006095762000960956200095a945f93620009c5575b505062000952919281019062001e4a565b908362002bd0565b62002cde565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2908060208101620005c7565b6200095293509081620009e692903d106200060157620005f0818362000adf565b915f62000941565b62000a0a919350823d84116200060157620005f0818362000adf565b915f62000910565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015620008c9565b346200035f575f3660031901126200035f576065546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200062d57604052565b606081019081106001600160401b038211176200062d57604052565b604081019081106001600160401b038211176200062d57604052565b608081019081106001600160401b038211176200062d57604052565b90601f801991011681019081106001600160401b038211176200062d57604052565b6040519062000b108262000aa7565b565b6001600160401b0381116200062d57601f01601f191660200190565b92919262000b3c8262000b12565b9162000b4c604051938462000adf565b8294818452818301116200035f578281602093845f960137010152565b6040806003193601126200035f57600490813562000b8781620003af565b6024356001600160401b0381116200035f57366023820112156200035f5762000bba903690602481870135910162000b2e565b9162000bc562002ced565b80519262000c008462000bf160209363439fab9160e01b85840152846024840152604483019062001904565b03601f19810186528562000adf565b62000c0a62002ced565b62000c14620025e4565b6001600160a01b0383811680159291908790841562000e00575b841562000d78575b841562000d0a575b5050821562000c6a575b505062000c5b5762000024838362003a48565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821562000609575f9262000cd6575b5050155f8062000c48565b62000cfa9250803d1062000d02575b62000cf1818362000adf565b81019062001fd9565b5f8062000ccb565b503d62000ce5565b855163054fd4d560e41b81529294508391839182905afa908115620006095760039160ff915f9162000d44575b5016141591865f62000c3e565b62000d699150843d861162000d70575b62000d60818362000adf565b81019062003a2d565b5f62000d37565b503d62000d54565b935050835163198ca60560e11b815282818981875afa908115620006095788917f333122211e64a98ebf9b5890e3a33144b1208484d235be41b9d0a827eb1b5b0c915f9162000dcc575b5014159362000c36565b62000df19150853d871162000df8575b62000de8818362000adf565b810190620026d1565b5f62000dc2565b503d62000ddc565b5f805160206200458783398151915254909450849062000e29906001600160a01b031662000476565b149362000c2e565b346200035f575f3660031901126200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300362000e8c5760206040515f80516020620045878339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126200035f576001600160a01b0362000ebc62001e0e565b1633036200063357005b346200035f575f3660031901126200035f57602060405160028152f35b346200035f575f3660031901126200035f575f8051602062004587833981519152546040516001600160a01b039091168152602090f35b346200035f575f3660031901126200035f576020620003a762001ed3565b346200035f5760203660031901126200035f576020620003a760043562001f0a565b346200035f575f3660031901126200035f57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801562000609576020915f9162000fce575b506040519015158152f35b62000fe99150823d841162000d025762000cf1818362000adf565b5f62000fc3565b346200035f5760203660031901126200035f576004356200101181620003af565b6200101b620025e4565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346200035f5760803660031901126200035f57620010b96200109c6004356200108a81620003af565b60643590604435906024359062001fff565b604080519384526020840192909252908201529081906060820190565b0390f35b346200035f575f3660031901126200035f576040518061019e805480845260208094019081925f527fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b905f5b868282106200116c578686620011228288038362000adf565b60405192839281840190828552518091526040840192915f5b8281106200114b57505050500390f35b83516001600160a01b0316855286955093810193928101926001016200113b565b83548552909301926001928301920162001109565b346200035f575f3660031901126200035f57602061ffff60655460a01c16604051908152f35b346200035f576003196040368201126200035f5760049081356001600160401b038082116200035f5760a08285019383360301126200035f576024359081116200035f57620011fa90369085016200082a565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156200035f5760405163837d444160e01b8152905f908290818381620012508c828f016200212b565b03925af18015620006095762001395575b506200126c6200302a565b620012766200245f565b90811633141591826200135e575b505090506200134d576044019160c46200129f8484620021b5565b9050048015801562001332575b6200132257620012c6620012bf62001dd5565b916200220f565b1162001313575060c4620012db8383620021b5565b9050145f14620012fc576200002491620012f591620021b5565b9062003ef2565b62000024916200130c91620021b5565b9062003da5565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506200133f8484620021b5565b905060c482021415620012ac565b604051634ca8886760e01b81528390fd5b620013889250620013816200138c946200137888620030bd565b92369162000b2e565b91620031a2565b1590565b805f8062001284565b806200061f620013a59262000a77565b5f62001261565b346200035f5760603660031901126200035f57600435602435620013d560443582843362001fff565b9192620014037f00000000000000000000000000000000000000000000000000000000000000008262001ef6565b421080156200163b575b801562001632575b62001620577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936200146a8662001464620014586099546001600160801b031690565b6001600160801b031690565b62002d4a565b156200157e57620014aa6200148f62001483866200327e565b60995460801c62002229565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91620014f19190620014e060808262000adf565b5190205f52609b60205260405f2090565b555f93600183116200152d575b505050506200150e8233620032b2565b604080519485526020850191909152830152339180606081015b0390a2005b620015739293945062001541908862001ef6565b6040805133602082019081529181019390935260608301829052608095860183529094909190620014e0908262000adf565b555f808080620014fe565b620015886200302a565b620015c9620015ad6200159b866200327e565b609e546001600160801b031662002229565b6001600160801b03166001600160801b0319609e541617609e55565b62001603620015e8620015dc856200327e565b609e5460801c62002229565b6001600160801b03609e549181199060801b16911617609e55565b6200161a6200161584609f5462001ef6565b609f55565b620014aa565b604051630e3d8e8d60e11b8152600490fd5b50821562001415565b5081156200140d565b346200035f576040806003193601126200035f57602435906004356200166a83620003af565b620016746200302a565b801562001836576001600160a01b0383169081156200182557620016988162001cc4565b9081156200181457620016ab8262003b42565b620016b6836200327e565b60985460801c90620016c89162002229565b620016e8906001600160801b036098549181199060801b16911617609855565b620016f48233620041dd565b609e54958660801c8281609f54906200170d9162001ef6565b9862001719876200327e565b6200172d916001600160801b03166200372d565b6200174e906001600160801b03166001600160801b0319609e541617609e55565b620017599162001ef6565b62001764906200327e565b62001784906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290620017b760808262000adf565b519020620017cd905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346200035f575f3660031901126200035f5761019d546020906001600160a01b0390811680620018815750805f5416905b60405191168152f35b9062001878565b346200035f57620015287f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf620018be366200085a565b9290620018ca620025e4565b60405191829160208352339560208401916200210b565b5f5b838110620018f35750505f910152565b8181015183820152602001620018e3565b906020916200191f81518092818552858086019101620018e1565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310620019615750505050505090565b909192939495848062001981600193603f198682030187528a5162001904565b980193019301919493929062001950565b346200035f5760203660031901126200035f576001600160401b036004358181116200035f57366023820112156200035f5780600401359182116200035f573660248360051b830101116200035f57620010b9916024620019f492016200239e565b604051918291826200192b565b90602062001a1492818152019062001904565b90565b346200035f575f3660031901126200035f57620010b960405162001a3b8162000aa7565b60058152640352e302e360dc1b602082015260405191829160208352602083019062001904565b346200035f575f3660031901126200035f576020620007b46200245f565b346200035f575f3660031901126200035f576020620007b462002496565b346200035f5760203660031901126200035f576020620003a760043562003351565b346200035f575f3660031901126200035f5760206001600160801b0360995416604051908152f35b346200035f5760203660031901126200035f576200002460043562001b0d81620003af565b62001b17620025e4565b620033ee565b346200035f575f3660031901126200035f5760206001600160801b03609e5416604051908152f35b346200035f5760203660031901126200035f5760043562001b6681620003af565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346200035f5760203660031901126200035f5760043562001ba581620003af565b61019c805490916001600160a01b03908116908216811462000444577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d92816020936200042e620025e4565b346200035f5760203660031901126200035f5760043562001c1281620003af565b60018060a01b03165f52610207602052602060ff60405f2054166040519015158152f35b346200035f575f3660031901126200035f575f546040516001600160a01b039091168152602090f35b60403660031901126200035f576020620003a760043562001c8081620003af565b60243590620006f682620003af565b346200035f5760203660031901126200035f576200002460043562001cb481620003af565b62001cbe620025e4565b62003476565b6098546001600160801b038116908162001cdd57505090565b9162001a149260801c9062002560565b6040513d5f823e3d90fd5b908160209103126200035f575162001a1481620003af565b610206546001600160a01b0391908216330362000633576001600160a01b0381165f90815261020760205260409020549215159260ff161515831462001da5576001600160a01b0381165f9081526102076020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b62001db962001dc191620026fd565b9190620028b5565b62001dc857565b62001dd262002a89565b50565b476099546001600160801b0362001dee81831662001cc4565b90609e5416019060801c01908181115f1462001e08570390565b50505f90565b610137546001600160a01b0316801562001e255790565b507f000000000000000000000000000000000000000000000000000000000000000090565b906020828203126200035f5781356001600160401b03928382116200035f5701916060838303126200035f576040519262001e858462000a8b565b80358452602081013561ffff811681036200035f57602085015260408101359182116200035f57019080601f830112156200035f5781602062001ecb9335910162000b2e565b604082015290565b609d548062001a1457505f1990565b634e487b7160e01b5f52601160045260245ffd5b9190820180921162001f0457565b62001ee2565b6001600160801b036099541662001f2062003afe565b90810180911162001f0457811062001f5a5762001f4a609f5462001f4362002d64565b9062001ef6565b111562001f55575f90565b5f1990565b609a90609a549182915f905b84821062001f825750505081101562001f7c5790565b505f1990565b909193808316906001818518811c830180931162001f04575f8790525f80516020620045678339815191528301546001600160a01b031684101562001fcd575050935b919062001f66565b90959101925062001fc5565b908160209103126200035f575162001a148162000645565b9190820391821162001f0457565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906200203f81608081015b03601f19810183528262000adf565b5190205f52609b60205260405f2054918215620020b4576001600160801b0360995416906200206d62003afe565b91820180921162001f045783918310156200209f57916200208e9262002e73565b90915b82810390811162001f045792565b5090620020ac9162002dd9565b909162002091565b5050505f905f905f90565b9035601e19823603018112156200035f5701602081359101916001600160401b0382116200035f5781360383136200035f57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a062001a14926020815282356020820152602083013560408201526200216c6200215b6040850185620020bf565b84606085015260c08401916200210b565b90620021a562002199620021846060870187620020bf565b601f198587038101608087015295916200210b565b946080810190620020bf565b939092828603019101526200210b565b903590601e19813603018212156200035f57018035906001600160401b0382116200035f576020019181360383136200035f57565b634e487b7160e01b5f52601260045260245ffd5b811562002209570490565b620021ea565b906801bc16d674ec800000918083029283040362001f0457565b6001600160801b03918216908216039190821162001f0457565b6001600160401b0381116200062d5760051b60200190565b90620022678262002243565b62002276604051918262000adf565b828152809262002289601f199162002243565b01905f5b8281106200229a57505050565b8060606020809385010152016200228d565b634e487b7160e01b5f52603260045260245ffd5b90821015620022da57620008889160051b810190620021b5565b620022ac565b908092918237015f815290565b3d156200231c573d90620023018262000b12565b9162002311604051938462000adf565b82523d5f602084013e565b606090565b6020818303126200035f578051906001600160401b0382116200035f570181601f820112156200035f578051620023588162000b12565b9262002368604051948562000adf565b818452602082840101116200035f5762001a149160208085019101620018e1565b8051821015620022da5760209160051b010190565b919091620023ac836200225b565b925f5b818110620023bc57505050565b5f80620023cb838587620022c0565b60409391620023df855180938193620022e0565b0390305af490620023ef620022ed565b91156200241c57509060019162002407828862002389565b5262002414818762002389565b5001620023af565b9060448151106200035f576200245b620024456004928381015160248091830101910162002321565b925162461bcd60e51b8152928392830162001a01565b0390fd5b60d2546001600160a01b03168062001a1457507f000000000000000000000000000000000000000000000000000000000000000090565b61019c546001600160a01b0390811680620024b257505f541690565b905090565b335f526101a160205260405f205415620024cd57565b620024d83362003453565b62001dd23433620034bd565b90808202905f19818409908280831092039180830392146200255557612710908282111562002543577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514620025d557848311156200254357829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509062001a149250620021fe565b5f546001600160a01b031633036200063357565b908160609103126200035f578051916040602083015192015162001a148162000645565b81835290916001600160fb1b0383116200035f5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036200035f57604083015260408101356200267381620003af565b6001600160a01b031660608381019190915281013536829003601e19018112156200035f5701602081359101906001600160401b0381116200035f578060051b360382136200035f5760a08360808062001a1496015201916200261c565b908160209103126200035f575190565b9190915f838201938412911290801582169115161762001f0457565b6040516325f56f1160e01b81526001600160a01b039291606090829081906200272a906004830162002641565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831562000609575f915f905f9562002868575b5084156200280d57816200277962001e0e565b16917f00000000000000000000000000000000000000000000000000000000000000001682146200280557509060205f92600460405180958193634641257d60e01b83525af19081156200060957620027db925f92620027df575b50620026e1565b9190565b620027fd91925060203d60201162000df85762000de8818362000adf565b905f620027d4565b908162002813575b50509190565b803b156200035f57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015620006095762002851575b806200280d565b806200061f620028619262000a77565b5f6200284a565b9194505062002893915060603d6060116200289c575b6200288a818362000adf565b810190620025f8565b93905f62002766565b503d6200287e565b600160ff1b811462001f04575f0390565b801562001dd257620028cd6200145860985460801c90565b5f8212620029cd5781620028e19162001ef6565b906200290c620028f1836200327e565b6001600160801b036098549181199060801b16911617609855565b620029236065549161ffff8360a01c1690620024e4565b801562001da557807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362002964620014586098546001600160801b031690565b80620029b3575050620029ae90925b6001600160a01b03169162002989848462003749565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b620029ae92620029c69203908462002560565b9262002973565b90620029d990620028a4565b620029f062001458609e546001600160801b031690565b8062002a1c575b508062002a02575050565b62002a16620028f19162000b109362001ff1565b6200327e565b9062002a7f7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9162002a6f620015ad62002a6362002a5b888862001ef6565b878562002560565b8080940396036200327e565b6040519081529081906020820190565b0390a15f620029f7565b609954906001600160801b03821691821562002bca5760801c62002ac462002ab2824762001ff1565b62002abd8562001cc4565b9062003799565b90811562002bc35762002ad78262003351565b93841562002bbb578262002b306200148f62002a1662000b1096620028f19662002b2a62002b0e62002a168d62002baf9a62001ff1565b6001600160801b03166001600160801b03196099541617609955565b62001ef6565b62002b3c818762003803565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a162002a1662002b9362002b81886200327e565b6098546001600160801b031662002229565b6001600160801b03166001600160801b03196098541617609855565b60985460801c62002229565b505f93505050565b505f925050565b505f9150565b62002bda620038e6565b604083015162002be9620038e6565b6001600160a01b038216801562002ccc576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528062002c453394602083019062001904565b0390a260208301519262002c58620038e6565b61271061ffff85161162002cba5762002cb09362002c7a62002ca093620033ee565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555162003928565b62002caa6200395c565b6200398f565b62000b10620039c1565b604051638a81d3b360e01b8152600490fd5b60405163d92e233d60e01b8152600490fd5b62000b109062001cbe620038e6565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562002d2d575b505062000e8c57565b5f80516020620045878339815191525416141590505f8062002d24565b9062002d5562003afe565b91820180921162001f04571090565b476099548060801c820391821162001f04578162002d8c6001600160801b0380931662001cc4565b908162002db8575b5050811562001e085762001a149162002db291609e54169062003799565b62003b42565b919250908181111562002dd057035b905f8062002d94565b50505f62002dc7565b62002de362002d64565b91609f5492830180931162001f04578083111562002e345762002e0892039062003799565b90609e548060801c80155f1462002e1f5750508190565b6001600160801b0362001a1492168462002560565b5050505f905f90565b90604051604081018181106001600160401b038211176200062d5760405291546001600160a01b038116835260a01c6020830152565b609a545f94859493909180841080159062003021575b62003014578362002fdd575f5b609a5f526001600160a01b031662002ebe5f8051602062004567833981519152860162002e3d565b805190979062002ed7906001600160a01b031662000476565b9862002efe62002ef26020809b01516001600160601b031690565b6001600160601b031690565b94838110801562002fd2575b62002fc05791600193979a9562002f2d62002f3a939488035b838c039062003799565b8092019887039162002560565b0197019380861180159062002fb5575b62002faa57609a5f52829062002f705f8051602062004567833981519152870162002e3d565b805190890151969992966001600160a01b03909116946001939262002f3a9290916001600160601b039091169062002f2d90880362002f23565b945050509250509190565b508185101562002f4a565b60405163e8722f8f60e01b8152600490fd5b50808b111562002f0a565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031662002e96565b505093505050505f905f90565b50841562002e89565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562000609575f9162003099575b506200308757565b60405163e775715160e01b8152600490fd5b620030b6915060203d60201162000d025762000cf1818362000adf565b5f6200307f565b604290467f000000000000000000000000000000000000000000000000000000000000000003620031725760d354905b62003108620031006040830183620021b5565b369162000b2e565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152620031558162000ac3565b5190206040519161190160f01b8352600283015260228201522090565b6200317c62003b7e565b90620030ed565b600411156200318e57565b634e487b7160e01b5f52602160045260245ffd5b620031ae838362003c4e565b50620031bd8195929562003183565b15938462003267575b508315620031d5575b50505090565b5f9293509082916040516200321081620020306020820194630b135d3f60e11b998a8752602484015260406044840152606483019062001904565b51915afa906200321f620022ed565b8262003258575b8262003238575b50505f8080620031cf565b6200324f91925060208082518301019101620026d1565b145f806200322d565b91506020825110159162003226565b6001600160a01b0383811691161493505f620031c6565b6001600160801b039081811162003293571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146200333f576002835581471062003327575f918291829182916001600160a01b03165af162003308620022ed565b5015620033155760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b0382168115801562003384575b15620033755750905090565b62001a149260801c9162002560565b50801562003369565b6098546001600160801b0381169082158015620033e5575b15620033b057505090565b60801c90620033c182828562002560565b928215620022095709620033d25790565b600181018091111562001a145762001ee2565b508115620033a5565b620033f86200302a565b6001600160a01b031680156200344157606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03165f908152610207602052604090205460ff16156200063357565b61020680546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b9190620034c96200302a565b6001600160a01b03831690811562002ccc578015620035835780620034f46200145860985460801c90565b01936200350062001ed3565b85116200357157620028f1946200352f916200352962003520856200338d565b9788936200327e565b62003749565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192620035a36200302a565b6001600160a01b03821691821562002ccc578115620035835781620035ce6200145860985460801c90565b01620035d962001ed3565b81116200357157620028f195620036286200356c927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94620035296200361f886200338d565b9a8b936200327e565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f5261019f8060205260405f2054155f1462001e085761019e8054600160401b8110156200062d5760018101808355811015620022da5783907fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b015554915f5260205260405f2055600190565b805f526101a18060205260405f2054155f1462001e08576101a08054600160401b8110156200062d5760018101808355811015620022da5783907f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c4015554915f5260205260405f2055600190565b9190916001600160801b038080941691160191821162001f0457565b62003754826200327e565b609854906200376e6001600160801b03918284166200372d565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015620024b2575090565b609a5490600160401b8210156200062d576001820180609a55821015620022da57609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206200456783398151915290910155565b91909180158015620038dd575b620038cb576200381f62003afe565b90810180911162001f04576001600160a01b03808211620038ab576001600160601b03908185116200388b579062000b1093946200387462003885936200386562000b01565b95166001600160a01b03168552565b166001600160601b03166020830152565b620037a7565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821562003810565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156200391657565b604051631afcd79f60e31b8152600490fd5b62003932620038e6565b80156200394a5760018101620039455750565b609d55565b6040516331278a8760e01b8152600490fd5b62003966620038e6565b6801bc16d674ec8000006200397a62001ed3565b106200394a576200398a62003b7e565b60d355565b62003999620038e6565b6001600160a01b031680620039ab5750565b61013780546001600160a01b0319169091179055565b620039cb620038e6565b620039d5620038e6565b620039df620038e6565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341062003a1b5762001dd23430620034bd565b60405163ea2559bb60e01b8152600490fd5b908160209103126200035f575160ff811681036200035f5790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948162003ad8575b5062003a9a57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f8051602062004587833981519152840362003abf5762000b1092935062003fea565b604051632a87526960e21b815260048101859052602490fd5b62003af691955060203d60201162000df85762000de8818362000adf565b935f62003a73565b609a548062003b0c57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031662000476565b609e54908160801c8115801562003b75575b1562003b605750905090565b6001600160801b0362001a1493169162002560565b50801562003b54565b6e5661756c7456616c696461746f727360881b602060405162003ba18162000aa7565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176200062d5760405251902090565b815191906041830362003c815762003c7a9250602082015190606060408401519301515f1a9062004092565b9192909190565b50505f9160029190565b906030116200035f5790603090565b909291928360b0116200035f5783116200035f5760b0019160af190190565b906090116200035f5760300190606090565b9060c4116200035f5760900190603490565b909392938483116200035f5784116200035f578101920390565b35906020811062003d06575090565b5f199060200360031b1b1690565b95949362003d4662003d559362003d376060969460808b5260808b0190620020f3565b9089820360208b015262001904565b9187830360408901526200210b565b930152565b9695949062003d559362003d3762003d46926060979560808c5260808c01916200210b565b90602062001a14928181520190620020f3565b91602062001a149381815201916200210b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062003dee575050505050505050565b8262003dff91018092878762003cdd565b9062003e0c828262003c8b565b9162003e2562003e1e85808462003c9a565b9062004117565b9062003e4a62003e4362003e3a878462003cb9565b97909362003ccb565b9062003cf7565b948c3b156200035f578c5f926801bc16d674ec80000060409562003e8687519a8b96879586946304512a2360e31b86528d8d6004880162003d5a565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19462003ecb9262003edb575b50519283928362003d92565b0390a16001819301929062003ddc565b806200061f62003eeb9262000a77565b5f62003ebf565b816030116200035f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169162003f3762003e1e82808562003c9a565b62003f43828462003cb9565b94909260b0116200035f57803b156200035f5762003f8c946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162003d14565b03925af190811562000609577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192620029ae9262003fd3575b506040519182918262003d7f565b806200061f62003fe39262000a77565b5f62003fc5565b90813b1562004071575f805160206200458783398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115620040555762001dd2916200422d565b5050346200405f57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116200410c579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1562000609575f516001600160a01b038116156200410257905f905f90565b505f906001905f90565b5050505f9160039190565b60148203620041cb576bffffffffffffffffffffffff199190358281169160148110620041b5575b5050905060601c6200416162001388825f5261019f60205260405f2054151590565b620041a35760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c83015262001a14908290810162002030565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f806200413f565b604051639be7315960e01b8152600490fd5b60018060a01b03165f52609c60205260405f2090815481810390811162001f04576200420a92556200327e565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f8062001a1493602081519101845af462004247620022ed565b91906200425f57508051156200331557805190602001fd5b8151158062004294575b62004272575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200426956fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003344da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220d1c8386a5d967c36f96777f42ae5bc259c8b29932d1bc8864e239f80cb9b37a164736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthRestakeVault.json b/test/shared/artifacts/EthRestakeVault.json deleted file mode 100644 index 6ff20f9f..00000000 --- a/test/shared/artifacts/EthRestakeVault.json +++ /dev/null @@ -1,1360 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthRestakeVault", - "sourceName": "contracts/vaults/ethereum/restake/EthRestakeVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "eigenPodOwnerImplementation", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "EigenPodNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentials", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "eigenPodOwner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "eigenPod", - "type": "address" - } - ], - "name": "EigenPodCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "RestakeOperatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "RestakeWithdrawalsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "createEigenPod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEigenPods", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "restakeOperatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "restakeWithdrawalsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeOperatorsManager", - "type": "address" - } - ], - "name": "setRestakeOperatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRestakeWithdrawalsManager", - "type": "address" - } - ], - "name": "setRestakeWithdrawalsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101a034620001e457601f6200456c38819003918201601f19168301926001600160401b0392909183851183861017620001e8578160e09284926040978852833981010312620001e4576200005481620001fc565b926200006360208301620001fc565b9362000071828401620001fc565b916200008060608501620001fc565b926200008f60808601620001fc565b9660c0620000a060a08801620001fc565b9601519360805260a05260c0523060e052610100958652610120944686526101409283526101609384526101809485527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c16620001d35780808316036200018e575b505050519361435a9586620002128739608051868181610f1601528181611193015281816125220152612e2d015260a05186610c28015260c051868181613b250152613c7b015260e051868181610dd40152612adf0152518561227301525184612eab0152518361136c015251828181611ca3015261256f015251816104750152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200010b565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620001e45756fe6080604052600436101562000026575b36156200001a575f80fd5b62000024620022b6565b005b5f3560e01c806301e1d114146200030657806307a2d13a1462000300578063096ae80d14620002fa5780630b10b20114620002f457806318f7295014620002ee5780631a7ff55314620002e85780632cdf740114620002e25780633229fa9514620002dc57806333194c0a14620002d65780633a98ef3914620002d0578063439fab9114620002ca5780634690484014620002c45780634f1ef28614620002be57806352d1902d14620002b857806353156f2814620002b257806354fd4d5014620002ac5780635c60da1b14620002a65780635cfc1a5114620002a057806360d60e6e146200029a57806372b410a81462000294578063754c3888146200028e57806376b58b9014620002885780637b6341c614620002825780637fd6f15c146200027c57806383d430d514620002765780638697d2c214620002705780638ceab9aa146200026a578063a045dd0c1462000264578063a49a1e7d146200025e578063ac9650d81462000258578063ad3cb1cc1462000252578063b1f0e7c7146200024c578063c5aecb221462000246578063c6e6f5921462000240578063d83ad00c146200023a578063e74b981b1462000234578063ee3bd5df146200022e578063f04da65b1462000228578063f132f5d31462000222578063f851a440146200021c5763f9609f08036200000f5762001ba9565b62001b80565b62001b13565b62001ad4565b62001aac565b62001a77565b62001a4f565b62001a2d565b62001a0f565b620019f1565b620019a6565b62001921565b62001817565b620017d6565b620015d3565b6200133b565b62001136565b62001110565b6200104c565b62000ff0565b62000f7f565b62000ee9565b62000ec7565b62000ea9565b62000e72565b62000e55565b62000e2d565b62000dc0565b62000af8565b620009c8565b620007be565b62000734565b620006f8565b620006c8565b620006aa565b62000671565b6200060c565b6200040e565b62000379565b6200033d565b6200031b565b5f9103126200031757565b5f80fd5b3462000317575f3660031901126200031757602060985460801c604051908152f35b3462000317576020366003190112620003175760206200035f60043562001bd9565b604051908152f35b6001600160a01b038116036200031757565b346200031757602036600319011262000317576004356200039a8162000367565b61019d805490916001600160a01b039081169082168114620003fc577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e89281602093620003e6620023d8565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b3462000317575f36600319011262000317576200043a6200042e62002295565b6001600160a01b031690565b3303620005eb576040516102c8808201908282106001600160401b03831117620005e5578291620004ab916200401d84396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff08015620005c1576001600160a01b0390811690813b15620003175760405163439fab9160e01b8152602060048201525f602482018190528160448183875af18015620005c157620005c7575b506040516351d5709b60e11b815291602083600481845afa918215620005c1577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f9362000584575b5062000553908316620033cf565b506200055f816200343d565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b62000553919350620005b19060203d602011620005b9575b620005a8818362000a6e565b81019062001c0d565b929062000545565b503d6200059c565b62001c02565b80620005d7620005de9262000a06565b806200030c565b5f620004fb565b620009f2565b604051634ca8886760e01b8152600490fd5b90816080910312620003175790565b60603660031901126200031757600435620006278162000367565b602435620006358162000367565b604435906001600160401b038211620003175760209262000669620006636200035f943690600401620005fd565b62001c25565b349062003313565b346200031757602036600319011262000317576004356001600160401b03811162000317576200066362000024913690600401620005fd565b3462000317575f366003190112620003175760206200035f62001c50565b3462000317575f36600319011262000317576020620006e662001c89565b6040516001600160a01b039091168152f35b3462000317575f366003190112620003175760206040517f43d6c07ac63953f42a28f0366affe9895fd54f84336314dd012087bd0941df678152f35b3462000317575f366003190112620003175760206001600160801b0360985416604051908152f35b9181601f8401121562000317578235916001600160401b0383116200031757602083818601950101116200031757565b60206003198201126200031757600435906001600160401b0382116200031757620007ba916004016200075c565b9091565b620007c9366200078c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c168015620009b3575b620009a25768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020918285600481335afa948515620005c1575f956200097e575b508351636f4fa30f60e01b8152908382600481335afa918215620005c1575f926200095a575b508201948383870312620003175782356001600160401b0393848211620003175701926060848803126200031757855193620008a78562000a1a565b803585528581013561ffff81168103620003175786860152868101359182116200031757019386601f8601121562000317577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d296856200090f92620009199735910162000abd565b85840152620029c7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055516002815280602081016200057f565b62000976919250843d8611620005b957620005a8818362000a6e565b905f6200086b565b6200099a919550833d8511620005b957620005a8818362000a6e565b935f62000845565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015620007ff565b3462000317575f36600319011262000317576065546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111620005e557604052565b606081019081106001600160401b03821117620005e557604052565b604081019081106001600160401b03821117620005e557604052565b608081019081106001600160401b03821117620005e557604052565b90601f801991011681019081106001600160401b03821117620005e557604052565b6040519062000a9f8262000a36565b565b6001600160401b038111620005e557601f01601f191660200190565b92919262000acb8262000aa1565b9162000adb604051938462000a6e565b82948184528183011162000317578281602093845f960137010152565b6040806003193601126200031757600490813562000b168162000367565b6024356001600160401b038111620003175736602382011215620003175762000b49903690602481870135910162000abd565b9162000b5462002ad5565b80519262000b8f8462000b8060209363439fab9160e01b85840152846024840152604483019062001893565b03601f19810186528562000a6e565b62000b9962002ad5565b62000ba3620023d8565b6001600160a01b0383811680159291908790841562000d8f575b841562000d07575b841562000c99575b5050821562000bf9575b505062000bea57620000248383620037c6565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215620005c1575f9262000c65575b5050155f8062000bd7565b62000c899250803d1062000c91575b62000c80818362000a6e565b81019062001dd9565b5f8062000c5a565b503d62000c74565b855163054fd4d560e41b81529294508391839182905afa908115620005c15760039160ff915f9162000cd3575b5016141591865f62000bcd565b62000cf89150843d861162000cff575b62000cef818362000a6e565b810190620037ab565b5f62000cc6565b503d62000ce3565b935050835163198ca60560e11b815282818981875afa908115620005c15788917f43d6c07ac63953f42a28f0366affe9895fd54f84336314dd012087bd0941df67915f9162000d5b575b5014159362000bc5565b62000d809150853d871162000d87575b62000d77818362000a6e565b810190620024c3565b5f62000d51565b503d62000d6b565b5f805160206200430583398151915254909450849062000db8906001600160a01b03166200042e565b149362000bbd565b3462000317575f36600319011262000317577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300362000e1b5760206040515f80516020620043058339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f36600319011262000317576001600160a01b0362000e4b62001c89565b163303620005eb57005b3462000317575f3660031901126200031757602060405160028152f35b3462000317575f36600319011262000317575f8051602062004305833981519152546040516001600160a01b039091168152602090f35b3462000317575f366003190112620003175760206200035f62001cc5565b3462000317576020366003190112620003175760206200035f60043562001cfc565b3462000317575f3660031901126200031757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015620005c1576020915f9162000f5d575b506040519015158152f35b62000f789150823d841162000c915762000c80818362000a6e565b5f62000f52565b3462000317576020366003190112620003175760043562000fa08162000367565b62000faa620023d8565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b34620003175760803660031901126200031757620010486200102b600435620010198162000367565b60643590604435906024359062001dfe565b604080519384526020840192909252908201529081906060820190565b0390f35b3462000317575f36600319011262000317576040518061019e805480845260208094019081925f527fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b905f5b86828210620010fb578686620010b18288038362000a6e565b60405192839281840190828552518091526040840192915f5b828110620010da57505050500390f35b83516001600160a01b031685528695509381019392810192600101620010ca565b83548552909301926001928301920162001098565b3462000317575f3660031901126200031757602061ffff60655460a01c16604051908152f35b346200031757600319604036820112620003175760049081356001600160401b03808211620003175760a0828501938336030112620003175760243590811162000317576200118990369085016200075c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b15620003175760405163837d444160e01b8152905f908290818381620011df8c828f0162001f2a565b03925af18015620005c15762001324575b50620011fb62002e12565b620012056200225e565b9081163314159182620012ed575b50509050620012dc576044019160c46200122e848462001fb4565b90500480158015620012c1575b620012b157620012556200124e62001c50565b916200200e565b11620012a2575060c46200126a838362001fb4565b9050145f146200128b576200002491620012849162001fb4565b9062003c70565b62000024916200129b9162001fb4565b9062003b23565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50620012ce848462001fb4565b905060c4820214156200123b565b604051634ca8886760e01b81528390fd5b620013179250620013106200131b94620013078862002ea5565b92369162000abd565b9162002f8a565b1590565b805f8062001213565b80620005d7620013349262000a06565b5f620011f0565b346200031757606036600319011262000317576004356024356200136460443582843362001dfe565b9192620013927f00000000000000000000000000000000000000000000000000000000000000008262001ce8565b42108015620015ca575b8015620015c1575b620015af577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693620013f986620013f3620013e76099546001600160801b031690565b6001600160801b031690565b62002b32565b156200150d57620014396200141e620014128662003066565b60995460801c62002028565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916200148091906200146f60808262000a6e565b5190205f52609b60205260405f2090565b555f9360018311620014bc575b505050506200149d82336200309a565b604080519485526020850191909152830152339180606081015b0390a2005b6200150292939450620014d0908862001ce8565b60408051336020820190815291810193909352606083018290526080958601835290949091906200146f908262000a6e565b555f8080806200148d565b6200151762002e12565b620015586200153c6200152a8662003066565b609e546001600160801b031662002028565b6001600160801b03166001600160801b0319609e541617609e55565b62001592620015776200156b8562003066565b609e5460801c62002028565b6001600160801b03609e549181199060801b16911617609e55565b620015a9620015a484609f5462001ce8565b609f55565b62001439565b604051630e3d8e8d60e11b8152600490fd5b508215620013a4565b5081156200139c565b346200031757604080600319360112620003175760243590600435620015f98362000367565b6200160362002e12565b8015620017c5576001600160a01b038316908115620017b457620016278162001bd9565b908115620017a3576200163a82620038c0565b620016458362003066565b60985460801c90620016579162002028565b62001677906001600160801b036098549181199060801b16911617609855565b62001683823362003f5b565b609e54958660801c8281609f54906200169c9162001ce8565b98620016a88762003066565b620016bc916001600160801b0316620034ab565b620016dd906001600160801b03166001600160801b0319609e541617609e55565b620016e89162001ce8565b620016f39062003066565b62001713906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906200174660808262000a6e565b5190206200175c905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3462000317575f366003190112620003175761019d546020906001600160a01b0390811680620018105750805f5416905b60405191168152f35b9062001807565b346200031757620014b77f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6200184d366200078c565b929062001859620023d8565b604051918291602083523395602084019162001f0a565b5f5b838110620018825750505f910152565b818101518382015260200162001872565b90602091620018ae8151809281855285808601910162001870565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310620018f05750505050505090565b909192939495848062001910600193603f198682030187528a5162001893565b9801930193019194939290620018df565b346200031757602036600319011262000317576001600160401b036004358181116200031757366023820112156200031757806004013591821162000317573660248360051b830101116200031757620010489160246200198392016200219d565b60405191829182620018ba565b906020620019a392818152019062001893565b90565b3462000317575f366003190112620003175762001048604051620019ca8162000a36565b60058152640352e302e360dc1b602082015260405191829160208352602083019062001893565b3462000317575f36600319011262000317576020620006e66200225e565b3462000317575f36600319011262000317576020620006e662002295565b3462000317576020366003190112620003175760206200035f60043562003139565b3462000317575f366003190112620003175760206001600160801b0360995416604051908152f35b346200031757602036600319011262000317576200002460043562001a9c8162000367565b62001aa6620023d8565b620031d6565b3462000317575f366003190112620003175760206001600160801b03609e5416604051908152f35b3462000317576020366003190112620003175760043562001af58162000367565b60018060a01b03165f52609c602052602060405f2054604051908152f35b3462000317576020366003190112620003175760043562001b348162000367565b61019c805490916001600160a01b039081169082168114620003fc577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d9281602093620003e6620023d8565b3462000317575f36600319011262000317575f546040516001600160a01b039091168152602090f35b6040366003190112620003175760206200035f60043562001bca8162000367565b60243590620006698262000367565b6098546001600160801b038116908162001bf257505090565b91620019a39260801c9062002354565b6040513d5f823e3d90fd5b90816020910312620003175751620019a38162000367565b62001c3462001c3c91620024ef565b9190620026a7565b62001c4357565b62001c4d62002880565b50565b476099546001600160801b0362001c6981831662001bd9565b90609e5416019060801c01908181115f1462001c83570390565b50505f90565b610137546001600160a01b0316801562001ca05790565b507f000000000000000000000000000000000000000000000000000000000000000090565b609d5480620019a357505f1990565b634e487b7160e01b5f52601160045260245ffd5b9190820180921162001cf657565b62001cd4565b6001600160801b036099541662001d126200387c565b90810180911162001cf657811062001d4c5762001d3c609f5462001d3562002b4c565b9062001ce8565b111562001d47575f90565b5f1990565b609a90609a549182915f905b84821062001d745750505081101562001d6e5790565b505f1990565b909193808316906001818518811c830180931162001cf6575f8790525f80516020620042e58339815191528301546001600160a01b031684101562001dbf575050935b919062001d58565b90959101925062001db7565b519081151582036200031757565b908160209103126200031757620019a39062001dcb565b9190820391821162001cf657565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919062001e3e81608081015b03601f19810183528262000a6e565b5190205f52609b60205260405f205491821562001eb3576001600160801b03609954169062001e6c6200387c565b91820180921162001cf657839183101562001e9e579162001e8d9262002c5b565b90915b82810390811162001cf65792565b509062001eab9162002bc1565b909162001e90565b5050505f905f905f90565b9035601e1982360301811215620003175701602081359101916001600160401b038211620003175781360383136200031757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620019a39260208152823560208201526020830135604082015262001f6b62001f5a604085018562001ebe565b84606085015260c084019162001f0a565b9062001fa462001f9862001f83606087018762001ebe565b601f1985870381016080870152959162001f0a565b94608081019062001ebe565b9390928286030191015262001f0a565b903590601e19813603018212156200031757018035906001600160401b03821162000317576020019181360383136200031757565b634e487b7160e01b5f52601260045260245ffd5b811562002008570490565b62001fe9565b906801bc16d674ec800000918083029283040362001cf657565b6001600160801b03918216908216039190821162001cf657565b6001600160401b038111620005e55760051b60200190565b90620020668262002042565b62002075604051918262000a6e565b828152809262002088601f199162002042565b01905f5b8281106200209957505050565b8060606020809385010152016200208c565b634e487b7160e01b5f52603260045260245ffd5b90821015620020d957620007ba9160051b81019062001fb4565b620020ab565b908092918237015f815290565b3d156200211b573d90620021008262000aa1565b9162002110604051938462000a6e565b82523d5f602084013e565b606090565b60208183031262000317578051906001600160401b03821162000317570181601f8201121562000317578051620021578162000aa1565b9262002167604051948562000a6e565b818452602082840101116200031757620019a3916020808501910162001870565b8051821015620020d95760209160051b010190565b919091620021ab836200205a565b925f5b818110620021bb57505050565b5f80620021ca838587620020bf565b60409391620021de855180938193620020df565b0390305af490620021ee620020ec565b91156200221b57509060019162002206828862002188565b5262002213818762002188565b5001620021ae565b90604481511062000317576200225a620022446004928381015160248091830101910162002120565b925162461bcd60e51b8152928392830162001990565b0390fd5b60d2546001600160a01b031680620019a357507f000000000000000000000000000000000000000000000000000000000000000090565b61019c546001600160a01b0390811680620022b157505f541690565b905090565b335f526101a160205260405f205415620022cc57565b62001c4d34336200323b565b90808202905f19818409908280831092039180830392146200234957612710908282111562002337577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514620023c957848311156200233757829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620019a3925062001ffd565b5f546001600160a01b03163303620005eb57565b908160609103126200031757805191620019a360406020840151930162001dcb565b81835290916001600160fb1b038311620003175760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103620003175760408301526040810135620024658162000367565b6001600160a01b031660608381019190915281013536829003601e1901811215620003175701602081359101906001600160401b03811162000317578060051b36038213620003175760a083608080620019a396015201916200240e565b9081602091031262000317575190565b9190915f838201938412911290801582169115161762001cf657565b6040516325f56f1160e01b81526001600160a01b039291606090829081906200251c906004830162002433565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315620005c1575f915f905f956200265a575b508415620025ff57816200256b62001c89565b16917f0000000000000000000000000000000000000000000000000000000000000000168214620025f757509060205f92600460405180958193634641257d60e01b83525af1908115620005c157620025cd925f92620025d1575b50620024d3565b9190565b620025ef91925060203d60201162000d875762000d77818362000a6e565b905f620025c6565b908162002605575b50509190565b803b156200031757604051636ee3193160e11b815260048101929092525f908290602490829084905af18015620005c15762002643575b80620025ff565b80620005d7620026539262000a06565b5f6200263c565b9194505062002685915060603d6060116200268e575b6200267c818362000a6e565b810190620023ec565b93905f62002558565b503d62002670565b600160ff1b811462001cf6575f0390565b801562001c4d57620026bf620013e760985460801c90565b5f8212620027c45781620026d39162001ce8565b90620026fe620026e38362003066565b6001600160801b036098549181199060801b16911617609855565b620027156065549161ffff8360a01c1690620022d8565b8015620027bf57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362002756620013e76098546001600160801b031690565b80620027a5575050620027a090925b6001600160a01b0316916200277b8484620034c7565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b620027a092620027b89203908462002354565b9262002765565b505050565b90620027d09062002696565b620027e7620013e7609e546001600160801b031690565b8062002813575b5080620027f9575050565b6200280d620026e39162000a9f9362001df0565b62003066565b90620028767f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91620028666200153c6200285a62002852888862001ce8565b878562002354565b80809403960362003066565b6040519081529081906020820190565b0390a15f620027ee565b609954906001600160801b038216918215620029c15760801c620028bb620028a9824762001df0565b620028b48562001bd9565b9062003517565b908115620029ba57620028ce8262003139565b938415620029b25782620029276200141e6200280d62000a9f96620026e39662002921620029056200280d8d620029a69a62001df0565b6001600160801b03166001600160801b03196099541617609955565b62001ce8565b62002933818762003581565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a16200280d6200298a620029788862003066565b6098546001600160801b031662002028565b6001600160801b03166001600160801b03196098541617609855565b60985460801c62002028565b505f93505050565b505f925050565b505f9150565b620029d162003664565b6040830151620029e062003664565b6001600160a01b038216801562002ac3576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528062002a3c3394602083019062001893565b0390a260208301519262002a4f62003664565b61271061ffff85161162002ab15762002aa79362002a7162002a9793620031d6565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551620036a6565b62002aa1620036da565b6200370d565b62000a9f6200373f565b604051638a81d3b360e01b8152600490fd5b60405163d92e233d60e01b8152600490fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562002b15575b505062000e1b57565b5f80516020620043058339815191525416141590505f8062002b0c565b9062002b3d6200387c565b91820180921162001cf6571090565b476099548060801c820391821162001cf6578162002b746001600160801b0380931662001bd9565b908162002ba0575b5050811562001c8357620019a39162002b9a91609e54169062003517565b620038c0565b919250908181111562002bb857035b905f8062002b7c565b50505f62002baf565b62002bcb62002b4c565b91609f5492830180931162001cf6578083111562002c1c5762002bf092039062003517565b90609e548060801c80155f1462002c075750508190565b6001600160801b03620019a392168462002354565b5050505f905f90565b90604051604081018181106001600160401b03821117620005e55760405291546001600160a01b038116835260a01c6020830152565b609a545f94859493909180841080159062002e09575b62002dfc578362002dc5575f5b609a5f526001600160a01b031662002ca65f80516020620042e5833981519152860162002c25565b805190979062002cbf906001600160a01b03166200042e565b9862002ce662002cda6020809b01516001600160601b031690565b6001600160601b031690565b94838110801562002dba575b62002da85791600193979a9562002d1562002d22939488035b838c039062003517565b8092019887039162002354565b0197019380861180159062002d9d575b62002d9257609a5f52829062002d585f80516020620042e5833981519152870162002c25565b805190890151969992966001600160a01b03909116946001939262002d229290916001600160601b039091169062002d1590880362002d0b565b945050509250509190565b508185101562002d32565b60405163e8722f8f60e01b8152600490fd5b50808b111562002cf2565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031662002c7e565b505093505050505f905f90565b50841562002c71565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115620005c1575f9162002e81575b5062002e6f57565b60405163e775715160e01b8152600490fd5b62002e9e915060203d60201162000c915762000c80818362000a6e565b5f62002e67565b604290467f00000000000000000000000000000000000000000000000000000000000000000362002f5a5760d354905b62002ef062002ee8604083018362001fb4565b369162000abd565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815262002f3d8162000a52565b5190206040519161190160f01b8352600283015260228201522090565b62002f64620038fc565b9062002ed5565b6004111562002f7657565b634e487b7160e01b5f52602160045260245ffd5b62002f968383620039cc565b5062002fa58195929562002f6b565b1593846200304f575b50831562002fbd575b50505090565b5f92935090829160405162002ff88162001e2f6020820194630b135d3f60e11b998a8752602484015260406044840152606483019062001893565b51915afa9062003007620020ec565b8262003040575b8262003020575b50505f808062002fb7565b6200303791925060208082518301019101620024c3565b145f8062003015565b9150602082511015916200300e565b6001600160a01b0383811691161493505f62002fae565b6001600160801b03908181116200307b571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146200312757600283558147106200310f575f918291829182916001600160a01b03165af1620030f0620020ec565b5015620030fd5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b038216811580156200316c575b156200315d5750905090565b620019a39260801c9162002354565b50801562003151565b6098546001600160801b0381169082158015620031cd575b156200319857505090565b60801c90620031a982828562002354565b928215620020085709620031ba5790565b6001810180911115620019a35762001cd4565b5081156200318d565b620031e062002e12565b6001600160a01b031680156200322957606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b91906200324762002e12565b6001600160a01b03831690811562002ac357801562003301578062003272620013e760985460801c90565b01936200327e62001cc5565b8511620032ef57620026e394620032ad91620032a76200329e8562003175565b97889362003066565b620034c7565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926200332162002e12565b6001600160a01b03821691821562002ac35781156200330157816200334c620013e760985460801c90565b016200335762001cc5565b8111620032ef57620026e395620033a6620032ea927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94620032a76200339d8862003175565b9a8b9362003066565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f5261019f8060205260405f2054155f1462001c835761019e8054600160401b811015620005e55760018101808355811015620020d95783907fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b015554915f5260205260405f2055600190565b805f526101a18060205260405f2054155f1462001c83576101a08054600160401b811015620005e55760018101808355811015620020d95783907f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c4015554915f5260205260405f2055600190565b9190916001600160801b038080941691160191821162001cf657565b620034d28262003066565b60985490620034ec6001600160801b0391828416620034ab565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015620022b1575090565b609a5490600160401b821015620005e5576001820180609a55821015620020d957609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020620042e583398151915290910155565b919091801580156200365b575b62003649576200359d6200387c565b90810180911162001cf6576001600160a01b0380821162003629576001600160601b039081851162003609579062000a9f9394620035f26200360393620035e362000a90565b95166001600160a01b03168552565b166001600160601b03166020830152565b62003525565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b5082156200358e565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156200369457565b604051631afcd79f60e31b8152600490fd5b620036b062003664565b8015620036c85760018101620036c35750565b609d55565b6040516331278a8760e01b8152600490fd5b620036e462003664565b6801bc16d674ec800000620036f862001cc5565b10620036c85762003708620038fc565b60d355565b6200371762003664565b6001600160a01b031680620037295750565b61013780546001600160a01b0319169091179055565b6200374962003664565b6200375362003664565b6200375d62003664565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410620037995762001c4d34306200323b565b60405163ea2559bb60e01b8152600490fd5b9081602091031262000317575160ff81168103620003175790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948162003856575b506200381857604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206200430583398151915284036200383d5762000a9f92935062003d68565b604051632a87526960e21b815260048101859052602490fd5b6200387491955060203d60201162000d875762000d77818362000a6e565b935f620037f1565b609a54806200388a57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166200042e565b609e54908160801c81158015620038f3575b15620038de5750905090565b6001600160801b03620019a393169162002354565b508015620038d2565b6e5661756c7456616c696461746f727360881b60206040516200391f8162000a36565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117620005e55760405251902090565b8151919060418303620039ff57620039f89250602082015190606060408401519301515f1a9062003e10565b9192909190565b50505f9160029190565b90603011620003175790603090565b909291928360b01162000317578311620003175760b0019160af190190565b90609011620003175760300190606090565b9060c411620003175760900190603490565b909392938483116200031757841162000317578101920390565b35906020811062003a84575090565b5f199060200360031b1b1690565b95949362003ac462003ad39362003ab56060969460808b5260808b019062001ef2565b9089820360208b015262001893565b91878303604089015262001f0a565b930152565b9695949062003ad39362003ab562003ac4926060979560808c5260808c019162001f0a565b906020620019a392818152019062001ef2565b916020620019a393818152019162001f0a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062003b6c575050505050505050565b8262003b7d91018092878762003a5b565b9062003b8a828262003a09565b9162003ba362003b9c85808462003a18565b9062003e95565b9062003bc862003bc162003bb8878462003a37565b97909362003a49565b9062003a75565b948c3b1562000317578c5f926801bc16d674ec80000060409562003c0487519a8b96879586946304512a2360e31b86528d8d6004880162003ad8565b03925af1908115620005c1577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19462003c499262003c59575b50519283928362003b10565b0390a16001819301929062003b5a565b80620005d762003c699262000a06565b5f62003c3d565b8160301162000317577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169162003cb562003b9c82808562003a18565b62003cc1828462003a37565b94909260b0116200031757803b15620003175762003d0a946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162003a92565b03925af1908115620005c1577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192620027a09262003d51575b506040519182918262003afd565b80620005d762003d619262000a06565b5f62003d43565b90813b1562003def575f805160206200430583398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562003dd35762001c4d9162003fab565b50503462003ddd57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162003e8a579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15620005c1575f516001600160a01b0381161562003e8057905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362003f49576bffffffffffffffffffffffff19919035828116916014811062003f33575b5050905060601c62003edf62001317825f5261019f60205260405f2054151590565b62003f215760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c830152620019a3908290810162001e2f565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062003ebd565b604051639be7315960e01b8152600490fd5b60018060a01b03165f52609c60205260405f2090815481810390811162001cf65762003f88925562003066565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f80620019a393602081519101845af462003fc5620020ec565b919062003fdd5750805115620030fd57805190602001fd5b8151158062004012575b62003ff0575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562003fe756fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003344da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220fa998e0f720a3b6c86d4486b23f1ab9d407deb883f0b2b5826894f6e1ae1ee1d64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101562000026575b36156200001a575f80fd5b62000024620022b6565b005b5f3560e01c806301e1d114146200030657806307a2d13a1462000300578063096ae80d14620002fa5780630b10b20114620002f457806318f7295014620002ee5780631a7ff55314620002e85780632cdf740114620002e25780633229fa9514620002dc57806333194c0a14620002d65780633a98ef3914620002d0578063439fab9114620002ca5780634690484014620002c45780634f1ef28614620002be57806352d1902d14620002b857806353156f2814620002b257806354fd4d5014620002ac5780635c60da1b14620002a65780635cfc1a5114620002a057806360d60e6e146200029a57806372b410a81462000294578063754c3888146200028e57806376b58b9014620002885780637b6341c614620002825780637fd6f15c146200027c57806383d430d514620002765780638697d2c214620002705780638ceab9aa146200026a578063a045dd0c1462000264578063a49a1e7d146200025e578063ac9650d81462000258578063ad3cb1cc1462000252578063b1f0e7c7146200024c578063c5aecb221462000246578063c6e6f5921462000240578063d83ad00c146200023a578063e74b981b1462000234578063ee3bd5df146200022e578063f04da65b1462000228578063f132f5d31462000222578063f851a440146200021c5763f9609f08036200000f5762001ba9565b62001b80565b62001b13565b62001ad4565b62001aac565b62001a77565b62001a4f565b62001a2d565b62001a0f565b620019f1565b620019a6565b62001921565b62001817565b620017d6565b620015d3565b6200133b565b62001136565b62001110565b6200104c565b62000ff0565b62000f7f565b62000ee9565b62000ec7565b62000ea9565b62000e72565b62000e55565b62000e2d565b62000dc0565b62000af8565b620009c8565b620007be565b62000734565b620006f8565b620006c8565b620006aa565b62000671565b6200060c565b6200040e565b62000379565b6200033d565b6200031b565b5f9103126200031757565b5f80fd5b3462000317575f3660031901126200031757602060985460801c604051908152f35b3462000317576020366003190112620003175760206200035f60043562001bd9565b604051908152f35b6001600160a01b038116036200031757565b346200031757602036600319011262000317576004356200039a8162000367565b61019d805490916001600160a01b039081169082168114620003fc577f890ff5077ab1949ce16449a660eb28ce16646b4c99e0901266d44a1042b1f9e89281602093620003e6620023d8565b6001600160a01b031916179055604051908152a1005b604051638c8728c760e01b8152600490fd5b3462000317575f36600319011262000317576200043a6200042e62002295565b6001600160a01b031690565b3303620005eb576040516102c8808201908282106001600160401b03831117620005e5578291620004ab916200401d84396001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526040602082018190525f9082015260600190565b03905ff08015620005c1576001600160a01b0390811690813b15620003175760405163439fab9160e01b8152602060048201525f602482018190528160448183875af18015620005c157620005c7575b506040516351d5709b60e11b815291602083600481845afa918215620005c1577fcdc82cfed67d9b46d3a15dd3b48745fb894a354d554cb5da5fb8c440f85c108e935f9362000584575b5062000553908316620033cf565b506200055f816200343d565b50604080516001600160a01b039283168152929091166020830152819081015b0390a1005b62000553919350620005b19060203d602011620005b9575b620005a8818362000a6e565b81019062001c0d565b929062000545565b503d6200059c565b62001c02565b80620005d7620005de9262000a06565b806200030c565b5f620004fb565b620009f2565b604051634ca8886760e01b8152600490fd5b90816080910312620003175790565b60603660031901126200031757600435620006278162000367565b602435620006358162000367565b604435906001600160401b038211620003175760209262000669620006636200035f943690600401620005fd565b62001c25565b349062003313565b346200031757602036600319011262000317576004356001600160401b03811162000317576200066362000024913690600401620005fd565b3462000317575f366003190112620003175760206200035f62001c50565b3462000317575f36600319011262000317576020620006e662001c89565b6040516001600160a01b039091168152f35b3462000317575f366003190112620003175760206040517f43d6c07ac63953f42a28f0366affe9895fd54f84336314dd012087bd0941df678152f35b3462000317575f366003190112620003175760206001600160801b0360985416604051908152f35b9181601f8401121562000317578235916001600160401b0383116200031757602083818601950101116200031757565b60206003198201126200031757600435906001600160401b0382116200031757620007ba916004016200075c565b9091565b620007c9366200078c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c168015620009b3575b620009a25768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020918285600481335afa948515620005c1575f956200097e575b508351636f4fa30f60e01b8152908382600481335afa918215620005c1575f926200095a575b508201948383870312620003175782356001600160401b0393848211620003175701926060848803126200031757855193620008a78562000a1a565b803585528581013561ffff81168103620003175786860152868101359182116200031757019386601f8601121562000317577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d296856200090f92620009199735910162000abd565b85840152620029c7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055516002815280602081016200057f565b62000976919250843d8611620005b957620005a8818362000a6e565b905f6200086b565b6200099a919550833d8511620005b957620005a8818362000a6e565b935f62000845565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015620007ff565b3462000317575f36600319011262000317576065546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111620005e557604052565b606081019081106001600160401b03821117620005e557604052565b604081019081106001600160401b03821117620005e557604052565b608081019081106001600160401b03821117620005e557604052565b90601f801991011681019081106001600160401b03821117620005e557604052565b6040519062000a9f8262000a36565b565b6001600160401b038111620005e557601f01601f191660200190565b92919262000acb8262000aa1565b9162000adb604051938462000a6e565b82948184528183011162000317578281602093845f960137010152565b6040806003193601126200031757600490813562000b168162000367565b6024356001600160401b038111620003175736602382011215620003175762000b49903690602481870135910162000abd565b9162000b5462002ad5565b80519262000b8f8462000b8060209363439fab9160e01b85840152846024840152604483019062001893565b03601f19810186528562000a6e565b62000b9962002ad5565b62000ba3620023d8565b6001600160a01b0383811680159291908790841562000d8f575b841562000d07575b841562000c99575b5050821562000bf9575b505062000bea57620000248383620037c6565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215620005c1575f9262000c65575b5050155f8062000bd7565b62000c899250803d1062000c91575b62000c80818362000a6e565b81019062001dd9565b5f8062000c5a565b503d62000c74565b855163054fd4d560e41b81529294508391839182905afa908115620005c15760039160ff915f9162000cd3575b5016141591865f62000bcd565b62000cf89150843d861162000cff575b62000cef818362000a6e565b810190620037ab565b5f62000cc6565b503d62000ce3565b935050835163198ca60560e11b815282818981875afa908115620005c15788917f43d6c07ac63953f42a28f0366affe9895fd54f84336314dd012087bd0941df67915f9162000d5b575b5014159362000bc5565b62000d809150853d871162000d87575b62000d77818362000a6e565b810190620024c3565b5f62000d51565b503d62000d6b565b5f805160206200430583398151915254909450849062000db8906001600160a01b03166200042e565b149362000bbd565b3462000317575f36600319011262000317577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300362000e1b5760206040515f80516020620043058339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f36600319011262000317576001600160a01b0362000e4b62001c89565b163303620005eb57005b3462000317575f3660031901126200031757602060405160028152f35b3462000317575f36600319011262000317575f8051602062004305833981519152546040516001600160a01b039091168152602090f35b3462000317575f366003190112620003175760206200035f62001cc5565b3462000317576020366003190112620003175760206200035f60043562001cfc565b3462000317575f3660031901126200031757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015620005c1576020915f9162000f5d575b506040519015158152f35b62000f789150823d841162000c915762000c80818362000a6e565b5f62000f52565b3462000317576020366003190112620003175760043562000fa08162000367565b62000faa620023d8565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b34620003175760803660031901126200031757620010486200102b600435620010198162000367565b60643590604435906024359062001dfe565b604080519384526020840192909252908201529081906060820190565b0390f35b3462000317575f36600319011262000317576040518061019e805480845260208094019081925f527fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b905f5b86828210620010fb578686620010b18288038362000a6e565b60405192839281840190828552518091526040840192915f5b828110620010da57505050500390f35b83516001600160a01b031685528695509381019392810192600101620010ca565b83548552909301926001928301920162001098565b3462000317575f3660031901126200031757602061ffff60655460a01c16604051908152f35b346200031757600319604036820112620003175760049081356001600160401b03808211620003175760a0828501938336030112620003175760243590811162000317576200118990369085016200075c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b15620003175760405163837d444160e01b8152905f908290818381620011df8c828f0162001f2a565b03925af18015620005c15762001324575b50620011fb62002e12565b620012056200225e565b9081163314159182620012ed575b50509050620012dc576044019160c46200122e848462001fb4565b90500480158015620012c1575b620012b157620012556200124e62001c50565b916200200e565b11620012a2575060c46200126a838362001fb4565b9050145f146200128b576200002491620012849162001fb4565b9062003c70565b62000024916200129b9162001fb4565b9062003b23565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50620012ce848462001fb4565b905060c4820214156200123b565b604051634ca8886760e01b81528390fd5b620013179250620013106200131b94620013078862002ea5565b92369162000abd565b9162002f8a565b1590565b805f8062001213565b80620005d7620013349262000a06565b5f620011f0565b346200031757606036600319011262000317576004356024356200136460443582843362001dfe565b9192620013927f00000000000000000000000000000000000000000000000000000000000000008262001ce8565b42108015620015ca575b8015620015c1575b620015af577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693620013f986620013f3620013e76099546001600160801b031690565b6001600160801b031690565b62002b32565b156200150d57620014396200141e620014128662003066565b60995460801c62002028565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916200148091906200146f60808262000a6e565b5190205f52609b60205260405f2090565b555f9360018311620014bc575b505050506200149d82336200309a565b604080519485526020850191909152830152339180606081015b0390a2005b6200150292939450620014d0908862001ce8565b60408051336020820190815291810193909352606083018290526080958601835290949091906200146f908262000a6e565b555f8080806200148d565b6200151762002e12565b620015586200153c6200152a8662003066565b609e546001600160801b031662002028565b6001600160801b03166001600160801b0319609e541617609e55565b62001592620015776200156b8562003066565b609e5460801c62002028565b6001600160801b03609e549181199060801b16911617609e55565b620015a9620015a484609f5462001ce8565b609f55565b62001439565b604051630e3d8e8d60e11b8152600490fd5b508215620013a4565b5081156200139c565b346200031757604080600319360112620003175760243590600435620015f98362000367565b6200160362002e12565b8015620017c5576001600160a01b038316908115620017b457620016278162001bd9565b908115620017a3576200163a82620038c0565b620016458362003066565b60985460801c90620016579162002028565b62001677906001600160801b036098549181199060801b16911617609855565b62001683823362003f5b565b609e54958660801c8281609f54906200169c9162001ce8565b98620016a88762003066565b620016bc916001600160801b0316620034ab565b620016dd906001600160801b03166001600160801b0319609e541617609e55565b620016e89162001ce8565b620016f39062003066565b62001713906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906200174660808262000a6e565b5190206200175c905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a351908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3462000317575f366003190112620003175761019d546020906001600160a01b0390811680620018105750805f5416905b60405191168152f35b9062001807565b346200031757620014b77f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6200184d366200078c565b929062001859620023d8565b604051918291602083523395602084019162001f0a565b5f5b838110620018825750505f910152565b818101518382015260200162001872565b90602091620018ae8151809281855285808601910162001870565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310620018f05750505050505090565b909192939495848062001910600193603f198682030187528a5162001893565b9801930193019194939290620018df565b346200031757602036600319011262000317576001600160401b036004358181116200031757366023820112156200031757806004013591821162000317573660248360051b830101116200031757620010489160246200198392016200219d565b60405191829182620018ba565b906020620019a392818152019062001893565b90565b3462000317575f366003190112620003175762001048604051620019ca8162000a36565b60058152640352e302e360dc1b602082015260405191829160208352602083019062001893565b3462000317575f36600319011262000317576020620006e66200225e565b3462000317575f36600319011262000317576020620006e662002295565b3462000317576020366003190112620003175760206200035f60043562003139565b3462000317575f366003190112620003175760206001600160801b0360995416604051908152f35b346200031757602036600319011262000317576200002460043562001a9c8162000367565b62001aa6620023d8565b620031d6565b3462000317575f366003190112620003175760206001600160801b03609e5416604051908152f35b3462000317576020366003190112620003175760043562001af58162000367565b60018060a01b03165f52609c602052602060405f2054604051908152f35b3462000317576020366003190112620003175760043562001b348162000367565b61019c805490916001600160a01b039081169082168114620003fc577f399f9aba7ac1bda99e0bee41ebd93a32387a0f37b3934265478e96121dac166d9281602093620003e6620023d8565b3462000317575f36600319011262000317575f546040516001600160a01b039091168152602090f35b6040366003190112620003175760206200035f60043562001bca8162000367565b60243590620006698262000367565b6098546001600160801b038116908162001bf257505090565b91620019a39260801c9062002354565b6040513d5f823e3d90fd5b90816020910312620003175751620019a38162000367565b62001c3462001c3c91620024ef565b9190620026a7565b62001c4357565b62001c4d62002880565b50565b476099546001600160801b0362001c6981831662001bd9565b90609e5416019060801c01908181115f1462001c83570390565b50505f90565b610137546001600160a01b0316801562001ca05790565b507f000000000000000000000000000000000000000000000000000000000000000090565b609d5480620019a357505f1990565b634e487b7160e01b5f52601160045260245ffd5b9190820180921162001cf657565b62001cd4565b6001600160801b036099541662001d126200387c565b90810180911162001cf657811062001d4c5762001d3c609f5462001d3562002b4c565b9062001ce8565b111562001d47575f90565b5f1990565b609a90609a549182915f905b84821062001d745750505081101562001d6e5790565b505f1990565b909193808316906001818518811c830180931162001cf6575f8790525f80516020620042e58339815191528301546001600160a01b031684101562001dbf575050935b919062001d58565b90959101925062001db7565b519081151582036200031757565b908160209103126200031757620019a39062001dcb565b9190820391821162001cf657565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919062001e3e81608081015b03601f19810183528262000a6e565b5190205f52609b60205260405f205491821562001eb3576001600160801b03609954169062001e6c6200387c565b91820180921162001cf657839183101562001e9e579162001e8d9262002c5b565b90915b82810390811162001cf65792565b509062001eab9162002bc1565b909162001e90565b5050505f905f905f90565b9035601e1982360301811215620003175701602081359101916001600160401b038211620003175781360383136200031757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0620019a39260208152823560208201526020830135604082015262001f6b62001f5a604085018562001ebe565b84606085015260c084019162001f0a565b9062001fa462001f9862001f83606087018762001ebe565b601f1985870381016080870152959162001f0a565b94608081019062001ebe565b9390928286030191015262001f0a565b903590601e19813603018212156200031757018035906001600160401b03821162000317576020019181360383136200031757565b634e487b7160e01b5f52601260045260245ffd5b811562002008570490565b62001fe9565b906801bc16d674ec800000918083029283040362001cf657565b6001600160801b03918216908216039190821162001cf657565b6001600160401b038111620005e55760051b60200190565b90620020668262002042565b62002075604051918262000a6e565b828152809262002088601f199162002042565b01905f5b8281106200209957505050565b8060606020809385010152016200208c565b634e487b7160e01b5f52603260045260245ffd5b90821015620020d957620007ba9160051b81019062001fb4565b620020ab565b908092918237015f815290565b3d156200211b573d90620021008262000aa1565b9162002110604051938462000a6e565b82523d5f602084013e565b606090565b60208183031262000317578051906001600160401b03821162000317570181601f8201121562000317578051620021578162000aa1565b9262002167604051948562000a6e565b818452602082840101116200031757620019a3916020808501910162001870565b8051821015620020d95760209160051b010190565b919091620021ab836200205a565b925f5b818110620021bb57505050565b5f80620021ca838587620020bf565b60409391620021de855180938193620020df565b0390305af490620021ee620020ec565b91156200221b57509060019162002206828862002188565b5262002213818762002188565b5001620021ae565b90604481511062000317576200225a620022446004928381015160248091830101910162002120565b925162461bcd60e51b8152928392830162001990565b0390fd5b60d2546001600160a01b031680620019a357507f000000000000000000000000000000000000000000000000000000000000000090565b61019c546001600160a01b0390811680620022b157505f541690565b905090565b335f526101a160205260405f205415620022cc57565b62001c4d34336200323b565b90808202905f19818409908280831092039180830392146200234957612710908282111562002337577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514620023c957848311156200233757829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090620019a3925062001ffd565b5f546001600160a01b03163303620005eb57565b908160609103126200031757805191620019a360406020840151930162001dcb565b81835290916001600160fb1b038311620003175760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103620003175760408301526040810135620024658162000367565b6001600160a01b031660608381019190915281013536829003601e1901811215620003175701602081359101906001600160401b03811162000317578060051b36038213620003175760a083608080620019a396015201916200240e565b9081602091031262000317575190565b9190915f838201938412911290801582169115161762001cf657565b6040516325f56f1160e01b81526001600160a01b039291606090829081906200251c906004830162002433565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315620005c1575f915f905f956200265a575b508415620025ff57816200256b62001c89565b16917f0000000000000000000000000000000000000000000000000000000000000000168214620025f757509060205f92600460405180958193634641257d60e01b83525af1908115620005c157620025cd925f92620025d1575b50620024d3565b9190565b620025ef91925060203d60201162000d875762000d77818362000a6e565b905f620025c6565b908162002605575b50509190565b803b156200031757604051636ee3193160e11b815260048101929092525f908290602490829084905af18015620005c15762002643575b80620025ff565b80620005d7620026539262000a06565b5f6200263c565b9194505062002685915060603d6060116200268e575b6200267c818362000a6e565b810190620023ec565b93905f62002558565b503d62002670565b600160ff1b811462001cf6575f0390565b801562001c4d57620026bf620013e760985460801c90565b5f8212620027c45781620026d39162001ce8565b90620026fe620026e38362003066565b6001600160801b036098549181199060801b16911617609855565b620027156065549161ffff8360a01c1690620022d8565b8015620027bf57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479362002756620013e76098546001600160801b031690565b80620027a5575050620027a090925b6001600160a01b0316916200277b8484620034c7565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b620027a092620027b89203908462002354565b9262002765565b505050565b90620027d09062002696565b620027e7620013e7609e546001600160801b031690565b8062002813575b5080620027f9575050565b6200280d620026e39162000a9f9362001df0565b62003066565b90620028767f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91620028666200153c6200285a62002852888862001ce8565b878562002354565b80809403960362003066565b6040519081529081906020820190565b0390a15f620027ee565b609954906001600160801b038216918215620029c15760801c620028bb620028a9824762001df0565b620028b48562001bd9565b9062003517565b908115620029ba57620028ce8262003139565b938415620029b25782620029276200141e6200280d62000a9f96620026e39662002921620029056200280d8d620029a69a62001df0565b6001600160801b03166001600160801b03196099541617609955565b62001ce8565b62002933818762003581565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a16200280d6200298a620029788862003066565b6098546001600160801b031662002028565b6001600160801b03166001600160801b03196098541617609855565b60985460801c62002028565b505f93505050565b505f925050565b505f9150565b620029d162003664565b6040830151620029e062003664565b6001600160a01b038216801562002ac3576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528062002a3c3394602083019062001893565b0390a260208301519262002a4f62003664565b61271061ffff85161162002ab15762002aa79362002a7162002a9793620031d6565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551620036a6565b62002aa1620036da565b6200370d565b62000a9f6200373f565b604051638a81d3b360e01b8152600490fd5b60405163d92e233d60e01b8152600490fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821562002b15575b505062000e1b57565b5f80516020620043058339815191525416141590505f8062002b0c565b9062002b3d6200387c565b91820180921162001cf6571090565b476099548060801c820391821162001cf6578162002b746001600160801b0380931662001bd9565b908162002ba0575b5050811562001c8357620019a39162002b9a91609e54169062003517565b620038c0565b919250908181111562002bb857035b905f8062002b7c565b50505f62002baf565b62002bcb62002b4c565b91609f5492830180931162001cf6578083111562002c1c5762002bf092039062003517565b90609e548060801c80155f1462002c075750508190565b6001600160801b03620019a392168462002354565b5050505f905f90565b90604051604081018181106001600160401b03821117620005e55760405291546001600160a01b038116835260a01c6020830152565b609a545f94859493909180841080159062002e09575b62002dfc578362002dc5575f5b609a5f526001600160a01b031662002ca65f80516020620042e5833981519152860162002c25565b805190979062002cbf906001600160a01b03166200042e565b9862002ce662002cda6020809b01516001600160601b031690565b6001600160601b031690565b94838110801562002dba575b62002da85791600193979a9562002d1562002d22939488035b838c039062003517565b8092019887039162002354565b0197019380861180159062002d9d575b62002d9257609a5f52829062002d585f80516020620042e5833981519152870162002c25565b805190890151969992966001600160a01b03909116946001939262002d229290916001600160601b039091169062002d1590880362002d0b565b945050509250509190565b508185101562002d32565b60405163e8722f8f60e01b8152600490fd5b50808b111562002cf2565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031662002c7e565b505093505050505f905f90565b50841562002c71565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115620005c1575f9162002e81575b5062002e6f57565b60405163e775715160e01b8152600490fd5b62002e9e915060203d60201162000c915762000c80818362000a6e565b5f62002e67565b604290467f00000000000000000000000000000000000000000000000000000000000000000362002f5a5760d354905b62002ef062002ee8604083018362001fb4565b369162000abd565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815262002f3d8162000a52565b5190206040519161190160f01b8352600283015260228201522090565b62002f64620038fc565b9062002ed5565b6004111562002f7657565b634e487b7160e01b5f52602160045260245ffd5b62002f968383620039cc565b5062002fa58195929562002f6b565b1593846200304f575b50831562002fbd575b50505090565b5f92935090829160405162002ff88162001e2f6020820194630b135d3f60e11b998a8752602484015260406044840152606483019062001893565b51915afa9062003007620020ec565b8262003040575b8262003020575b50505f808062002fb7565b6200303791925060208082518301019101620024c3565b145f8062003015565b9150602082511015916200300e565b6001600160a01b0383811691161493505f62002fae565b6001600160801b03908181116200307b571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146200312757600283558147106200310f575f918291829182916001600160a01b03165af1620030f0620020ec565b5015620030fd5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b038216811580156200316c575b156200315d5750905090565b620019a39260801c9162002354565b50801562003151565b6098546001600160801b0381169082158015620031cd575b156200319857505090565b60801c90620031a982828562002354565b928215620020085709620031ba5790565b6001810180911115620019a35762001cd4565b5081156200318d565b620031e062002e12565b6001600160a01b031680156200322957606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b91906200324762002e12565b6001600160a01b03831690811562002ac357801562003301578062003272620013e760985460801c90565b01936200327e62001cc5565b8511620032ef57620026e394620032ad91620032a76200329e8562003175565b97889362003066565b620034c7565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926200332162002e12565b6001600160a01b03821691821562002ac35781156200330157816200334c620013e760985460801c90565b016200335762001cc5565b8111620032ef57620026e395620033a6620032ea927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94620032a76200339d8862003175565b9a8b9362003066565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b805f5261019f8060205260405f2054155f1462001c835761019e8054600160401b811015620005e55760018101808355811015620020d95783907fe182ec4162b2bb087af6d462e45917a32b2b0170bcaf1db406b2ae4590b6953b015554915f5260205260405f2055600190565b805f526101a18060205260405f2054155f1462001c83576101a08054600160401b811015620005e55760018101808355811015620020d95783907f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c4015554915f5260205260405f2055600190565b9190916001600160801b038080941691160191821162001cf657565b620034d28262003066565b60985490620034ec6001600160801b0391828416620034ab565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015620022b1575090565b609a5490600160401b821015620005e5576001820180609a55821015620020d957609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020620042e583398151915290910155565b919091801580156200365b575b62003649576200359d6200387c565b90810180911162001cf6576001600160a01b0380821162003629576001600160601b039081851162003609579062000a9f9394620035f26200360393620035e362000a90565b95166001600160a01b03168552565b166001600160601b03166020830152565b62003525565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b5082156200358e565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156200369457565b604051631afcd79f60e31b8152600490fd5b620036b062003664565b8015620036c85760018101620036c35750565b609d55565b6040516331278a8760e01b8152600490fd5b620036e462003664565b6801bc16d674ec800000620036f862001cc5565b10620036c85762003708620038fc565b60d355565b6200371762003664565b6001600160a01b031680620037295750565b61013780546001600160a01b0319169091179055565b6200374962003664565b6200375362003664565b6200375d62003664565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410620037995762001c4d34306200323b565b60405163ea2559bb60e01b8152600490fd5b9081602091031262000317575160ff81168103620003175790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948162003856575b506200381857604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206200430583398151915284036200383d5762000a9f92935062003d68565b604051632a87526960e21b815260048101859052602490fd5b6200387491955060203d60201162000d875762000d77818362000a6e565b935f620037f1565b609a54806200388a57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166200042e565b609e54908160801c81158015620038f3575b15620038de5750905090565b6001600160801b03620019a393169162002354565b508015620038d2565b6e5661756c7456616c696461746f727360881b60206040516200391f8162000a36565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117620005e55760405251902090565b8151919060418303620039ff57620039f89250602082015190606060408401519301515f1a9062003e10565b9192909190565b50505f9160029190565b90603011620003175790603090565b909291928360b01162000317578311620003175760b0019160af190190565b90609011620003175760300190606090565b9060c411620003175760900190603490565b909392938483116200031757841162000317578101920390565b35906020811062003a84575090565b5f199060200360031b1b1690565b95949362003ac462003ad39362003ab56060969460808b5260808b019062001ef2565b9089820360208b015262001893565b91878303604089015262001f0a565b930152565b9695949062003ad39362003ab562003ac4926060979560808c5260808c019162001f0a565b906020620019a392818152019062001ef2565b916020620019a393818152019162001f0a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169160c480820492905f9081805b86841062003b6c575050505050505050565b8262003b7d91018092878762003a5b565b9062003b8a828262003a09565b9162003ba362003b9c85808462003a18565b9062003e95565b9062003bc862003bc162003bb8878462003a37565b97909362003a49565b9062003a75565b948c3b1562000317578c5f926801bc16d674ec80000060409562003c0487519a8b96879586946304512a2360e31b86528d8d6004880162003ad8565b03925af1908115620005c1577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19462003c499262003c59575b50519283928362003b10565b0390a16001819301929062003b5a565b80620005d762003c699262000a06565b5f62003c3d565b8160301162000317577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169162003cb562003b9c82808562003a18565b62003cc1828462003a37565b94909260b0116200031757803b15620003175762003d0a946801bc16d674ec8000005f94604051978895869485936304512a2360e31b855260908b0135928b6004870162003a92565b03925af1908115620005c1577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192620027a09262003d51575b506040519182918262003afd565b80620005d762003d619262000a06565b5f62003d43565b90813b1562003def575f805160206200430583398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511562003dd35762001c4d9162003fab565b50503462003ddd57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841162003e8a579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15620005c1575f516001600160a01b0381161562003e8057905f905f90565b505f906001905f90565b5050505f9160039190565b6014820362003f49576bffffffffffffffffffffffff19919035828116916014811062003f33575b5050905060601c62003edf62001317825f5261019f60205260405f2054151590565b62003f215760408051600160f81b60208201525f602182015260609290921b6bffffffffffffffffffffffff1916602c830152620019a3908290810162001e2f565b604051632899266560e21b8152600490fd5b8391925060140360031b1b1616805f8062003ebd565b604051639be7315960e01b8152600490fd5b60018060a01b03165f52609c60205260405f2090815481810390811162001cf65762003f88925562003066565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f80620019a393602081519101845af462003fc5620020ec565b919062003fdd5750805115620030fd57805190602001fd5b8151158062004012575b62003ff0575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562003fe756fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003344da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220fa998e0f720a3b6c86d4486b23f1ab9d407deb883f0b2b5826894f6e1ae1ee1d64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/contracts.ts b/test/shared/contracts.ts index bd877290..2642c56c 100644 --- a/test/shared/contracts.ts +++ b/test/shared/contracts.ts @@ -9,12 +9,6 @@ import EthPrivErc20Vault from './artifacts/EthPrivErc20Vault.json' import EthPrivVault from './artifacts/EthPrivVault.json' import EthBlocklistVault from './artifacts/EthBlocklistVault.json' import EthBlocklistErc20Vault from './artifacts/EthBlocklistErc20Vault.json' -import EthRestakeVault from './artifacts/EthRestakeVault.json' -import EthRestakePrivVault from './artifacts/EthRestakePrivVault.json' -import EthRestakeErc20Vault from './artifacts/EthRestakeErc20Vault.json' -import EthRestakePrivErc20Vault from './artifacts/EthRestakePrivErc20Vault.json' -import EthRestakeBlocklistVault from './artifacts/EthRestakeBlocklistVault.json' -import EthRestakeBlocklistErc20Vault from './artifacts/EthRestakeBlocklistErc20Vault.json' import GnoVault from './artifacts/GnoVault.json' import GnoPrivVault from './artifacts/GnoPrivVault.json' import GnoErc20Vault from './artifacts/GnoErc20Vault.json' @@ -71,39 +65,6 @@ export async function getEthGenesisVaultV3Factory(): Promise { return await ethers.getContractFactory(EthGenesisVault.abi, EthGenesisVault.bytecode) } -export async function getEthRestakeVaultV2Factory(): Promise { - return await ethers.getContractFactory(EthRestakeVault.abi, EthRestakeVault.bytecode) -} - -export async function getEthRestakePrivVaultV2Factory(): Promise { - return await ethers.getContractFactory(EthRestakePrivVault.abi, EthRestakePrivVault.bytecode) -} - -export async function getEthRestakeErc20VaultV2Factory(): Promise { - return await ethers.getContractFactory(EthRestakeErc20Vault.abi, EthRestakeErc20Vault.bytecode) -} - -export async function getEthRestakePrivErc20VaultV2Factory(): Promise { - return await ethers.getContractFactory( - EthRestakePrivErc20Vault.abi, - EthRestakePrivErc20Vault.bytecode - ) -} - -export async function getEthRestakeBlocklistVaultV2Factory(): Promise { - return await ethers.getContractFactory( - EthRestakeBlocklistVault.abi, - EthRestakeBlocklistVault.bytecode - ) -} - -export async function getEthRestakeBlocklistErc20VaultV2Factory(): Promise { - return await ethers.getContractFactory( - EthRestakeBlocklistErc20Vault.abi, - EthRestakeBlocklistErc20Vault.bytecode - ) -} - export async function getGnoVaultV2Factory(): Promise { return await ethers.getContractFactory(GnoVault.abi, GnoVault.bytecode) } diff --git a/test/shared/fixtures.ts b/test/shared/fixtures.ts index eeeabdd5..4213960a 100644 --- a/test/shared/fixtures.ts +++ b/test/shared/fixtures.ts @@ -8,8 +8,6 @@ import { import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util' import EthereumWallet from 'ethereumjs-wallet' import { - CumulativeMerkleDrop, - CumulativeMerkleDrop__factory, EthBlocklistErc20Vault, EthBlocklistErc20Vault__factory, EthBlocklistVault, @@ -81,12 +79,7 @@ import { SECURITY_DEPOSIT, VALIDATORS_MIN_ORACLES, } from './constants' -import { - EthErc20VaultInitParamsStruct, - EthRestakeVaultType, - EthVaultInitParamsStruct, - EthVaultType, -} from './types' +import { EthErc20VaultInitParamsStruct, EthVaultInitParamsStruct, EthVaultType } from './types' import { DepositorMock } from '../../typechain-types/contracts/mocks/DepositorMock' import { DepositorMock__factory } from '../../typechain-types/factories/contracts/mocks/DepositorMock__factory' import { UnknownVaultMock } from '../../typechain-types/contracts/mocks/UnknownVaultMock' @@ -98,13 +91,7 @@ import { MAINNET_FORK, NETWORKS } from '../../helpers/constants' import mainnetDeployment from '../../deployments/mainnet.json' export const transferOwnership = async function ( - contract: - | Keeper - | VaultsRegistry - | OsTokenVaultController - | OsToken - | OsTokenConfig - | CumulativeMerkleDrop, + contract: Keeper | VaultsRegistry | OsTokenVaultController | OsToken | OsTokenConfig, newOwner: Signer ) { const currentOwnerAddr = await contract.owner() @@ -154,9 +141,7 @@ export const updateVaultState = async function ( await vault.updateState(harvestParams) } -export const createDepositorMock = async function ( - vault: EthVaultType | EthRestakeVaultType -): Promise { +export const createDepositorMock = async function (vault: EthVaultType): Promise { const depositorMockFactory = await ethers.getContractFactory('DepositorMock') const contract = await depositorMockFactory.deploy(await vault.getAddress()) return DepositorMock__factory.connect( @@ -423,18 +408,6 @@ export const createOsTokenFlashLoans = async function ( return OsTokenFlashLoans__factory.connect(await contract.getAddress(), signer) } -export const createCumulativeMerkleDrop = async function ( - token: string, - owner: Wallet -): Promise { - const factory = await ethers.getContractFactory('CumulativeMerkleDrop') - const contract = await factory.deploy(owner.address, token) - return CumulativeMerkleDrop__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} - export const createKeeper = async function ( initialOracles: string[], configIpfsHash: string, diff --git a/test/shared/restakeFixtures.ts b/test/shared/restakeFixtures.ts deleted file mode 100644 index e5c0cee3..00000000 --- a/test/shared/restakeFixtures.ts +++ /dev/null @@ -1,423 +0,0 @@ -import hre, { ethers } from 'hardhat' -import { Contract, ContractFactory, Signer, Wallet } from 'ethers' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import EthereumWallet from 'ethereumjs-wallet' -import { - DepositDataRegistry, - EthRestakeBlocklistErc20Vault, - EthRestakeBlocklistErc20Vault__factory, - EthRestakeBlocklistVault, - EthRestakeBlocklistVault__factory, - EthRestakeErc20Vault, - EthRestakeErc20Vault__factory, - EthRestakePrivErc20Vault, - EthRestakePrivErc20Vault__factory, - EthRestakePrivVault, - EthRestakePrivVault__factory, - EthRestakeVault, - EthRestakeVault__factory, - Keeper, - SharedMevEscrow, - VaultsRegistry, - VaultsRegistry__factory, - SharedMevEscrow__factory, - Keeper__factory, - EthRestakeVaultFactory, - EthRestakeVaultFactory__factory, -} from '../../typechain-types' -import { - EXITING_ASSETS_MIN_DELAY, - ORACLES, - ORACLES_CONFIG, - REWARDS_MIN_ORACLES, - SECURITY_DEPOSIT, - VALIDATORS_MIN_ORACLES, -} from './constants' -import { EthRestakeErc20VaultInitParamsStruct, EthRestakeVaultInitParamsStruct } from './types' -import { extractVaultAddress } from './utils' -import { createDepositDataRegistry, createEthVaultFactory, transferOwnership } from './fixtures' -import { MAINNET_FORK, NETWORKS } from '../../helpers/constants' -import { getEthValidatorsRegistryFactory } from './contracts' -import mainnetDeployment from '../../deployments/mainnet.json' - -export const createEthRestakeVaultFactory = async function ( - dao: Signer, - implementation: string, - vaultsRegistry: VaultsRegistry -): Promise { - const factory = await ethers.getContractFactory('EthRestakeVaultFactory') - const contract = await factory.deploy( - await dao.getAddress(), - implementation, - await vaultsRegistry.getAddress() - ) - return EthRestakeVaultFactory__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} -export const deployEigenPodOwnerImplementation = async function ( - eigenPodManagerAddr: string, - eigenDelegationManagerAddr: string, - eigenDelayedWithdrawalRouterAddr: string -): Promise { - const factory = await ethers.getContractFactory('EigenPodOwner') - const constructorArgs = [ - eigenPodManagerAddr, - eigenDelegationManagerAddr, - eigenDelayedWithdrawalRouterAddr, - ] - const contract = await factory.deploy(...constructorArgs) - const eigenPodOwnerImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, eigenPodOwnerImpl) - return eigenPodOwnerImpl -} - -export async function deployEthRestakeVaultV2( - implFactory: ContractFactory, - admin: Signer, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: Contract, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - eigenPodOwnerImpl: string, - encodedParams: string, - isOwnMevEscrow = false -): Promise { - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - eigenPodOwnerImpl, - EXITING_ASSETS_MIN_DELAY, - ] - const vaultImpl = await implFactory.deploy(...constructorArgs) - const vaultImplAddr = await vaultImpl.getAddress() - await vaultsRegistry.addVaultImpl(vaultImplAddr) - - const vaultFactory = await createEthVaultFactory(vaultImplAddr, vaultsRegistry) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - - const tx = await vaultFactory.connect(admin).createVault(encodedParams, isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - return new Contract( - await extractVaultAddress(tx), - implFactory.interface, - await ethers.provider.getSigner() - ) -} - -export const deployEthRestakeVaultImplementation = async function ( - vaultType: string, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: string, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - eigenPodOwnerImpl: string, - exitingAssetsMinDelay: number -): Promise { - const factory = await ethers.getContractFactory(vaultType) - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - validatorsRegistry, - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - eigenPodOwnerImpl, - exitingAssetsMinDelay, - ] - const contract = await factory.deploy(...constructorArgs) - const vaultImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, vaultImpl) - return vaultImpl -} - -export const encodeEthRestakeVaultInitParams = function ( - vaultParams: EthRestakeVaultInitParamsStruct -): string { - return ethers.AbiCoder.defaultAbiCoder().encode( - ['tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [[vaultParams.capacity, vaultParams.feePercent, vaultParams.metadataIpfsHash]] - ) -} - -export const encodeEthRestakeErc20VaultInitParams = function ( - vaultParams: EthRestakeErc20VaultInitParamsStruct -): string { - return ethers.AbiCoder.defaultAbiCoder().encode( - [ - 'tuple(uint256 capacity, uint16 feePercent, string name, string symbol, string metadataIpfsHash)', - ], - [ - [ - vaultParams.capacity, - vaultParams.feePercent, - vaultParams.name, - vaultParams.symbol, - vaultParams.metadataIpfsHash, - ], - ] - ) -} - -interface EthRestakeVaultFixture { - vaultsRegistry: VaultsRegistry - keeper: Keeper - sharedMevEscrow: SharedMevEscrow - depositDataRegistry: DepositDataRegistry - validatorsRegistry: Contract - ethRestakeVaultFactory: EthRestakeVaultFactory - ethRestakePrivVaultFactory: EthRestakeVaultFactory - ethRestakeErc20VaultFactory: EthRestakeVaultFactory - ethRestakePrivErc20VaultFactory: EthRestakeVaultFactory - ethRestakeBlocklistVaultFactory: EthRestakeVaultFactory - ethRestakeBlocklistErc20VaultFactory: EthRestakeVaultFactory - eigenPodOwnerImplementation: string - - createEthRestakeVault( - admin: Signer, - vaultParams: EthRestakeVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthRestakePrivVault( - admin: Signer, - vaultParams: EthRestakeVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthRestakeBlocklistVault( - admin: Signer, - vaultParams: EthRestakeVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthRestakeErc20Vault( - admin: Signer, - vaultParams: EthRestakeErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthRestakePrivErc20Vault( - admin: Signer, - vaultParams: EthRestakeErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthRestakeBlocklistErc20Vault( - admin: Signer, - vaultParams: EthRestakeErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise -} - -export const ethRestakeVaultFixture = async function (): Promise { - const dao = await (ethers as any).provider.getSigner() - - const validatorsRegistryFactory = await getEthValidatorsRegistryFactory() - const validatorsRegistry = new Contract( - NETWORKS.mainnet.validatorsRegistry, - validatorsRegistryFactory.interface, - dao - ) - const vaultsRegistry = VaultsRegistry__factory.connect(mainnetDeployment.VaultsRegistry, dao) - const depositDataRegistry = await createDepositDataRegistry(vaultsRegistry) - const sharedMevEscrow = SharedMevEscrow__factory.connect(mainnetDeployment.SharedMevEscrow, dao) - const keeper = Keeper__factory.connect(mainnetDeployment.Keeper, dao) - - // change ownership - await transferOwnership(vaultsRegistry, dao) - await transferOwnership(keeper, dao) - - // drop mainnet oracles - for (const oracleAddr of MAINNET_FORK.oracles) { - if (await keeper.isOracle(oracleAddr)) { - await keeper.removeOracle(oracleAddr) - } - } - - // add test oracles - const sortedOracles = ORACLES.sort((oracle1, oracle2) => { - const oracle1Addr = new EthereumWallet(oracle1).getAddressString() - const oracle2Addr = new EthereumWallet(oracle2).getAddressString() - return oracle1Addr > oracle2Addr ? 1 : -1 - }) - const sortedOraclesAddresses = sortedOracles.map((s) => new EthereumWallet(s).getAddressString()) - for (let i = 0; i < sortedOraclesAddresses.length; i++) { - if (!(await keeper.isOracle(sortedOraclesAddresses[i]))) { - await keeper.addOracle(sortedOraclesAddresses[i]) - } - } - - await keeper.updateConfig(ORACLES_CONFIG) - await keeper.setRewardsMinOracles(REWARDS_MIN_ORACLES) - await keeper.setValidatorsMinOracles(VALIDATORS_MIN_ORACLES) - - const eigenPodOwnerImplementation = await deployEigenPodOwnerImplementation( - MAINNET_FORK.eigenPodManager, - MAINNET_FORK.eigenDelegationManager, - MAINNET_FORK.eigenDelayedWithdrawalRouter - ) - - // deploy implementations and factories - const factories = {} - const implementations = {} - - for (const vaultType of [ - 'EthRestakeVault', - 'EthRestakePrivVault', - 'EthRestakeErc20Vault', - 'EthRestakePrivErc20Vault', - 'EthRestakeBlocklistVault', - 'EthRestakeBlocklistErc20Vault', - ]) { - const vaultImpl = await deployEthRestakeVaultImplementation( - vaultType, - keeper, - vaultsRegistry, - await validatorsRegistry.getAddress(), - sharedMevEscrow, - depositDataRegistry, - eigenPodOwnerImplementation, - EXITING_ASSETS_MIN_DELAY - ) - await vaultsRegistry.addVaultImpl(vaultImpl) - implementations[vaultType] = vaultImpl - - const vaultFactory = await createEthRestakeVaultFactory(dao, vaultImpl, vaultsRegistry) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - factories[vaultType] = vaultFactory - } - - const ethRestakeVaultFactory = factories['EthRestakeVault'] - const ethRestakePrivVaultFactory = factories['EthRestakePrivVault'] - const ethRestakeErc20VaultFactory = factories['EthRestakeErc20Vault'] - const ethRestakePrivErc20VaultFactory = factories['EthRestakePrivErc20Vault'] - const ethRestakeBlocklistVaultFactory = factories['EthRestakeBlocklistVault'] - const ethRestakeBlocklistErc20VaultFactory = factories['EthRestakeBlocklistErc20Vault'] - - return { - vaultsRegistry, - sharedMevEscrow, - depositDataRegistry, - keeper, - validatorsRegistry, - ethRestakeVaultFactory, - ethRestakePrivVaultFactory, - ethRestakeErc20VaultFactory, - ethRestakePrivErc20VaultFactory, - ethRestakeBlocklistVaultFactory, - ethRestakeBlocklistErc20VaultFactory, - eigenPodOwnerImplementation, - createEthRestakeVault: async ( - admin: Signer, - vaultParams: EthRestakeVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethRestakeVaultFactory.createVault( - await admin.getAddress(), - encodeEthRestakeVaultInitParams(vaultParams), - isOwnMevEscrow, - { - value: SECURITY_DEPOSIT, - } - ) - const vaultAddress = await extractVaultAddress(tx) - return EthRestakeVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createEthRestakePrivVault: async ( - admin: Signer, - vaultParams: EthRestakeVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethRestakePrivVaultFactory.createVault( - await admin.getAddress(), - encodeEthRestakeVaultInitParams(vaultParams), - isOwnMevEscrow, - { - value: SECURITY_DEPOSIT, - } - ) - const vaultAddress = await extractVaultAddress(tx) - return EthRestakePrivVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createEthRestakeBlocklistVault: async ( - admin: Signer, - vaultParams: EthRestakeVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethRestakeBlocklistVaultFactory.createVault( - await admin.getAddress(), - encodeEthRestakeVaultInitParams(vaultParams), - isOwnMevEscrow, - { - value: SECURITY_DEPOSIT, - } - ) - const vaultAddress = await extractVaultAddress(tx) - return EthRestakeBlocklistVault__factory.connect( - vaultAddress, - await ethers.provider.getSigner() - ) - }, - createEthRestakeErc20Vault: async ( - admin: Signer, - vaultParams: EthRestakeErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethRestakeErc20VaultFactory.createVault( - await admin.getAddress(), - encodeEthRestakeErc20VaultInitParams(vaultParams), - isOwnMevEscrow, - { - value: SECURITY_DEPOSIT, - } - ) - const vaultAddress = await extractVaultAddress(tx) - return EthRestakeErc20Vault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createEthRestakePrivErc20Vault: async ( - admin: Signer, - vaultParams: EthRestakeErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethRestakePrivErc20VaultFactory.createVault( - await admin.getAddress(), - encodeEthRestakeErc20VaultInitParams(vaultParams), - isOwnMevEscrow, - { - value: SECURITY_DEPOSIT, - } - ) - const vaultAddress = await extractVaultAddress(tx) - return EthRestakePrivErc20Vault__factory.connect( - vaultAddress, - await ethers.provider.getSigner() - ) - }, - createEthRestakeBlocklistErc20Vault: async ( - admin: Wallet, - vaultParams: EthRestakeErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethRestakeBlocklistErc20VaultFactory.createVault( - await admin.getAddress(), - encodeEthRestakeErc20VaultInitParams(vaultParams), - isOwnMevEscrow, - { - value: SECURITY_DEPOSIT, - } - ) - const vaultAddress = await extractVaultAddress(tx) - return EthRestakeBlocklistErc20Vault__factory.connect( - vaultAddress, - await ethers.provider.getSigner() - ) - }, - } -} diff --git a/test/shared/rewards.ts b/test/shared/rewards.ts index e3b62b64..403cedac 100644 --- a/test/shared/rewards.ts +++ b/test/shared/rewards.ts @@ -28,7 +28,7 @@ import { } from './utils' import { getOraclesSignatures } from './fixtures' import { MAINNET_FORK } from '../../helpers/constants' -import { EthRestakeVaultType, EthVaultType } from './types' +import { EthVaultType } from './types' export type RewardsTree = StandardMerkleTree<[string, bigint, bigint]> @@ -140,7 +140,7 @@ export function getRewardsRootProof(tree: RewardsTree, vaultReward: VaultReward) } export async function collateralizeEthVault( - vault: EthVaultType | EthRestakeVaultType, + vault: EthVaultType, keeper: Keeper, depositDataRegistry: DepositDataRegistry, admin: Signer, diff --git a/test/shared/types.ts b/test/shared/types.ts index 54712869..0fc97075 100644 --- a/test/shared/types.ts +++ b/test/shared/types.ts @@ -12,12 +12,6 @@ import { GnoErc20Vault, GnoPrivErc20Vault, GnoGenesisVault, - EthRestakeVault, - EthRestakePrivVault, - EthRestakeErc20Vault, - EthRestakePrivErc20Vault, - EthRestakeBlocklistErc20Vault, - EthRestakeBlocklistVault, } from '../../typechain-types' export type EthVaultInitParamsStruct = { @@ -32,12 +26,6 @@ export type GnoVaultInitParamsStruct = { metadataIpfsHash: string } -export type EthRestakeVaultInitParamsStruct = { - capacity: bigint - feePercent: number - metadataIpfsHash: string -} - export type EthErc20VaultInitParamsStruct = { capacity: bigint feePercent: number @@ -54,14 +42,6 @@ export type GnoErc20VaultInitParamsStruct = { metadataIpfsHash: string } -export type EthRestakeErc20VaultInitParamsStruct = { - capacity: bigint - feePercent: number - name: string - symbol: string - metadataIpfsHash: string -} - export type EthVaultType = | EthVault | EthPrivVault @@ -78,11 +58,3 @@ export type GnoVaultType = | GnoErc20Vault | GnoPrivErc20Vault | GnoGenesisVault - -export type EthRestakeVaultType = - | EthRestakeVault - | EthRestakePrivVault - | EthRestakeBlocklistVault - | EthRestakeErc20Vault - | EthRestakePrivErc20Vault - | EthRestakeBlocklistErc20Vault diff --git a/test/shared/validators.ts b/test/shared/validators.ts index 9bd07588..aca27b59 100644 --- a/test/shared/validators.ts +++ b/test/shared/validators.ts @@ -15,7 +15,7 @@ import { ZERO_BYTES32, } from './constants' import { getOraclesSignatures } from './fixtures' -import { EthRestakeVaultType, EthVaultType, GnoVaultType } from './types' +import { EthVaultType, GnoVaultType } from './types' export const secretKeys = [ '0x2c66340f2d886f3fc4cfef10a802ddbaf4a37ffb49533b604f8a50804e8d198f', @@ -190,31 +190,20 @@ export function appendDepositData( } export async function createEthValidatorsData( - vault: EthVaultType | GnoVaultType | EthRestakeVaultType, + vault: EthVaultType | GnoVaultType, genesisVaultPoolEscrow: string | null = null ): Promise { const validatorDeposit = ethers.parseEther('32') let withdrawalAddress: string - let isRestakeVault = false if (genesisVaultPoolEscrow !== null) { withdrawalAddress = genesisVaultPoolEscrow - } else if ((vault).restakeOperatorsManager) { - isRestakeVault = true - const eigenPods = await (vault).getEigenPods() - if (eigenPods.length === 0) { - throw new Error('No eigen pods found') - } - withdrawalAddress = eigenPods[0] } else { withdrawalAddress = await vault.getAddress() } const withdrawalCredentials = getWithdrawalCredentials(withdrawalAddress) - let validators = await createValidators(validatorDeposit, withdrawalCredentials) - if (isRestakeVault) { - validators = validators.map((v) => Buffer.concat([v, ethers.getBytes(withdrawalAddress)])) - } + const validators = await createValidators(validatorDeposit, withdrawalCredentials) const tree = StandardMerkleTree.of( validators.map((v, i) => [v, i]), ['bytes', 'uint256'] @@ -233,7 +222,7 @@ export async function getEthValidatorsSigningData( deadline: bigint, exitSignaturesIpfsHash: string, keeper: Keeper, - vault: EthVaultType | GnoVaultType | EthRestakeVaultType, + vault: EthVaultType | GnoVaultType, validatorsRegistryRoot: BytesLike ) { return { @@ -257,7 +246,7 @@ export async function getEthValidatorsSigningData( export async function getValidatorsManagerSigningData( validators: Buffer, - vault: EthVaultType | GnoVaultType | EthRestakeVaultType, + vault: EthVaultType | GnoVaultType, validatorsRegistryRoot: BytesLike ) { return { @@ -322,7 +311,7 @@ export function getValidatorsMultiProof( } export async function registerEthValidator( - vault: EthVaultType | GnoVaultType | EthRestakeVaultType, + vault: EthVaultType | GnoVaultType, keeper: Keeper, depositDataRegistry: DepositDataRegistry, admin: Signer, From 26b11ca3d33e0efdc1de6ddb0b1af831cf7585c4 Mon Sep 17 00:00:00 2001 From: evgeny-stakewise <123374581+evgeny-stakewise@users.noreply.github.com> Date: Mon, 17 Mar 2025 14:07:30 +0300 Subject: [PATCH 02/15] Add claim on behalf in RewardSplitter (#101) * Add claim on behalf in RewardSplitter * Review fixes * Split to Eth and Gno versions * Add simple test * Review fixes 2 * Make enterExitQueueOnBehalf external in interface * fixup * Add tests 2 * Fix missing syncRewards calls * Add tests 4 * Add tests 5 * Fix ReentrancyGuard * Modify enterExitQueueOnBehalf returns positionTicket * Add tests for new features * Add tests for gnosis * Review fixes 3 * Optimize syncRewards * Del GnoRewardSplitterEnterExitQueueOnBehalfTest * Add test for claim for multiple users * Cleanup * Review fixes * Del test/RewardSplitter.spec.ts --------- Co-authored-by: Dmitri Tsumak --- contracts/interfaces/IRewardSplitter.sol | 79 ++- contracts/misc/EthRewardSplitter.sol | 35 ++ contracts/misc/GnoRewardSplitter.sol | 36 ++ contracts/misc/RewardSplitter.sol | 117 +++- contracts/misc/RewardSplitterFactory.sol | 2 +- test/Constants.t.sol | 27 + test/EthRewardSplitter.t.sol | 696 +++++++++++++++++++++++ test/Fork.t.sol | 22 + test/GnoRewardSplitter.t.sol | 156 +++++ test/GnosisFork.t.sol | 34 ++ test/MainnetFork.t.sol | 32 ++ test/RewardSplitter.spec.ts | 481 ---------------- test/Rewards.t.sol | 130 +++++ test/VaultExitQueueClaim.t.sol | 134 +---- 14 files changed, 1354 insertions(+), 627 deletions(-) create mode 100644 contracts/misc/EthRewardSplitter.sol create mode 100644 contracts/misc/GnoRewardSplitter.sol create mode 100644 test/Constants.t.sol create mode 100644 test/EthRewardSplitter.t.sol create mode 100644 test/Fork.t.sol create mode 100644 test/GnoRewardSplitter.t.sol create mode 100644 test/GnosisFork.t.sol create mode 100644 test/MainnetFork.t.sol delete mode 100644 test/RewardSplitter.spec.ts create mode 100644 test/Rewards.t.sol diff --git a/contracts/interfaces/IRewardSplitter.sol b/contracts/interfaces/IRewardSplitter.sol index 81efa816..e5c646b8 100644 --- a/contracts/interfaces/IRewardSplitter.sol +++ b/contracts/interfaces/IRewardSplitter.sol @@ -26,6 +26,13 @@ interface IRewardSplitter is IMulticall { uint128 rewardPerShare; } + /** + * @notice Event emitted when the claim on behalf flag is updated + * @param caller The address of the account that called the function + * @param enabled The flag indicating whether the claim on behalf is enabled + */ + event ClaimOnBehalfUpdated(address caller, bool enabled); + /** * @notice Event emitted when the number of shares is increased for an account * @param account The address of the account for which the shares were increased @@ -54,30 +61,69 @@ interface IRewardSplitter is IMulticall { */ event RewardsWithdrawn(address indexed account, uint256 amount); + /** + * @notice Event emitted when the rewards are claimed on behalf + * @param onBehalf The address of the account on behalf of which the rewards were claimed + * @param positionTicket The position ticket in the exit queue + * @param amount The amount of rewards that were claimed + */ + event ExitQueueEnteredOnBehalf(address indexed onBehalf, uint256 positionTicket, uint256 amount); + + /** + * @notice Event emitted when the exited assets are claimed on behalf + * @param onBehalf The address of the account on behalf of which the assets were claimed + * @param positionTicket The position ticket in the exit queue + * @param amount The amount of assets that were claimed + */ + event ExitedAssetsClaimedOnBehalf( + address indexed onBehalf, + uint256 positionTicket, + uint256 amount + ); + /** * @notice The vault to which the RewardSplitter is connected * @return The address of the vault */ - function vault() external returns (address); + function vault() external view returns (address); /** * @notice The total number of shares in the splitter * @return The total number of shares */ - function totalShares() external returns (uint256); + function totalShares() external view returns (uint256); + + /** + * @notice Returns the address of shareholder on behalf of which the rewards are claimed + * @param exitPosition The position in the exit queue + * @return onBehalf The address of shareholder + */ + function exitPositions(uint256 exitPosition) external view returns (address onBehalf); + + /** + * @notice Returns whether the claim on behalf is enabled + * @return `true` if the claim on behalf is enabled, `false` otherwise + */ + function isClaimOnBehalfEnabled() external view returns (bool); /** * @notice The total amount of unclaimed rewards in the splitter * @return The total amount of rewards */ - function totalRewards() external returns (uint128); + function totalRewards() external view returns (uint128); /** * @notice Initializes the RewardSplitter contract - * @param owner The address of the owner of the RewardSplitter contract * @param _vault The address of the vault to which the RewardSplitter will be connected */ - function initialize(address owner, address _vault) external; + function initialize(address _vault) external; + + /** + * @notice Sets the flag indicating whether the claim on behalf is enabled. + * @param enabled The flag indicating whether the claim on behalf is enabled + * Can only be called by the vault admin. + */ + function setClaimOnBehalf(bool enabled) external; /** * @notice Retrieves the amount of splitter shares for the given account. @@ -138,6 +184,29 @@ interface IRewardSplitter is IMulticall { address receiver ) external returns (uint256 positionTicket); + /** + * @notice Enters the exit queue on behalf of the shareholder. Can only be called if claim on behalf is enabled. + * @param rewards The amount of rewards to send to the exit queue + * @param onBehalf The address of the account on behalf of which the rewards are sent to the exit queue + * @return positionTicket The position ticket of the exit queue + */ + function enterExitQueueOnBehalf( + uint256 rewards, + address onBehalf + ) external returns (uint256 positionTicket); + + /** + * @notice Claims the exited assets from the vault. + * @param positionTicket The position ticket in the exit queue + * @param timestamp The timestamp when the shares entered the exit queue + * @param exitQueueIndex The exit queue index of the exit request + */ + function claimExitedAssetsOnBehalf( + uint256 positionTicket, + uint256 timestamp, + uint256 exitQueueIndex + ) external; + /** * @notice Syncs the rewards from the vault to the splitter. The vault state must be up-to-date. */ diff --git a/contracts/misc/EthRewardSplitter.sol b/contracts/misc/EthRewardSplitter.sol new file mode 100644 index 00000000..affd3502 --- /dev/null +++ b/contracts/misc/EthRewardSplitter.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; +import {RewardSplitter} from './RewardSplitter.sol'; +import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; + +/** + * @title EthRewardSplitter + * @author StakeWise + * @notice The EthRewardSplitter can be used on Ethereum networks + to split the rewards of the fee recipient of the vault based on configured shares + */ +contract EthRewardSplitter is ReentrancyGuardUpgradeable, RewardSplitter { + /** + * @dev Constructor for EthRewardSplitter + */ + constructor() RewardSplitter() {} + + /// Allows to claim rewards from the vault and receive them to the reward splitter address + receive() external payable {} + + /// @inheritdoc IRewardSplitter + function initialize(address _vault) external override initializer { + __ReentrancyGuard_init(); + __RewardSplitter_init(_vault); + } + + /// @inheritdoc RewardSplitter + function _transferRewards(address shareholder, uint256 amount) internal override nonReentrant { + Address.sendValue(payable(shareholder), amount); + } +} diff --git a/contracts/misc/GnoRewardSplitter.sol b/contracts/misc/GnoRewardSplitter.sol new file mode 100644 index 00000000..857b7753 --- /dev/null +++ b/contracts/misc/GnoRewardSplitter.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {RewardSplitter} from './RewardSplitter.sol'; +import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; + +/** + * @title GnoRewardSplitter + * @author StakeWise + * @notice The GnoRewardSplitter can be used on Gnosis networks + to split the rewards of the fee recipient of the vault based on configures shares + */ +contract GnoRewardSplitter is RewardSplitter { + IERC20 private immutable _gnoToken; + + /** + * @dev Constructor for GnoRewardSplitter + * @param gnoToken The address of the GNO token + */ + constructor(address gnoToken) RewardSplitter() { + _gnoToken = IERC20(gnoToken); + } + + /// @inheritdoc IRewardSplitter + function initialize(address _vault) external override initializer { + __RewardSplitter_init(_vault); + } + + /// @inheritdoc RewardSplitter + function _transferRewards(address shareholder, uint256 amount) internal override { + SafeERC20.safeTransfer(_gnoToken, shareholder, amount); + } +} diff --git a/contracts/misc/RewardSplitter.sol b/contracts/misc/RewardSplitter.sol index c99380f0..973152c6 100644 --- a/contracts/misc/RewardSplitter.sol +++ b/contracts/misc/RewardSplitter.sol @@ -7,19 +7,20 @@ import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {OwnableUpgradeable} from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; import {IVaultState} from '../interfaces/IVaultState.sol'; import {IVaultEnterExit} from '../interfaces/IVaultEnterExit.sol'; +import {IVaultAdmin} from '../interfaces/IVaultAdmin.sol'; import {Multicall} from '../base/Multicall.sol'; +import {Errors} from '../libraries/Errors.sol'; /** * @title RewardSplitter * @author StakeWise - * @notice The RewardSplitter can be used to split the rewards of the fee recipient of the vault based on configures shares + * @notice The RewardSplitter can be used to split the rewards of the fee recipient of the vault based on configured shares */ -contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, Multicall { +abstract contract RewardSplitter is IRewardSplitter, Initializable, Multicall { uint256 private constant _wad = 1e18; /// @inheritdoc IRewardSplitter @@ -28,21 +29,34 @@ contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, M /// @inheritdoc IRewardSplitter uint256 public override totalShares; + /// @inheritdoc IRewardSplitter + bool public override isClaimOnBehalfEnabled; + mapping(address => ShareHolder) private _shareHolders; mapping(address => uint256) private _unclaimedRewards; + mapping(uint256 positionTicket => address onBehalf) public override exitPositions; uint128 private _totalRewards; uint128 private _rewardPerShare; - /// @custom:oz-upgrades-unsafe-allow constructor + /** + * @dev Modifier to check if the caller is the vault admin + */ + modifier onlyVaultAdmin() { + if (msg.sender != IVaultAdmin(vault).admin()) { + revert Errors.AccessDenied(); + } + _; + } + constructor() { _disableInitializers(); } /// @inheritdoc IRewardSplitter - function initialize(address owner, address _vault) external override initializer { - __Ownable_init(owner); - vault = _vault; + function setClaimOnBehalf(bool enabled) external onlyVaultAdmin { + isClaimOnBehalfEnabled = enabled; + emit ClaimOnBehalfUpdated(msg.sender, enabled); } /// @inheritdoc IRewardSplitter @@ -74,7 +88,7 @@ contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, M } /// @inheritdoc IRewardSplitter - function increaseShares(address account, uint128 amount) external override onlyOwner { + function increaseShares(address account, uint128 amount) external override onlyVaultAdmin { if (account == address(0)) revert InvalidAccount(); if (amount == 0) revert InvalidAmount(); @@ -96,7 +110,7 @@ contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, M } /// @inheritdoc IRewardSplitter - function decreaseShares(address account, uint128 amount) external override onlyOwner { + function decreaseShares(address account, uint128 amount) external override onlyVaultAdmin { if (account == address(0)) revert InvalidAccount(); if (amount == 0) revert InvalidAmount(); @@ -124,7 +138,7 @@ contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, M /// @inheritdoc IRewardSplitter function claimVaultTokens(uint256 rewards, address receiver) external override { - _withdrawRewards(msg.sender, rewards); + rewards = _withdrawRewards(msg.sender, rewards); // NB! will revert if vault is not ERC-20 SafeERC20.safeTransfer(IERC20(vault), receiver, rewards); } @@ -134,10 +148,60 @@ contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, M uint256 rewards, address receiver ) external override returns (uint256 positionTicket) { - _withdrawRewards(msg.sender, rewards); + rewards = _withdrawRewards(msg.sender, rewards); return IVaultEnterExit(vault).enterExitQueue(rewards, receiver); } + /// @inheritdoc IRewardSplitter + function enterExitQueueOnBehalf( + uint256 rewards, + address onBehalf + ) external override returns (uint256 positionTicket) { + if (!isClaimOnBehalfEnabled) revert Errors.AccessDenied(); + + rewards = _withdrawRewards(onBehalf, rewards); + + // Use the reward splitter address as receiver. This allows the reward splitter to claim the assets. + positionTicket = IVaultEnterExit(vault).enterExitQueue(rewards, address(this)); + exitPositions[positionTicket] = onBehalf; + + emit ExitQueueEnteredOnBehalf(onBehalf, positionTicket, rewards); + } + + /// @inheritdoc IRewardSplitter + function claimExitedAssetsOnBehalf( + uint256 positionTicket, + uint256 timestamp, + uint256 exitQueueIndex + ) external override { + address onBehalf = exitPositions[positionTicket]; + if (onBehalf == address(0)) revert Errors.InvalidPosition(); + + // calculate exited tickets and assets + (uint256 leftTickets, , uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( + address(this), + positionTicket, + timestamp, + exitQueueIndex + ); + // disallow partial claims (1 ticket could be a rounding error) + if (leftTickets > 1) revert Errors.ExitRequestNotProcessed(); + + IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + delete exitPositions[positionTicket]; + + _transferRewards(onBehalf, exitedAssets); + + emit ExitedAssetsClaimedOnBehalf(onBehalf, positionTicket, exitedAssets); + } + + /** + * @dev Transfers the specified amount of rewards to the shareholder + * @param shareholder The address of the shareholder + * @param amount The amount of rewards to transfer + */ + function _transferRewards(address shareholder, uint256 amount) internal virtual; + /// @inheritdoc IRewardSplitter function syncRewards() public override { // SLOAD to memory @@ -169,17 +233,44 @@ contract RewardSplitter is IRewardSplitter, Initializable, OwnableUpgradeable, M emit RewardsSynced(newTotalRewards, newRewardPerShare); } - function _withdrawRewards(address account, uint256 rewards) private { + /** + * @dev Withdraws rewards for the given account + * @param account The address of the account to withdraw rewards for + * @param rewards The amount of rewards to withdraw + * @return The actual amount of rewards withdrawn + */ + function _withdrawRewards(address account, uint256 rewards) private returns (uint256) { + // Sync rewards from the vault + syncRewards(); + // get user total number of rewards uint256 accountRewards = rewardsOf(account); - // update state + // Set actual amount of rewards if user requested to withdraw all available rewards + if (rewards == type(uint256).max) { + rewards = accountRewards; + } + + // withdraw shareholder rewards from the splitter _totalRewards -= SafeCast.toUint128(rewards); + + // update shareholder // reverts if withdrawn rewards exceed total _unclaimedRewards[account] = accountRewards - rewards; _shareHolders[account].rewardPerShare = _rewardPerShare; // emit event emit RewardsWithdrawn(account, rewards); + + // return actual amount of rewards withdrawn + return rewards; + } + + /** + * @dev Initializes the RewardSplitter contract + * @param _vault The address of the vault to which the RewardSplitter will be connected + */ + function __RewardSplitter_init(address _vault) internal onlyInitializing { + vault = _vault; } } diff --git a/contracts/misc/RewardSplitterFactory.sol b/contracts/misc/RewardSplitterFactory.sol index da30616c..ba0d3f31 100644 --- a/contracts/misc/RewardSplitterFactory.sol +++ b/contracts/misc/RewardSplitterFactory.sol @@ -27,7 +27,7 @@ contract RewardSplitterFactory is IRewardSplitterFactory { function createRewardSplitter(address vault) external override returns (address rewardSplitter) { // deploy and initialize reward splitter rewardSplitter = Clones.clone(implementation); - IRewardSplitter(rewardSplitter).initialize(msg.sender, vault); + IRewardSplitter(rewardSplitter).initialize(vault); // emit event emit RewardSplitterCreated(msg.sender, vault, rewardSplitter); diff --git a/test/Constants.t.sol b/test/Constants.t.sol new file mode 100644 index 00000000..ee375056 --- /dev/null +++ b/test/Constants.t.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.8.22; + +import {Test} from '../lib/forge-std/src/Test.sol'; + +abstract contract ConstantsTest is Test { + address ZERO_ADDRESS; + uint256 REWARDS_DELAY = 12 hours; + uint256 SECURITY_DEPOSIT = 1 gwei; + + enum PanicCode { + ARITHMETIC_UNDER_OR_OVERFLOW, + DIVISION_BY_ZERO, + OUT_OF_BOUND_INDEX + } + + mapping(PanicCode => uint8) public panicCodes; + + function setUp() public virtual { + panicCodes[PanicCode.ARITHMETIC_UNDER_OR_OVERFLOW] = 0x11; + panicCodes[PanicCode.DIVISION_BY_ZERO] = 0x12; + panicCodes[PanicCode.OUT_OF_BOUND_INDEX] = 0x32; + } + + function expectRevertWithPanic(PanicCode code) public { + vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", panicCodes[code])); + } +} diff --git a/test/EthRewardSplitter.t.sol b/test/EthRewardSplitter.t.sol new file mode 100644 index 00000000..12fa614e --- /dev/null +++ b/test/EthRewardSplitter.t.sol @@ -0,0 +1,696 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; +import {IEthVaultFactory} from '../contracts/interfaces/IEthVaultFactory.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IVaultAdmin} from '../contracts/interfaces/IVaultAdmin.sol'; +import {IVaultFee} from '../contracts/interfaces/IVaultFee.sol'; +import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {RewardSplitterFactory} from '../contracts/misc/RewardSplitterFactory.sol'; +import {IRewardSplitterFactory} from '../contracts/interfaces/IRewardSplitterFactory.sol'; +import {EthRewardSplitter} from '../contracts/misc/EthRewardSplitter.sol'; +import {RewardSplitter} from '../contracts/misc/RewardSplitter.sol'; +import {IRewardSplitter} from '../contracts/interfaces/IRewardSplitter.sol'; +import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; +import {IVaultEthStaking} from '../contracts/interfaces/IVaultEthStaking.sol'; +import {Vm} from '../lib/forge-std/src/Vm.sol'; +import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; +import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; +import {Test} from '../lib/forge-std/src/Test.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {RewardsTest} from './Rewards.t.sol'; +import {ConstantsTest} from './Constants.t.sol'; +import {MainnetForkTest} from './MainnetFork.t.sol'; + +abstract contract EthRewardSplitterTest is Test, ConstantsTest, RewardsTest, MainnetForkTest { + address public constant user1 = address(0x1); + address public constant user2 = address(0x2); + + address public vault; + address public vaultAdmin; + address public rewardSplitter; + address public rewardSplitterFactory; + uint256 avgRewardPerSecond = 1585489600; + + function setUp() public virtual override(ConstantsTest, MainnetForkTest, RewardsTest) { + MainnetForkTest.setUp(); + ConstantsTest.setUp(); + RewardsTest.setUp(); + + vm.prank(VaultsRegistry(vaultsRegistry).owner()); + VaultsRegistry(vaultsRegistry).addFactory(v2VaultFactory); + + // create V2 vault + IEthVault.EthVaultInitParams memory params = IEthVault.EthVaultInitParams({ + capacity: type(uint256).max, + feePercent: 1000, + metadataIpfsHash: '' + }); + vault = IEthVaultFactory(v2VaultFactory).createVault{value: 1 gwei}(abi.encode(params), false); + + // collateralize vault (imitate validator creation) + _collateralizeVault(vault); + + // set vault admin + vaultAdmin = IVaultAdmin(vault).admin(); + + // create reward splitter and connect to vault + vm.startPrank(vaultAdmin); + address rewardSplitterImpl = address(new EthRewardSplitter()); + rewardSplitterFactory = address(new RewardSplitterFactory(rewardSplitterImpl)); + rewardSplitter = IRewardSplitterFactory(rewardSplitterFactory).createRewardSplitter(vault); + IVaultFee(vault).setFeeRecipient(rewardSplitter); + vm.stopPrank(); + } +} + +contract EthRewardSplitterSetClaimOnBehalfTest is EthRewardSplitterTest { + function test_failsByNotVaultAdmin() public { + vm.prank(user1); + vm.expectRevert(Errors.AccessDenied.selector); + IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + } + + function test_normal() public { + // enable claim on behalf + vm.prank(vaultAdmin); + vm.expectEmit(rewardSplitter); + emit IRewardSplitter.ClaimOnBehalfUpdated(vaultAdmin, true); + + IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + + assertTrue(IRewardSplitter(rewardSplitter).isClaimOnBehalfEnabled()); + + // disable claim on behalf + vm.prank(vaultAdmin); + vm.expectEmit(rewardSplitter); + emit IRewardSplitter.ClaimOnBehalfUpdated(vaultAdmin, false); + + IRewardSplitter(rewardSplitter).setClaimOnBehalf(false); + + assertFalse(IRewardSplitter(rewardSplitter).isClaimOnBehalfEnabled()); + } +} + +contract EthRewardSplitterIncreaseSharesTest is EthRewardSplitterTest { + function test_failsWithZeroShares() public { + vm.prank(vaultAdmin); + vm.expectRevert(IRewardSplitter.InvalidAmount.selector); + IRewardSplitter(rewardSplitter).increaseShares(user1, 0); + } + + function test_failsWithZeroAccount() public { + vm.prank(vaultAdmin); + vm.expectRevert(IRewardSplitter.InvalidAccount.selector); + IRewardSplitter(rewardSplitter).increaseShares(ZERO_ADDRESS, 1); + } + + function test_failsByNotVaultAdmin() public { + vm.prank(user1); + vm.expectRevert(Errors.AccessDenied.selector); + IRewardSplitter(rewardSplitter).increaseShares(user1, 1); + } + + function test_failsWhenVaultNotHarvested() public { + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, 1); + + uint256 unlockedMevReward = 0; + skip(REWARDS_DELAY + 1); + _setVaultRewards(vault, 1 ether, unlockedMevReward, avgRewardPerSecond); + + skip(REWARDS_DELAY + 1); + _setVaultRewards(vault, 2 ether, unlockedMevReward, avgRewardPerSecond); + + vm.prank(vaultAdmin); + vm.expectRevert(IRewardSplitter.NotHarvested.selector); + IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, 1); + } + + function test_doesNotAffectOthersRewards() public { + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, 100); + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); + uint256 totalReward = 1 ether; + uint256 fee = 0.1 ether; + uint256 unlockedMevReward = 0; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); + IVaultState(vault).updateState(harvestParams); + uint256 feeShares = IVaultState(vault).convertToShares(fee); + + assertEq(IVaultFee(vault).feeRecipient(), rewardSplitter); + assertEq(IVaultState(vault).getShares(rewardSplitter), feeShares); + + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, 100); + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), feeShares); + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(vaultAdmin), 0); + } + + function test_vaultAdminCanIncreaseShares() public { + uint128 shares = 100; + + vm.prank(vaultAdmin); + vm.expectEmit(rewardSplitter); + emit IRewardSplitter.SharesIncreased(user1, shares); + + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + assertEq(IRewardSplitter(rewardSplitter).sharesOf(user1), shares); + assertEq(IRewardSplitter(rewardSplitter).totalShares(), shares); + } +} + +contract EthRewardSplitterDecreaseSharesTest is EthRewardSplitterTest { + uint128 public constant shares = 100; + + function setUp() public override { + super.setUp(); + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + } + + function test_failsWithZeroShares() public { + vm.prank(vaultAdmin); + vm.expectRevert(IRewardSplitter.InvalidAmount.selector); + IRewardSplitter(rewardSplitter).decreaseShares(user1, 0); + } + + function test_failsWithZeroAccount() public { + vm.prank(vaultAdmin); + vm.expectRevert(IRewardSplitter.InvalidAccount.selector); + IRewardSplitter(rewardSplitter).decreaseShares(ZERO_ADDRESS, 1); + } + + function test_failsByNotVaultAdmin() public { + vm.prank(user1); + vm.expectRevert(Errors.AccessDenied.selector); + IRewardSplitter(rewardSplitter).decreaseShares(user1, 1); + } + + function test_failsWithAmountLargerThanBalance() public { + vm.prank(vaultAdmin); + expectRevertWithPanic(PanicCode.ARITHMETIC_UNDER_OR_OVERFLOW); + IRewardSplitter(rewardSplitter).decreaseShares(user1, shares + 1); + } + + function test_failsWhenVaultNotHarvested() public { + uint256 unlockedMevReward = 0; + skip(REWARDS_DELAY + 1); + _setVaultRewards(vault, 1 ether, unlockedMevReward, avgRewardPerSecond); + + skip(REWARDS_DELAY + 1); + _setVaultRewards(vault, 2 ether, unlockedMevReward, avgRewardPerSecond); + + vm.prank(vaultAdmin); + vm.expectRevert(IRewardSplitter.NotHarvested.selector); + IRewardSplitter(rewardSplitter).decreaseShares(user1, 1); + } + + function test_doesNotAffectRewards() public { + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, shares); + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); + uint256 totalReward = 1 ether; + uint256 fee = 0.1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + uint256 feeShares = IVaultState(vault).convertToShares(fee); + + assertEq(IVaultFee(vault).feeRecipient(), rewardSplitter); + assertEq(IVaultState(vault).getShares(rewardSplitter), feeShares); + + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).decreaseShares(vaultAdmin, 1); + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), feeShares / 2); + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(vaultAdmin), feeShares / 2); + } + + function test_vaultAdminCanDecreaseShares() public { + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).decreaseShares(user1, 1); + + uint128 newShares = shares - 1; + assertEq(IRewardSplitter(rewardSplitter).sharesOf(user1), newShares); + assertEq(IRewardSplitter(rewardSplitter).totalShares(), newShares); + } +} + +contract EthRewardSplitterSyncRewardsTest is Test, EthRewardSplitterTest { + uint128 public constant shares = 100; + + function setUp() public override { + super.setUp(); + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + } + + function test_NoOpWhenUpToDate() public { + uint256 totalReward = 1 ether; + uint256 unlockedMevReward = 0; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); + IVaultState(vault).updateState(harvestParams); + + bool canSyncRewards; + canSyncRewards = IRewardSplitter(rewardSplitter).canSyncRewards(); + assertTrue(canSyncRewards); + IRewardSplitter(rewardSplitter).syncRewards(); + + canSyncRewards = IRewardSplitter(rewardSplitter).canSyncRewards(); + assertFalse(canSyncRewards); + + vm.recordLogs(); + IRewardSplitter(rewardSplitter).syncRewards(); + + // check that RewardsSynced event was not emitted + Vm.Log[] memory logs = vm.getRecordedLogs(); + assertEq(logs.length, 0); + } + + function test_noOpWithZeroTotalShares() public { + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).decreaseShares(user1, shares); + + uint256 totalReward = 1 ether; + uint256 unlockedMevReward = 0; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); + IVaultState(vault).updateState(harvestParams); + + bool canSyncRewards = IRewardSplitter(rewardSplitter).canSyncRewards(); + assertFalse(canSyncRewards); + + vm.recordLogs(); + IRewardSplitter(rewardSplitter).syncRewards(); + + // check that RewardsSynced event was not emitted + Vm.Log[] memory logs = vm.getRecordedLogs(); + assertEq(logs.length, 0); + } + + function test_anyoneCanSyncRewards() public { + vm.prank(vaultAdmin); + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); + uint256 totalReward = 1 ether; + uint256 fee = 0.1 ether; + uint256 unlockedMevReward = 0; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); + IVaultState(vault).updateState(harvestParams); + uint256 feeShares = IVaultState(vault).convertToShares(fee); + + assertTrue(IRewardSplitter(rewardSplitter).canSyncRewards()); + + vm.expectEmit(rewardSplitter); + emit IRewardSplitter.RewardsSynced(feeShares, feeShares * 1 ether / shares); + IRewardSplitter(rewardSplitter).syncRewards(); + } +} + +contract EthRewardSplitterClaimVaultTokensTest is EthRewardSplitterTest { + uint128 public constant shares = 100; + uint256 rewards; + address erc20Vault; + address erc20VaultAdmin; + + function setUp() public override { + super.setUp(); + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), 0, 0); + IVaultState(vault).updateState(harvestParams); + + IRewardSplitter(rewardSplitter).syncRewards(); + rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + + IEthErc20Vault.EthErc20VaultInitParams memory params = IEthErc20Vault.EthErc20VaultInitParams({ + capacity: type(uint256).max, + feePercent: 1000, + metadataIpfsHash: '', + name: 'SW ETH Vault', + symbol: 'SW-ETH-1' + }); + erc20Vault = IEthVaultFactory(erc20VaultFactory).createVault{value: SECURITY_DEPOSIT}(abi.encode(params), true); + + // collateralize vault (imitate validator creation) + _collateralizeVault(erc20Vault); + + // Remember erc20 vault admin + erc20VaultAdmin = IVaultAdmin(erc20Vault).admin(); + } + + function test_revertsForNotErc20Vault() public { + vm.expectRevert(); + IRewardSplitter(rewardSplitter).claimVaultTokens(rewards, user1); + } + + function test_canClaimForErc20Vault() public { + // create reward splitter and connect to erc20 vault + vm.startPrank(erc20VaultAdmin); + rewardSplitter = IRewardSplitterFactory(rewardSplitterFactory).createRewardSplitter(erc20Vault); + IVaultFee(erc20Vault).setFeeRecipient(rewardSplitter); + vm.stopPrank(); + + // increase shares + vm.prank(erc20VaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + // harvest vault rewards + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + erc20Vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(erc20Vault).updateState(harvestParams); + + // sync rewards to splitter + IRewardSplitter(rewardSplitter).syncRewards(); + rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + + // claim vault tokens + vm.prank(user1); + vm.expectEmit(rewardSplitter); + emit IRewardSplitter.RewardsWithdrawn(user1, rewards); + IRewardSplitter(rewardSplitter).claimVaultTokens(rewards, user1); + + // check no rewards left + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); + + // second claim should fail + vm.prank(user1); + expectRevertWithPanic(PanicCode.ARITHMETIC_UNDER_OR_OVERFLOW); + IRewardSplitter(rewardSplitter).claimVaultTokens(rewards, user1); + } +} + +contract EthRewardSplitterEnterExitQueueTest is EthRewardSplitterTest { + uint128 public constant shares = 100; + uint256 rewards; + + function setUp() public override { + super.setUp(); + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), 0, 0); + IVaultState(vault).updateState(harvestParams); + + IRewardSplitter(rewardSplitter).syncRewards(); + rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + } + + function test_enterExitQueueWithMulticall() public { + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); + + // harvest vault rewards + uint256 totalReward = 2 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + + // harvest vault rewards one more time + totalReward = 3 ether; + skip(REWARDS_DELAY + 1); + harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + + // Prepare updateVaultState call + bytes memory updateStateCall = abi.encodeWithSignature( + "updateVaultState((bytes32,int160,uint160,bytes32[]))", + harvestParams + ); + + // Call enterExitQueue prepended with updateStateCall + vm.prank(user1); + bytes[] memory enterExitQueueCalls = new bytes[](2); + enterExitQueueCalls[0] = updateStateCall; + enterExitQueueCalls[1] = abi.encodeWithSignature( + "enterExitQueue(uint256,address)", type(uint256).max, user1 + ); + IRewardSplitter(rewardSplitter).multicall(enterExitQueueCalls); + + // check updateState call succeeded + assertFalse(IVaultState(vault).isStateUpdateRequired()); + + // check splitter rewards are synced + assertFalse(IRewardSplitter(rewardSplitter).canSyncRewards()); + + // check all user rewards are withdrawn + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); + } +} + +contract EthRewardSplitterEnterExitQueueOnBehalfTest is EthRewardSplitterTest { + uint128 public constant shares = 100; + uint256 rewards; + + function setUp() public override { + super.setUp(); + + // add shareholder + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + // deposit vault + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user2, ZERO_ADDRESS); + + // set vault rewards + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + + // set shareholder rewards + IRewardSplitter(rewardSplitter).syncRewards(); + rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + + // enable claim on behalf + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + } + + function test_failsIfClaimOnBehalfDisabled() public { + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).setClaimOnBehalf(false); + + vm.expectRevert(Errors.AccessDenied.selector); + IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); + } + + function test_withdrawFixedRewards() public { + // check onBehalf and rewards, do not check positionTicket + vm.expectEmit(true, false, true, false); + emit IRewardSplitter.ExitQueueEnteredOnBehalf(user1, 0, rewards); + + // enter exit queue on behalf + IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); + + // check splitter rewards are synced + assertFalse(IRewardSplitter(rewardSplitter).canSyncRewards()); + + // check all user rewards are withdrawn + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); + } + + function test_withdrawAllRewards() public { + // set vault rewards + uint256 totalReward = 2 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + + // check onBehalf, do not check positionTicket and rewards + vm.expectEmit(true, false, false, false); + emit IRewardSplitter.ExitQueueEnteredOnBehalf(user1, 0, 0); + + // enter exit queue on behalf + IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(type(uint256).max, user1); + + // check splitter rewards are synced + assertFalse(IRewardSplitter(rewardSplitter).canSyncRewards()); + + // check all user rewards are withdrawn + assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); + } +} + + +contract EthRewardSplitterClaimExitedAssetsOnBehalfTest is EthRewardSplitterTest { + uint128 public constant shares = 100; + uint256 rewards; + uint256 positionTicket; + uint256 timestamp; + + function setUp() public override { + super.setUp(); + + // add shareholder + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + // deposit vault + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user2, ZERO_ADDRESS); + + // set vault rewards + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + + // set shareholder rewards + IRewardSplitter(rewardSplitter).syncRewards(); + rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + + // enable claim on behalf + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + + // enter exit queue on behalf + positionTicket = IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); + timestamp = block.timestamp; + } + + function test_failsIfInvalidPosition() public { + positionTicket++; + int256 exitQueueIndex = IEthVault(vault).getExitQueueIndex(positionTicket); + + vm.expectRevert(Errors.InvalidPosition.selector); + + // claim exited assets on behalf + IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( + positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + ); + } + + function test_basic() public { + skip(exitingAssetsClaimDelay + 1); + + uint256 balanceBeforeClaim = user1.balance; + + // check onBehalf, positionTicket, do not check amount + vm.expectEmit(true, true, false, false); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(user1, positionTicket, 0); + + // claim exited assets on behalf + int256 exitQueueIndex = IEthVault(vault).getExitQueueIndex(positionTicket); + IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( + positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + ); + + // Take 1 ether vault reward, apply 10% vault fee + uint256 exitedAssets = 0.1 ether; + + // check user balance change, leave 1 wei for rounding error + assertApproxEqAbs(user1.balance - balanceBeforeClaim, exitedAssets, 1 wei); + + // check repeating call fails + vm.expectRevert(Errors.InvalidPosition.selector); + IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( + positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + ); + } +} + + +contract EthRewardSplitterClaimExitedAssetsOnBehalfMultipleUsersTest is EthRewardSplitterTest { + uint128 public constant shares = 100; + uint256 rewards; + uint256 timestamp; + + function setUp() public override { + super.setUp(); + + // add shareholder + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + // assign 10% of shares to user1 and 90% to user2 + IRewardSplitter(rewardSplitter).increaseShares(user2, 9 * shares); + + // deposit vault + IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user2, ZERO_ADDRESS); + + // set vault rewards + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + + // enable claim on behalf + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + } + + function test_multipleShareholder() public { + uint256 splitterBalanceBeforeClaim = rewardSplitter.balance; + + // Take 1 ether vault reward, apply 10% vault fee + // got 0.1 ether + // 10% to user1, 90% to user2 + uint256 exitedAssets1 = 0.01 ether; + uint256 exitedAssets2 = 0.09 ether; + + // Each exit-claim combination adds up rounding error 1 wei + uint256 maxError1 = 1 wei; + uint256 maxError2 = 2 wei; + + _claimExitedAssetsOnBehalf(user1, exitedAssets1, maxError1); + _claimExitedAssetsOnBehalf(user2, exitedAssets2, maxError2); + + // check unclaimed rewards on splitter balance + assertEq(rewardSplitter.balance - splitterBalanceBeforeClaim, 0); + } + + function _claimExitedAssetsOnBehalf( + address user, uint256 exitedAssets, uint256 maxError + ) internal { + // set balances before claim + uint256 userBalanceBeforeClaim = user.balance; + + // enter exit queue on behalf + uint256 positionTicket = IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf( + type(uint256).max, user + ); + timestamp = block.timestamp; + + skip(exitingAssetsClaimDelay + 1); + + // check onBehalf, positionTicket, do not check amount + vm.expectEmit(true, true, false, false); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(user, positionTicket, 0); + + // claim exited assets on behalf + int256 exitQueueIndex = IEthVault(vault).getExitQueueIndex(positionTicket); + IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( + positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + ); + + // check user balance change, allow rounding error + assertApproxEqAbs(user.balance - userBalanceBeforeClaim, exitedAssets, maxError); + } +} diff --git a/test/Fork.t.sol b/test/Fork.t.sol new file mode 100644 index 00000000..989cf994 --- /dev/null +++ b/test/Fork.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +abstract contract ForkTest { + uint256 public forkBlockNumber; + address public keeper; + address public validatorsRegistry; + address public vaultsRegistry; + address public osTokenVaultController; + address public osTokenConfig; + address public osTokenVaultEscrow; + address public sharedMevEscrow; + address public depositDataRegistry; + uint256 public exitingAssetsClaimDelay; + address public v2VaultFactory; + address public erc20VaultFactory; + address public vaultV3Impl; + address public genesisVault; + address public poolEscrow; + address public rewardEthToken; +} diff --git a/test/GnoRewardSplitter.t.sol b/test/GnoRewardSplitter.t.sol new file mode 100644 index 00000000..1168d420 --- /dev/null +++ b/test/GnoRewardSplitter.t.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IGnoVault} from '../contracts/interfaces/IGnoVault.sol'; +import {IGnoVaultFactory} from '../contracts/interfaces/IGnoVaultFactory.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IVaultAdmin} from '../contracts/interfaces/IVaultAdmin.sol'; +import {IVaultFee} from '../contracts/interfaces/IVaultFee.sol'; +import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; +import {GnoVault} from '../contracts/vaults/gnosis/GnoVault.sol'; +import {RewardSplitterFactory} from '../contracts/misc/RewardSplitterFactory.sol'; +import {IRewardSplitterFactory} from '../contracts/interfaces/IRewardSplitterFactory.sol'; +import {GnoRewardSplitter} from '../contracts/misc/GnoRewardSplitter.sol'; +import {RewardSplitter} from '../contracts/misc/RewardSplitter.sol'; +import {IRewardSplitter} from '../contracts/interfaces/IRewardSplitter.sol'; +import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; +import {IVaultGnoStaking} from '../contracts/interfaces/IVaultGnoStaking.sol'; +import {Vm} from '../lib/forge-std/src/Vm.sol'; +import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; +import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; +import {Test} from '../lib/forge-std/src/Test.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {RewardsTest} from './Rewards.t.sol'; +import {ConstantsTest} from './Constants.t.sol'; +import {GnosisForkTest} from './GnosisFork.t.sol'; + +abstract contract GnoRewardSplitterTest is Test, ConstantsTest, GnosisForkTest, RewardsTest { + address public constant user1 = address(0x1); + address public constant user2 = address(0x2); + + address public vault; + address public vaultAdmin; + address public rewardSplitter; + address public rewardSplitterFactory; + uint256 avgRewardPerSecond = 1585489600; + + function setUp() public virtual override(ConstantsTest, GnosisForkTest, RewardsTest) { + GnosisForkTest.setUp(); + ConstantsTest.setUp(); + RewardsTest.setUp(); + + vm.prank(VaultsRegistry(vaultsRegistry).owner()); + VaultsRegistry(vaultsRegistry).addFactory(v2VaultFactory); + + // set GNO token balance + deal(address(gnoToken), address(this), 100 ether); + + // approve GNO token for V2 vault factory + IERC20(gnoToken).approve(v2VaultFactory, 1 ether); + + // create V2 vault + IGnoVault.GnoVaultInitParams memory params = IGnoVault.GnoVaultInitParams({ + capacity: type(uint256).max, + feePercent: 1000, + metadataIpfsHash: '' + }); + vault = IGnoVaultFactory(v2VaultFactory).createVault(abi.encode(params), false); + + // collateralize vault (imitate validator creation) + _collateralizeVault(vault); + + // set vault admin + vaultAdmin = IVaultAdmin(vault).admin(); + + // create reward splitter and connect to vault + vm.startPrank(vaultAdmin); + address rewardSplitterImpl = address(new GnoRewardSplitter(gnoToken)); + rewardSplitterFactory = address(new RewardSplitterFactory(rewardSplitterImpl)); + rewardSplitter = IRewardSplitterFactory(rewardSplitterFactory).createRewardSplitter(vault); + IVaultFee(vault).setFeeRecipient(rewardSplitter); + vm.stopPrank(); + } +} + +contract GnoRewardSplitterClaimExitedAssetsOnBehalfTest is GnoRewardSplitterTest { + uint128 public constant shares = 100; + uint256 rewards; + uint256 positionTicket; + uint256 timestamp; + + function setUp() public override { + super.setUp(); + + // add shareholder + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + + // approve GNO token for vault + IERC20(gnoToken).approve(vault, 10 ether); + + // deposit vault + uint256 depositAmount = 10 ether - SECURITY_DEPOSIT; + IVaultGnoStaking(vault).deposit(depositAmount, user2, ZERO_ADDRESS); + + // set vault rewards + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + + // set shareholder rewards + IRewardSplitter(rewardSplitter).syncRewards(); + rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + + // enable claim on behalf + vm.prank(vaultAdmin); + IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + + // enter exit queue on behalf + positionTicket = IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); + timestamp = block.timestamp; + } + + function test_basic() public { + skip(exitingAssetsClaimDelay + 1); + + // repeat update state to trigger exit queue processing + uint256 totalReward = 1 ether; + skip(REWARDS_DELAY + 1); + IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( + vault, SafeCast.toInt256(totalReward), 0, 0 + ); + IVaultState(vault).updateState(harvestParams); + + // set shareholder balance before claim + uint256 balanceBeforeClaim = IERC20(gnoToken).balanceOf(user1); + + // check onBehalf, positionTicket, do not check amount + vm.expectEmit(true, true, false, false); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(user1, positionTicket, 0); + + // claim exited assets on behalf + int256 exitQueueIndex = IGnoVault(vault).getExitQueueIndex(positionTicket); + IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( + positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + ); + + // Take 1 ether vault reward, apply 10% vault fee + uint256 exitedAssets = 0.1 ether; + + // check user balance change, leave 1 wei for rounding error + uint256 balanceAfterClaim = IERC20(gnoToken).balanceOf(user1); + assertApproxEqAbs(balanceAfterClaim - balanceBeforeClaim, exitedAssets, 1 wei); + + // check repeating call fails + vm.expectRevert(Errors.InvalidPosition.selector); + IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( + positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + ); + } +} diff --git a/test/GnosisFork.t.sol b/test/GnosisFork.t.sol new file mode 100644 index 00000000..d19c0dd6 --- /dev/null +++ b/test/GnosisFork.t.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Test} from '../lib/forge-std/src/Test.sol'; +import {ForkTest} from './Fork.t.sol'; + + +abstract contract GnosisForkTest is Test, ForkTest { + address public gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; + + function setUp() public virtual { + forkBlockNumber = 38760307; + + keeper = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; + validatorsRegistry = 0x0B98057eA310F4d31F2a452B414647007d1645d9; + vaultsRegistry = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; + osTokenVaultController = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; + osTokenConfig = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; + osTokenVaultEscrow = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; + sharedMevEscrow = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; + depositDataRegistry = 0x58e16621B5c0786D6667D2d54E28A20940269E16; + exitingAssetsClaimDelay = 24 hours; + v2VaultFactory = 0x78c54FEfAB5DAb75ee7461565b85341dd8b92e30; + erc20VaultFactory = 0x0aaa2b3Cf5F14eF24Afb2CD7Cf4CcCC065Be108B; + vaultV3Impl = 0x0000000000000000000000000000000000000000; + genesisVault = 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a; + poolEscrow = 0x0000000000000000000000000000000000000000; + rewardEthToken = 0x0000000000000000000000000000000000000000; + gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; + + vm.createSelectFork(vm.envString('GNOSIS_RPC_URL'), forkBlockNumber); + } +} diff --git a/test/MainnetFork.t.sol b/test/MainnetFork.t.sol new file mode 100644 index 00000000..ba606093 --- /dev/null +++ b/test/MainnetFork.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Test} from '../lib/forge-std/src/Test.sol'; +import {ForkTest} from './Fork.t.sol'; + + +abstract contract MainnetForkTest is Test, ForkTest { + + function setUp() public virtual { + forkBlockNumber = 21737000; + + keeper = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; + validatorsRegistry = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + vaultsRegistry = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; + osTokenVaultController = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; + osTokenConfig = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; + osTokenVaultEscrow = 0x09e84205DF7c68907e619D07aFD90143c5763605; + sharedMevEscrow = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; + depositDataRegistry = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; + exitingAssetsClaimDelay = 24 hours; + v2VaultFactory = 0xfaa05900019f6E465086bcE16Bb3F06992715D53; + erc20VaultFactory = 0x978302cAcAdEDE5d503390E176e86F3889Df6Ce6; + vaultV3Impl = 0x9747e1fF73f1759217AFD212Dd36d21360D0880A; + genesisVault = 0xAC0F906E433d58FA868F936E8A43230473652885; + poolEscrow = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; + rewardEthToken = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; + + vm.createSelectFork(vm.envString('MAINNET_RPC_URL'), forkBlockNumber); + } +} diff --git a/test/RewardSplitter.spec.ts b/test/RewardSplitter.spec.ts deleted file mode 100644 index 97b82dc4..00000000 --- a/test/RewardSplitter.spec.ts +++ /dev/null @@ -1,481 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthErc20Vault, - EthVault, - Keeper, - RewardSplitter, - RewardSplitter__factory, - DepositDataRegistry, -} from '../typechain-types' -import { createRewardSplitterFactory, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { PANIC_CODES, SECURITY_DEPOSIT, ZERO_ADDRESS } from './shared/constants' -import { collateralizeEthVault, getRewardsRootProof, updateRewards } from './shared/rewards' -import snapshotGasCost from './shared/snapshotGasCost' -import { MAINNET_FORK } from '../helpers/constants' - -describe('RewardSplitter', () => { - let admin: Wallet, other: Wallet - let vault: EthVault, - keeper: Keeper, - rewardSplitter: RewardSplitter, - erc20Vault: EthErc20Vault, - depositDataRegistry: DepositDataRegistry - - before('create fixture loader', async () => { - ;[admin, other] = (await (ethers as any).getSigners()).slice(1, 3) - }) - - beforeEach(async () => { - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthVault( - admin, - { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - }, - false, - true - ) - erc20Vault = await fixture.createEthErc20Vault( - admin, - { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - }, - false, - true - ) - keeper = fixture.keeper - depositDataRegistry = fixture.depositDataRegistry - await collateralizeEthVault( - vault, - keeper, - depositDataRegistry, - admin, - fixture.validatorsRegistry - ) - await collateralizeEthVault( - erc20Vault, - keeper, - depositDataRegistry, - admin, - fixture.validatorsRegistry - ) - - const rewardSplitterFactory = await createRewardSplitterFactory() - const rewardSplitterAddress = await rewardSplitterFactory - .connect(admin) - .createRewardSplitter.staticCall(await vault.getAddress()) - await rewardSplitterFactory.connect(admin).createRewardSplitter(await vault.getAddress()) - rewardSplitter = RewardSplitter__factory.connect(rewardSplitterAddress, admin) - await vault.connect(admin).setFeeRecipient(rewardSplitterAddress) - }) - - describe('increase shares', () => { - it('fails with zero shares', async () => { - await expect( - rewardSplitter.connect(admin).increaseShares(other.address, 0) - ).to.be.revertedWithCustomError(rewardSplitter, 'InvalidAmount') - }) - - it('fails with zero account', async () => { - await expect( - rewardSplitter.connect(admin).increaseShares(ZERO_ADDRESS, 1) - ).to.be.revertedWithCustomError(rewardSplitter, 'InvalidAccount') - }) - - it('fails by not owner', async () => { - await expect( - rewardSplitter.connect(other).increaseShares(other.address, 1) - ).to.be.revertedWithCustomError(rewardSplitter, 'OwnableUnauthorizedAccount') - }) - - it('fails when vault not harvested', async () => { - await rewardSplitter.connect(admin).increaseShares(other.address, 1) - await updateRewards( - keeper, - [ - { - vault: await vault.getAddress(), - reward: ethers.parseEther('1'), - unlockedMevReward: 0n, - }, - ], - 0 - ) - await updateRewards( - keeper, - [ - { - vault: await vault.getAddress(), - reward: ethers.parseEther('2'), - unlockedMevReward: 0n, - }, - ], - 0 - ) - await expect( - rewardSplitter.connect(admin).increaseShares(other.address, 1) - ).to.be.revertedWithCustomError(rewardSplitter, 'NotHarvested') - }) - - it('increasing shares does not affect others rewards', async () => { - await rewardSplitter.connect(admin).increaseShares(other.address, 100) - await vault.deposit(other.address, ZERO_ADDRESS, { - value: ethers.parseEther('10') - SECURITY_DEPOSIT, - }) - const totalReward = ethers.parseEther('1') - const fee = ethers.parseEther('0.1') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - const feeShares = await vault.convertToShares(fee) - expect(await vault.feeRecipient()).to.eq(await rewardSplitter.getAddress()) - expect(await vault.getShares(await rewardSplitter.getAddress())).to.eq(feeShares) - - await rewardSplitter.connect(admin).increaseShares(admin.address, 100) - expect(await rewardSplitter.rewardsOf(other.address)).to.eq(feeShares) - expect(await rewardSplitter.rewardsOf(admin.address)).to.eq(0) - }) - - it('owner can increase shares', async () => { - const shares = 100 - const receipt = await rewardSplitter.connect(admin).increaseShares(other.address, shares) - expect(await rewardSplitter.sharesOf(other.address)).to.eq(shares) - expect(await rewardSplitter.totalShares()).to.eq(shares) - await expect(receipt) - .to.emit(rewardSplitter, 'SharesIncreased') - .withArgs(other.address, shares) - await snapshotGasCost(receipt) - }) - }) - - describe('decrease shares', () => { - const shares = 100 - beforeEach(async () => { - await rewardSplitter.connect(admin).increaseShares(other.address, shares) - }) - - it('fails with zero shares', async () => { - await expect( - rewardSplitter.connect(admin).decreaseShares(other.address, 0) - ).to.be.revertedWithCustomError(rewardSplitter, 'InvalidAmount') - }) - - it('fails with zero account', async () => { - await expect( - rewardSplitter.connect(admin).decreaseShares(ZERO_ADDRESS, 1) - ).to.be.revertedWithCustomError(rewardSplitter, 'InvalidAccount') - }) - - it('fails by not owner', async () => { - await expect( - rewardSplitter.connect(other).decreaseShares(other.address, 1) - ).to.be.revertedWithCustomError(rewardSplitter, 'OwnableUnauthorizedAccount') - }) - - it('fails with amount larger than balance', async () => { - await expect( - rewardSplitter.connect(admin).decreaseShares(other.address, shares + 1) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('fails when vault not harvested', async () => { - await updateRewards( - keeper, - [ - { - vault: await vault.getAddress(), - reward: ethers.parseEther('1'), - unlockedMevReward: 0n, - }, - ], - 0 - ) - await updateRewards( - keeper, - [ - { - vault: await vault.getAddress(), - reward: ethers.parseEther('2'), - unlockedMevReward: 0n, - }, - ], - 0 - ) - await expect( - rewardSplitter.connect(admin).decreaseShares(other.address, 1) - ).to.be.revertedWithCustomError(rewardSplitter, 'NotHarvested') - }) - - it('decreasing shares does not affect rewards', async () => { - await rewardSplitter.connect(admin).increaseShares(admin.address, shares) - await vault.deposit(other.address, ZERO_ADDRESS, { - value: ethers.parseEther('10') - SECURITY_DEPOSIT, - }) - const totalReward = ethers.parseEther('1') - const fee = ethers.parseEther('0.1') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - const feeShares = await vault.convertToShares(fee) - expect(await vault.feeRecipient()).to.eq(await rewardSplitter.getAddress()) - expect(await vault.getShares(await rewardSplitter.getAddress())).to.eq(feeShares) - - await rewardSplitter.connect(admin).decreaseShares(admin.address, 1) - expect(await rewardSplitter.rewardsOf(other.address)).to.eq(feeShares / 2n) - expect(await rewardSplitter.rewardsOf(admin.address)).to.eq(feeShares / 2n) - }) - - it('owner can decrease shares', async () => { - const receipt = await rewardSplitter.connect(admin).decreaseShares(other.address, 1) - const newShares = shares - 1 - - expect(await rewardSplitter.sharesOf(other.address)).to.eq(newShares) - expect(await rewardSplitter.totalShares()).to.eq(newShares) - await expect(receipt).to.emit(rewardSplitter, 'SharesDecreased').withArgs(other.address, 1) - await snapshotGasCost(receipt) - }) - }) - - describe('sync rewards', () => { - const shares = 100n - beforeEach(async () => { - await rewardSplitter.connect(admin).increaseShares(other.address, shares) - }) - - it('does not sync rewards when up to date', async () => { - const totalReward = ethers.parseEther('1') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - expect(await rewardSplitter.canSyncRewards()).to.eq(true) - await rewardSplitter.syncRewards() - expect(await rewardSplitter.canSyncRewards()).to.eq(false) - await expect(rewardSplitter.syncRewards()).to.not.emit(rewardSplitter, 'RewardsSynced') - }) - - it('does not sync rewards with zero total shares', async () => { - await rewardSplitter.connect(admin).decreaseShares(other.address, shares) - const totalReward = ethers.parseEther('1') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - expect(await rewardSplitter.canSyncRewards()).to.eq(false) - await expect(rewardSplitter.syncRewards()).to.not.emit(rewardSplitter, 'RewardsSynced') - }) - - it('anyone can sync rewards', async () => { - await vault.deposit(other.address, ZERO_ADDRESS, { - value: ethers.parseEther('10') - SECURITY_DEPOSIT, - }) - const totalReward = ethers.parseEther('1') - const fee = ethers.parseEther('0.1') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - const feeShares = await vault.convertToShares(fee) - expect(await rewardSplitter.canSyncRewards()).to.eq(true) - const receipt = await rewardSplitter.syncRewards() - - if (!MAINNET_FORK.enabled) { - expect(await rewardSplitter.totalRewards()).to.eq(feeShares) - } - await expect(receipt) - .to.emit(rewardSplitter, 'RewardsSynced') - .withArgs(feeShares, (feeShares * ethers.parseEther('1')) / shares) - await snapshotGasCost(receipt) - }) - }) - - describe('withdraw rewards', () => { - const shares = 100 - let rewards: bigint - - beforeEach(async () => { - await rewardSplitter.connect(admin).increaseShares(other.address, shares) - const totalReward = ethers.parseEther('1') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - await rewardSplitter.syncRewards() - rewards = await rewardSplitter.rewardsOf(other.address) - }) - - it('fails to claim vault tokens for not ERC-20 vault', async () => { - await expect(rewardSplitter.connect(other).claimVaultTokens(rewards, other.address)).to.be - .reverted - }) - - it('can claim vault tokens for ERC-20 vault', async () => { - // create rewards splitter - const rewardSplitterFactory = await createRewardSplitterFactory() - const rewardSplitterAddress = await rewardSplitterFactory - .connect(admin) - .createRewardSplitter.staticCall(await erc20Vault.getAddress()) - await rewardSplitterFactory.connect(admin).createRewardSplitter(await erc20Vault.getAddress()) - - // collateralize rewards splitter - const rewardSplitter = RewardSplitter__factory.connect(rewardSplitterAddress, admin) - await erc20Vault.connect(admin).setFeeRecipient(await rewardSplitter.getAddress()) - await rewardSplitter.connect(admin).increaseShares(other.address, shares) - const totalReward = ethers.parseEther('1') - const tree = await updateRewards( - keeper, - [{ vault: await erc20Vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - await erc20Vault.updateState({ - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await erc20Vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }) - await rewardSplitter.syncRewards() - const rewards = await rewardSplitter.rewardsOf(other.address) - - const receipt = await rewardSplitter.connect(other).claimVaultTokens(rewards, other.address) - await expect(receipt) - .to.emit(rewardSplitter, 'RewardsWithdrawn') - .withArgs(other.address, rewards) - expect(await rewardSplitter.rewardsOf(other.address)).to.eq(0) - - // second claim should fail - await expect( - rewardSplitter.connect(other).claimVaultTokens(rewards, other.address) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - await snapshotGasCost(receipt) - }) - - it('can enter exit queue with multicall', async () => { - await vault.deposit(other.address, ZERO_ADDRESS, { - value: ethers.parseEther('10') - SECURITY_DEPOSIT, - }) - let totalReward = ethers.parseEther('2') - await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - totalReward = ethers.parseEther('3') - const tree = await updateRewards( - keeper, - [{ vault: await vault.getAddress(), reward: totalReward, unlockedMevReward: 0n }], - 0 - ) - - const calls: string[] = [ - rewardSplitter.interface.encodeFunctionData('updateVaultState', [ - { - rewardsRoot: tree.root, - reward: totalReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: totalReward, - }), - }, - ]), - rewardSplitter.interface.encodeFunctionData('syncRewards'), - ] - const result = await rewardSplitter.multicall.staticCall([ - ...calls, - rewardSplitter.interface.encodeFunctionData('rewardsOf', [other.address]), - ]) - const rewards = rewardSplitter.interface.decodeFunctionResult('rewardsOf', result[2])[0] - - const receipt = await rewardSplitter - .connect(other) - .multicall([ - ...calls, - rewardSplitter.interface.encodeFunctionData('enterExitQueue', [rewards, other.address]), - ]) - expect(await rewardSplitter.rewardsOf(other.address)).to.eq(0) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/Rewards.t.sol b/test/Rewards.t.sol new file mode 100644 index 00000000..efad9ed9 --- /dev/null +++ b/test/Rewards.t.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; +import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; +import {IValidatorsRegistry} from '../contracts/interfaces/IValidatorsRegistry.sol'; +import {Keeper} from '../contracts/keeper/Keeper.sol'; +import {Test} from '../lib/forge-std/src/Test.sol'; +import {ForkTest} from './Fork.t.sol'; + + +abstract contract RewardsTest is Test, ForkTest { + address public oracle; + uint256 public oraclePrivateKey; + + function setUp() public virtual { + oracle = address(this); + oraclePrivateKey = 1; + + // setup oracle + (oracle, oraclePrivateKey) = makeAddrAndKey('oracle'); + address keeperOwner = Keeper(keeper).owner(); + vm.startPrank(keeperOwner); + Keeper(keeper).setValidatorsMinOracles(1); + Keeper(keeper).addOracle(oracle); + vm.stopPrank(); + } + + function _collateralizeVault(address _vault) internal { + IKeeperValidators.ApprovalParams memory approvalParams = IKeeperValidators.ApprovalParams({ + validatorsRegistryRoot: IValidatorsRegistry(validatorsRegistry).get_deposit_root(), + deadline: vm.getBlockTimestamp() + 1, + validators: 'validator1', + signatures: '', + exitSignaturesIpfsHash: 'ipfsHash' + }); + bytes32 digest = _hashTypedDataV4( + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' + ), + approvalParams.validatorsRegistryRoot, + _vault, + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); + + vm.prank(_vault); + Keeper(keeper).approveValidators(approvalParams); + } + + + function _setVaultRewards( + address _vault, + int256 reward, + uint256 unlockedMevReward, + uint256 avgRewardPerSecond + ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { + address keeperOwner = Keeper(keeper).owner(); + vm.startPrank(keeperOwner); + Keeper(keeper).setRewardsMinOracles(1); + vm.stopPrank(); + + bytes32 root = keccak256( + bytes.concat( + keccak256( + abi.encode(_vault, SafeCast.toInt160(reward), SafeCast.toUint160(unlockedMevReward)) + ) + ) + ); + IKeeperRewards.RewardsUpdateParams memory params = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: root, + avgRewardPerSecond: avgRewardPerSecond, + updateTimestamp: uint64(vm.getBlockTimestamp()), + rewardsIpfsHash: 'ipfsHash', + signatures: '' + }); + bytes32 digest = _hashTypedDataV4( + keccak256( + abi.encode( + keccak256( + 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' + ), + root, + keccak256(bytes(params.rewardsIpfsHash)), + params.avgRewardPerSecond, + params.updateTimestamp, + Keeper(keeper).rewardsNonce() + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(oraclePrivateKey, digest); + params.signatures = abi.encodePacked(r, s, v); + Keeper(keeper).updateRewards(params); + bytes32[] memory proof = new bytes32[](0); + harvestParams = IKeeperRewards.HarvestParams({ + rewardsRoot: root, + reward: SafeCast.toInt160(reward), + unlockedMevReward: SafeCast.toUint160(unlockedMevReward), + proof: proof + }); + } + + function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) { + return + MessageHashUtils.toTypedDataHash( + keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256(bytes('KeeperOracles')), + keccak256(bytes('1')), + block.chainid, + keeper + ) + ), + structHash + ); + } +} \ No newline at end of file diff --git a/test/VaultExitQueueClaim.t.sol b/test/VaultExitQueueClaim.t.sol index d286f492..535beb48 100644 --- a/test/VaultExitQueueClaim.t.sol +++ b/test/VaultExitQueueClaim.t.sol @@ -21,8 +21,11 @@ import {Test} from '../lib/forge-std/src/Test.sol'; import {UUPSUpgradeable} from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {RewardsTest} from './Rewards.t.sol'; +import {MainnetForkTest} from './MainnetFork.t.sol'; -contract VaultExitQueueClaimTest is Test { + +contract VaultExitQueueClaimTest is Test, MainnetForkTest, RewardsTest { struct ExitRequest { uint256 totalTickets; uint256 positionTicket; @@ -31,40 +34,15 @@ contract VaultExitQueueClaimTest is Test { uint256 timestamp; } - uint256 public constant forkBlockNumber = 21737000; - address public constant vaultsRegistry = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; - address public constant validatorsRegistry = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address public constant keeper = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; - address public constant osTokenVaultController = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; - address public constant osTokenConfig = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; - address public constant osTokenVaultEscrow = 0x09e84205DF7c68907e619D07aFD90143c5763605; - address public constant sharedMevEscrow = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; - address public constant depositDataRegistry = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; - uint256 public constant exitingAssetsClaimDelay = 24 hours; - address public constant v2VaultFactory = 0xfaa05900019f6E465086bcE16Bb3F06992715D53; - address public constant vaultV3Impl = 0x9747e1fF73f1759217AFD212Dd36d21360D0880A; - address public constant genesisVault = 0xAC0F906E433d58FA868F936E8A43230473652885; - address public constant poolEscrow = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; - address public constant rewardEthToken = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; - address public constant user1 = address(0x1); address public constant user2 = address(0x2); - address public oracle; - uint256 public oraclePrivateKey; - address public vault; - function setUp() public { - vm.createSelectFork(vm.envString('MAINNET_RPC_URL'), forkBlockNumber); + function setUp() public override(MainnetForkTest, RewardsTest) { + MainnetForkTest.setUp(); - // setup oracle - (oracle, oraclePrivateKey) = makeAddrAndKey('oracle'); - address keeperOwner = Keeper(keeper).owner(); - vm.startPrank(keeperOwner); - Keeper(keeper).setValidatorsMinOracles(1); - Keeper(keeper).addOracle(oracle); - vm.stopPrank(); + RewardsTest.setUp(); vm.prank(VaultsRegistry(vaultsRegistry).owner()); VaultsRegistry(vaultsRegistry).addFactory(v2VaultFactory); @@ -455,102 +433,4 @@ contract VaultExitQueueClaimTest is Test { assertEq(exitedAssets, 0); } } - - function _collateralizeVault(address _vault) private { - IKeeperValidators.ApprovalParams memory approvalParams = IKeeperValidators.ApprovalParams({ - validatorsRegistryRoot: IValidatorsRegistry(validatorsRegistry).get_deposit_root(), - deadline: vm.getBlockTimestamp() + 1, - validators: 'validator1', - signatures: '', - exitSignaturesIpfsHash: 'ipfsHash' - }); - bytes32 digest = _hashTypedDataV4( - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' - ), - approvalParams.validatorsRegistryRoot, - _vault, - keccak256(approvalParams.validators), - keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), - approvalParams.deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(oraclePrivateKey, digest); - approvalParams.signatures = abi.encodePacked(r, s, v); - - vm.prank(_vault); - Keeper(keeper).approveValidators(approvalParams); - } - - function _setVaultRewards( - address _vault, - int256 reward, - uint256 unlockedMevReward, - uint256 avgRewardPerSecond - ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { - address keeperOwner = Keeper(keeper).owner(); - vm.startPrank(keeperOwner); - Keeper(keeper).setRewardsMinOracles(1); - vm.stopPrank(); - - bytes32 root = keccak256( - bytes.concat( - keccak256( - abi.encode(_vault, SafeCast.toInt160(reward), SafeCast.toUint160(unlockedMevReward)) - ) - ) - ); - IKeeperRewards.RewardsUpdateParams memory params = IKeeperRewards.RewardsUpdateParams({ - rewardsRoot: root, - avgRewardPerSecond: avgRewardPerSecond, - updateTimestamp: uint64(vm.getBlockTimestamp()), - rewardsIpfsHash: 'ipfsHash', - signatures: '' - }); - bytes32 digest = _hashTypedDataV4( - keccak256( - abi.encode( - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' - ), - root, - keccak256(bytes(params.rewardsIpfsHash)), - params.avgRewardPerSecond, - params.updateTimestamp, - Keeper(keeper).rewardsNonce() - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(oraclePrivateKey, digest); - params.signatures = abi.encodePacked(r, s, v); - Keeper(keeper).updateRewards(params); - bytes32[] memory proof = new bytes32[](0); - harvestParams = IKeeperRewards.HarvestParams({ - rewardsRoot: root, - reward: SafeCast.toInt160(reward), - unlockedMevReward: SafeCast.toUint160(unlockedMevReward), - proof: proof - }); - } - - function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) { - return - MessageHashUtils.toTypedDataHash( - keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes('KeeperOracles')), - keccak256(bytes('1')), - block.chainid, - keeper - ) - ), - structHash - ); - } } From ca9c97a312c9fcd164007368d639a0c3502be2de Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Wed, 2 Apr 2025 01:04:54 +0300 Subject: [PATCH 03/15] Replace holesky with hoodi (#103) --- .openzeppelin/unknown-560048.json | 12394 ++++++++++++++++ abi/IERC1363.json | 373 + abi/IERC1967.json | 47 + abi/IRewardSplitter.json | 172 +- deployments/holesky-upgrade-v2-tx.json | 186 - deployments/holesky-upgrade-v3-tx.json | 213 - deployments/holesky-vault-v2-upgrades.json | 41 - deployments/hoodi-upgrade-v2-tx.json | 172 + deployments/hoodi-upgrade-v3-tx.json | 213 + deployments/hoodi-upgrade-v4-tx.json | 72 + ...ades.json => hoodi-vault-v2-upgrades.json} | 14 +- deployments/hoodi-vault-v3-upgrades.json | 23 + deployments/hoodi-vault-v4-upgrades.json | 23 + deployments/hoodi.json | 25 + hardhat.config.ts | 10 +- helpers/constants.ts | 16 +- helpers/types.ts | 2 +- package.json | 5 +- tasks/eth-full-deploy-local.ts | 2 +- 19 files changed, 13531 insertions(+), 472 deletions(-) create mode 100644 .openzeppelin/unknown-560048.json create mode 100644 abi/IERC1363.json create mode 100644 abi/IERC1967.json delete mode 100644 deployments/holesky-upgrade-v2-tx.json delete mode 100644 deployments/holesky-upgrade-v3-tx.json delete mode 100644 deployments/holesky-vault-v2-upgrades.json create mode 100644 deployments/hoodi-upgrade-v2-tx.json create mode 100644 deployments/hoodi-upgrade-v3-tx.json create mode 100644 deployments/hoodi-upgrade-v4-tx.json rename deployments/{holesky-vault-v3-upgrades.json => hoodi-vault-v2-upgrades.json} (59%) create mode 100644 deployments/hoodi-vault-v3-upgrades.json create mode 100644 deployments/hoodi-vault-v4-upgrades.json create mode 100644 deployments/hoodi.json diff --git a/.openzeppelin/unknown-560048.json b/.openzeppelin/unknown-560048.json new file mode 100644 index 00000000..bf8bf983 --- /dev/null +++ b/.openzeppelin/unknown-560048.json @@ -0,0 +1,12394 @@ +{ + "manifestVersion": "3.2", + "proxies": [], + "impls": { + "276380239a8703a10aa03afde862b5ae86f7a4d1709f20dc1381d9ccc4d72e76": { + "address": "0x16c35CC583b35c301D1884D4cdFb6e06A2dF45f2", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:48" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)11653_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:30" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "158", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:268" + }, + { + "label": "validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:29" + }, + { + "label": "validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:32" + }, + { + "label": "_keysManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "211", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:199" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:212" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:313" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:153" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:142" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)45_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)101_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)11647_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)11653_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)9945_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "67ebb0a156674a06e0516fed634b8deb7ee072ac2b4a2b3aca86e9b1a3a240d6": { + "address": "0x3c4ae629bf823475192124E02b9879D3C1fd4538", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:48" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)11653_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:30" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "158", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:268" + }, + { + "label": "validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:29" + }, + { + "label": "validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:32" + }, + { + "label": "_keysManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "211", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:199" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:212" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:313" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:153" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:142" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:69" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivVault", + "src": "contracts/vaults/ethereum/EthPrivVault.sol:104" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)45_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)101_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)11647_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)11653_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)9945_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "4155fcddea6e92a813cd4b072ef9dd9f3c13a77452c463cfb01f768f21f2386c": { + "address": "0xdeCC5732c21be460017FEE770022A34ac291f3CC", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:48" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)11653_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:30" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "213", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:268" + }, + { + "label": "validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:29" + }, + { + "label": "validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:32" + }, + { + "label": "_keysManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "266", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:199" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:212" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:313" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:153" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)45_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)101_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "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(OsTokenPosition)9945_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)11647_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)11653_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)9945_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "325b626d76800db58b2f2dcbf4805624ec5d83c98f3b92c63416c425a7816420": { + "address": "0x7571Bda0eB8028419f7b195230E966D42a27A005", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:48" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)11653_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:30" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "213", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:268" + }, + { + "label": "validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:29" + }, + { + "label": "validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:32" + }, + { + "label": "_keysManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "266", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:199" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:212" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:313" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:153" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:69" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivErc20Vault", + "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:104" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)45_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)101_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)9945_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)11647_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)11653_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)9945_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "4068b882d4fa3f1df7923f801ac7a2c41f0855df3160e328b62bfa285fafb50a": { + "address": "0x2CBF6995d5cd13744e91Cae01B5B2bAF19b6B94d", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:48" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)11653_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:30" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "158", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:268" + }, + { + "label": "validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:29" + }, + { + "label": "validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:32" + }, + { + "label": "_keysManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "211", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:199" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:212" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:313" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:153" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:142" + }, + { + "label": "__gap", + "offset": 0, + "slot": "513", + "type": "t_array(t_uint256)50_storage", + "contract": "EthGenesisVault", + "src": "contracts/vaults/ethereum/EthGenesisVault.sol:241" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)45_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)101_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)11647_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)11653_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)9945_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "abf4d6d9349b3c6b6cbaf813f1615c8857e77679edf711ebc27d46fc62efdecd": { + "address": "0xd57c19f20168406d162852515030e00e49bB7781", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:48" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)11795_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:30" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "158", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:268" + }, + { + "label": "validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:29" + }, + { + "label": "validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:32" + }, + { + "label": "_keysManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:34" + }, + { + "label": "__gap", + "offset": 0, + "slot": "211", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:199" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:243" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "311", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "362", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:153" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "412", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "413", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "414", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "464", + "type": "t_array(t_uint256)50_storage", + "contract": "EthFoxVault", + "src": "contracts/vaults/ethereum/custom/EthFoxVault.sol:145" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)64_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)188_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)11789_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)11789_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)11795_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)11789_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + }, + "allAddresses": [ + "0xd57c19f20168406d162852515030e00e49bB7781", + "0xcf28acEF84c2279873Fc4bc02029123a3739e60b" + ] + }, + "e2810c87d956a41326a89cb41ca3e96534786393fd9f63b050fc293ee52bce8f": { + "address": "0xFe974c6502E59d760B3a27e6D5a4315DC668d716", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:175" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "1835a32672daa763d92d447cf5eb450cfae3b06b9fa73d08ee4ea6d35947a4a1": { + "address": "0x3BEc3c1cf81A1176c12550B4315bdd53A2B4Fd5D", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:175" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivVault", + "src": "contracts/vaults/ethereum/EthPrivVault.sol:120" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "fcbcf8e057b337dfe10014f3fa9cd62a20003755f328d48a423c8872e8c20ed1": { + "address": "0xD506fE0B3dDF9e685C16E000514a835D3a511b26", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:175" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthBlocklistVault", + "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:115" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "b1e262b3be8e8fc964972e9c48d810a83ee9a5156f1806f16ea45b3f0d0dd876": { + "address": "0x0C2eC14603Ad9c14a820ad0C91122210Ab84A9e5", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "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(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "320fbb484ce92bccaf4ff85a86beeb8da0f5b6d7664e1f6db06fd2df87907dcd": { + "address": "0x60CE7c5547Ada69042Df8aC4f40B74ED0031E90d", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivErc20Vault", + "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:128" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "c3ef2951989f1c1b60d210d887b9f9af92c43cdf79596955e434e2bfb3e94c61": { + "address": "0x028DbA0cA8C761C7831fA0A681b8B61bA04ce939", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthBlocklistErc20Vault", + "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:128" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "c2774cbb16a5c2235092a7c2aed838ebdbf064fb10300823b4fddfa548678550": { + "address": "0xBe89b8a90018f1bD458803e713575287E23CA04a", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14077_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:331" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:228" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:270" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:32" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:296" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:175" + }, + { + "label": "__gap", + "offset": 0, + "slot": "513", + "type": "t_array(t_uint256)50_storage", + "contract": "EthGenesisVault", + "src": "contracts/vaults/ethereum/EthGenesisVault.sol:264" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)105_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)229_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14071_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14077_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12309_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "530b5b57509b99022a4edb5165c3480290bb0d15dff8572473d32ab3a99a5dc3": { + "address": "0x2B3Fd45831BBe53230a5f7E068ca75cd2a8DfaF3", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:173" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "3841f1064bf286d24700aaa0510af6ddc2ac7f2b7508a4829f743b84a6bdb8f3": { + "address": "0xc43A7b16A7a167c0318390Cba16787C11e9e1FD0", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:173" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivVault", + "src": "contracts/vaults/ethereum/EthPrivVault.sol:124" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "c291e7de6aa4ed44b6abd963714442c31d5c6276b4c60e5356941f0d59a1b814": { + "address": "0x3cc1bde89640E0D32b2D2D66D3098d9Bc11b17Ee", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:173" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthBlocklistVault", + "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:124" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "b9b55735d238ae0309e8be4150ed268fa5cccd589d97741fbbc4f343c37b4b24": { + "address": "0xfc81D3369fBEAa6E0926eedA71E5C91724f2c079", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:76" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "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(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "417427cee50fe0558a4226b7ff573a50d4ba39091344ad29a7642437b97b484b": { + "address": "0xD935a9f586dFa83Df20553b40Ce24f3746b258E2", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:76" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivErc20Vault", + "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:132" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "59a5c0fa78da9c59cd2bbb95c024be83447f68cc4419929395ec663916970474": { + "address": "0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:76" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthBlocklistErc20Vault", + "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:137" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "3349c7ddbf2d19e1d6462fb4321bb521c6692293b30d7457d68092f3bf76365a": { + "address": "0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)14418_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:173" + }, + { + "label": "__gap", + "offset": 0, + "slot": "513", + "type": "t_array(t_uint256)50_storage", + "contract": "EthGenesisVault", + "src": "contracts/vaults/ethereum/EthGenesisVault.sol:298" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)14412_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)14418_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)12646_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "b4791db8afac621222d022e3bd4d4f016abfc4d7aca4807fb6174fa42bbceeab": { + "address": "0xeBF52C2d940F46f2dbFB4982447D15cf589711AD", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:164" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "f9daa7652b8e2ae1be69802ce9ab4df0b22668605885c3ce36ae44bd8ac9068f": { + "address": "0x3F2c0a621369fc54f6DeEC6C9534e980fd2E98d5", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:164" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivVault", + "src": "contracts/vaults/ethereum/EthPrivVault.sol:123" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "b884e823d94cb3da62e28a6bdde4ceff771fceac639195abdca4487c4938e570": { + "address": "0x70E1238e3eb4bda45C0E93e114bD5C7d9c512126", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:164" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "513", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "514", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "515", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "565", + "type": "t_array(t_uint256)50_storage", + "contract": "EthBlocklistVault", + "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:123" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "8f6fcae43d0254af70196968374a7c5c74f991dfae51ff576c497844658c73de": { + "address": "0xE51eE4200510498d5964627B25FE7D4685CB858c", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:76" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "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(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "9f4b1e57e47e2924962c6d5802991805bcff854ae0213a0eb411cf667e0906d9": { + "address": "0x42427acFf6DdC93f73Fcb53d1a03AA26A292bA1A", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:76" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" + }, + { + "label": "whitelister", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:17" + }, + { + "label": "whitelistedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultWhitelist", + "src": "contracts/vaults/modules/VaultWhitelist.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthPrivErc20Vault", + "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:131" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "c7313f2b7fa8046ce5816b81d7d3f1ebb209fdba5a1a1fa567af3d09eed60dcb": { + "address": "0xCd191DfDF52ae7aa2B1AD7B4a6A9D4d4FFB837B5", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "name", + "offset": 0, + "slot": "0", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:21" + }, + { + "label": "symbol", + "offset": 0, + "slot": "1", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:24" + }, + { + "label": "allowance", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:30" + }, + { + "label": "nonces", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:33" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "4", + "type": "t_bytes32", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20Upgradeable", + "src": "contracts/base/ERC20Upgradeable.sol:173" + }, + { + "label": "admin", + "offset": 0, + "slot": "55", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "106", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "156", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "156", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "157", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "207", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "208", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "209", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "210", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "211", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "212", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "213", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "214", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "215", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "263", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "264", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "265", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "266", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "267", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "316", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "366", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "417", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "418", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "468", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultToken", + "src": "contracts/vaults/modules/VaultToken.sol:76" + }, + { + "label": "__gap", + "offset": 0, + "slot": "518", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "568", + "type": "t_array(t_uint256)50_storage", + "contract": "EthErc20Vault", + "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" + }, + { + "label": "blocklistManager", + "offset": 0, + "slot": "618", + "type": "t_address", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:17" + }, + { + "label": "blockedAccounts", + "offset": 0, + "slot": "619", + "type": "t_mapping(t_address,t_bool)", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "620", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultBlocklist", + "src": "contracts/vaults/modules/VaultBlocklist.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "670", + "type": "t_array(t_uint256)50_storage", + "contract": "EthBlocklistErc20Vault", + "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:136" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "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(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "779ee9708dbbc090754973d832c1d5c372f65cf7d46993746ba6208fb8013ad0": { + "address": "0x8f347eb308707DC1FA1acCF3ea889CF554b6B8A5", + "layout": { + "solcVersion": "0.8.22", + "storage": [ + { + "label": "admin", + "offset": 0, + "slot": "0", + "type": "t_address", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:16" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultAdmin", + "src": "contracts/vaults/modules/VaultAdmin.sol:49" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultVersion", + "src": "contracts/vaults/modules/VaultVersion.sol:66" + }, + { + "label": "feeRecipient", + "offset": 0, + "slot": "101", + "type": "t_address", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:21" + }, + { + "label": "feePercent", + "offset": 20, + "slot": "101", + "type": "t_uint16", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultFee", + "src": "contracts/vaults/modules/VaultFee.sol:62" + }, + { + "label": "_totalShares", + "offset": 0, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:23" + }, + { + "label": "_totalAssets", + "offset": 16, + "slot": "152", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:24" + }, + { + "label": "queuedShares", + "offset": 0, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:27" + }, + { + "label": "_unclaimedAssets", + "offset": 16, + "slot": "153", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:28" + }, + { + "label": "_exitQueue", + "offset": 0, + "slot": "154", + "type": "t_struct(History)17288_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:29" + }, + { + "label": "_exitRequests", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:31" + }, + { + "label": "_balances", + "offset": 0, + "slot": "156", + "type": "t_mapping(t_address,t_uint256)", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:32" + }, + { + "label": "_capacity", + "offset": 0, + "slot": "157", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:34" + }, + { + "label": "totalExitingAssets", + "offset": 0, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:37" + }, + { + "label": "_totalExitingTickets", + "offset": 16, + "slot": "158", + "type": "t_uint128", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:38" + }, + { + "label": "_totalExitedTickets", + "offset": 0, + "slot": "159", + "type": "t_uint256", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:39" + }, + { + "label": "__gap", + "offset": 0, + "slot": "160", + "type": "t_array(t_uint256)48_storage", + "contract": "VaultState", + "src": "contracts/vaults/modules/VaultState.sol:353" + }, + { + "label": "_validatorsRoot", + "offset": 0, + "slot": "208", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:39" + }, + { + "label": "_validatorIndex", + "offset": 0, + "slot": "209", + "type": "t_uint256", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:42" + }, + { + "label": "_validatorsManager", + "offset": 0, + "slot": "210", + "type": "t_address", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:44" + }, + { + "label": "_initialDomainSeparator", + "offset": 0, + "slot": "211", + "type": "t_bytes32", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "212", + "type": "t_array(t_uint256)49_storage", + "contract": "VaultValidators", + "src": "contracts/vaults/modules/VaultValidators.sol:239" + }, + { + "label": "__gap", + "offset": 0, + "slot": "261", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEnterExit", + "src": "contracts/vaults/modules/VaultEnterExit.sol:219" + }, + { + "label": "_positions", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "312", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultOsToken", + "src": "contracts/vaults/modules/VaultOsToken.sol:375" + }, + { + "label": "_ownMevEscrow", + "offset": 0, + "slot": "362", + "type": "t_address", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:20" + }, + { + "label": "__gap", + "offset": 0, + "slot": "363", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultMev", + "src": "contracts/vaults/modules/VaultMev.sol:77" + }, + { + "label": "__gap", + "offset": 0, + "slot": "413", + "type": "t_array(t_uint256)50_storage", + "contract": "VaultEthStaking", + "src": "contracts/vaults/modules/VaultEthStaking.sol:152" + }, + { + "label": "__gap", + "offset": 0, + "slot": "463", + "type": "t_array(t_uint256)50_storage", + "contract": "EthVault", + "src": "contracts/vaults/ethereum/EthVault.sol:164" + }, + { + "label": "__gap", + "offset": 0, + "slot": "513", + "type": "t_array(t_uint256)50_storage", + "contract": "EthGenesisVault", + "src": "contracts/vaults/ethereum/EthGenesisVault.sol:297" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)128_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(ReentrancyGuardStorage)276_storage": { + "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", + "members": [ + { + "label": "_status", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { + "label": "struct ExitQueue.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { + "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)17282_storage": { + "label": "struct ExitQueue.Checkpoint", + "members": [ + { + "label": "totalTickets", + "type": "t_uint160", + "offset": 0, + "slot": "0" + }, + { + "label": "exitedAssets", + "type": "t_uint96", + "offset": 20, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(History)17288_storage": { + "label": "struct ExitQueue.History", + "members": [ + { + "label": "checkpoints", + "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(OsTokenPosition)15516_storage": { + "label": "struct IVaultOsToken.OsTokenPosition", + "members": [ + { + "label": "shares", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "cumulativeFeePerShare", + "type": "t_uint128", + "offset": 16, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint160": { + "label": "uint160", + "numberOfBytes": "20" + }, + "t_uint96": { + "label": "uint96", + "numberOfBytes": "12" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.ReentrancyGuard": [ + { + "contract": "ReentrancyGuardUpgradeable", + "label": "_status", + "type": "t_uint256", + "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + } + } +} diff --git a/abi/IERC1363.json b/abi/IERC1363.json new file mode 100644 index 00000000..af4691b3 --- /dev/null +++ b/abi/IERC1363.json @@ -0,0 +1,373 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approveAndCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "approveAndCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferAndCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "transferAndCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "transferFromAndCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFromAndCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/IERC1967.json b/abi/IERC1967.json new file mode 100644 index 00000000..0855e48e --- /dev/null +++ b/abi/IERC1967.json @@ -0,0 +1,47 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + } +] diff --git a/abi/IRewardSplitter.json b/abi/IRewardSplitter.json index 5d6eb894..ed9cb858 100644 --- a/abi/IRewardSplitter.json +++ b/abi/IRewardSplitter.json @@ -14,6 +14,75 @@ "name": "NotHarvested", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "ClaimOnBehalfUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "onBehalf", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "positionTicket", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ExitQueueEnteredOnBehalf", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "onBehalf", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "positionTicket", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ExitedAssetsClaimedOnBehalf", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -103,6 +172,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "positionTicket", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exitQueueIndex", + "type": "uint256" + } + ], + "name": "claimExitedAssetsOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -163,6 +255,49 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "rewards", + "type": "uint256" + }, + { + "internalType": "address", + "name": "onBehalf", + "type": "address" + } + ], + "name": "enterExitQueueOnBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "positionTicket", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "exitPosition", + "type": "uint256" + } + ], + "name": "exitPositions", + "outputs": [ + { + "internalType": "address", + "name": "onBehalf", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -183,11 +318,6 @@ }, { "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, { "internalType": "address", "name": "_vault", @@ -199,6 +329,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "isClaimOnBehalfEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -237,6 +380,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "setClaimOnBehalf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -273,7 +429,7 @@ "type": "uint128" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -286,7 +442,7 @@ "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -334,7 +490,7 @@ "type": "address" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" } ] diff --git a/deployments/holesky-upgrade-v2-tx.json b/deployments/holesky-upgrade-v2-tx.json deleted file mode 100644 index c31aac6c..00000000 --- a/deployments/holesky-upgrade-v2-tx.json +++ /dev/null @@ -1,186 +0,0 @@ -[ - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000001428bb71261f01bbc03ce4ec7ceea674f94b5f18", - "method": "removeFactory(address)", - "params": ["0x1428BB71261f01BbC03ce4eC7cEEA674f94b5F18"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000a1424bd00e6940a58b1232ad4160a77dd0ac3099", - "method": "addFactory(address)", - "params": ["0xA1424Bd00e6940A58B1232ad4160A77dD0AC3099"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000355ab27bc05f6f54632cfa5a7168219df72ae727", - "method": "addVaultImpl(address)", - "params": ["0x355AB27BC05f6f54632cFA5A7168219DF72ae727"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000009741f8e49ffa322714511b5d17bd052698eafa43", - "method": "removeFactory(address)", - "params": ["0x9741f8e49fFa322714511b5D17bD052698eAFA43"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000008023518b2192fb5384dadc596765b3dd1cdfe471", - "method": "addFactory(address)", - "params": ["0x8023518b2192FB5384DAdc596765B3dD1cdFe471"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000ebcbadedbd0dd909b87bbac44e522ad00e37f075", - "method": "addVaultImpl(address)", - "params": ["0xEBCBADedbd0Dd909B87BBAC44e522aD00E37F075"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000090a9428b8c58ca80b28aaf46b936d42e87797449", - "method": "addFactory(address)", - "params": ["0x90a9428b8c58cA80B28aAF46B936D42e87797449"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000e00512e3f38ec4f4e79152474da215506b5b1902", - "method": "addVaultImpl(address)", - "params": ["0xE00512e3F38Ec4f4e79152474DA215506b5b1902"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000004c1140f4a5e3dd459de642a46bd1df6fbe287e1b", - "method": "removeFactory(address)", - "params": ["0x4C1140F4A5E3DD459De642A46bd1df6FBe287e1B"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000c6e7d05b3f6e73e3a86c6deae0da1fce993cf833", - "method": "addFactory(address)", - "params": ["0xc6e7d05B3F6e73E3A86C6deAE0Da1fce993cF833"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000849da65afed8483152f8baa75f776c6f2c02e540", - "method": "addVaultImpl(address)", - "params": ["0x849DA65aFEd8483152f8Baa75F776c6f2C02E540"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000930a2d0adebf4e69bb929f6456c3d4bcabf52796", - "method": "removeFactory(address)", - "params": ["0x930A2D0ADEbF4E69Bb929F6456C3D4bcabf52796"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000481f28c0d733614af87897e43d0d52c451799592", - "method": "addFactory(address)", - "params": ["0x481f28C0D733614aF87897E43d0D52C451799592"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000f0c1670364d4b5c4e9dc8062cdd45068d9c678d6", - "method": "addVaultImpl(address)", - "params": ["0xF0C1670364d4b5c4e9dc8062cDd45068D9c678d6"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000082fe8c78cae0013471179e76224ef89941baaa75", - "method": "addFactory(address)", - "params": ["0x82FE8C78CaE0013471179e76224ef89941bAaa75"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000001d34aee72325f1d4a748f13c2169404523ecee0", - "method": "addVaultImpl(address)", - "params": ["0x01d34aeE72325F1d4A748f13C2169404523eCEE0"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000006415926885a628dcc5960c8870562e728e94dd7e", - "method": "addVaultImpl(address)", - "params": ["0x6415926885A628DCc5960C8870562e728E94Dd7E"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000003f6e93ca5c426907aa8c66f4202d5fed4e86804a", - "method": "addFactory(address)", - "params": ["0x3F6E93ca5c426907aA8C66f4202d5fEd4e86804a"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000038a6c11417bbf584bdc2c18a1e83bcd7e906bb19", - "method": "addFactory(address)", - "params": ["0x38a6C11417bBf584bDC2C18a1E83bCD7e906BB19"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000003a30416a16b992ff65722e7d659668db36d678b5", - "method": "addFactory(address)", - "params": ["0x3a30416A16B992ff65722e7D659668DB36d678b5"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000db79701d6a4d6476bfe2d59afb0d675f97a6f67d", - "method": "addFactory(address)", - "params": ["0xdB79701D6a4d6476Bfe2d59Afb0d675F97A6f67D"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000470e61817be4d064acd9422ab6bfc23d5101f84e", - "method": "addFactory(address)", - "params": ["0x470e61817bE4d064aCd9422aB6BfC23D5101F84E"] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000cce89ab06221c533190e0001f6ad1bad58888dc2", - "method": "addFactory(address)", - "params": ["0xcCE89aB06221c533190E0001F6ad1BAD58888DC2"] - } -] diff --git a/deployments/holesky-upgrade-v3-tx.json b/deployments/holesky-upgrade-v3-tx.json deleted file mode 100644 index 6b9ac58f..00000000 --- a/deployments/holesky-upgrade-v3-tx.json +++ /dev/null @@ -1,213 +0,0 @@ -[ - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x256b5a02000000000000000000000000807305c086a99cbdbff07cb4256ce556d9d6f0af", - "method": "addVault(address)", - "params": [ - "0x807305c086A99cbDBff07cB4256cE556d9d6F0af" - ] - }, - { - "to": "0xF603c5A3F774F05d4D848A9bB139809790890864", - "operation": "0", - "value": "0.0", - "data": "0xe0dba60f0000000000000000000000003e30370cabd4b4d95be17706d840ff9de1addb670000000000000000000000000000000000000000000000000000000000000001", - "method": "setController(address,bool)", - "params": [ - "0x3e30370cabD4B4D95Be17706D840FF9de1ADdb67", - true - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000215f4c69c3d1461c7aa38c9c73c27e10cfb0eee4", - "method": "removeFactory(address)", - "params": [ - "0xA1424Bd00e6940A58B1232ad4160A77dD0AC3099" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000003acdbdbf0459d376df9378c02af50c83dc7646e9", - "method": "addFactory(address)", - "params": [ - "0x3acDBdbf0459d376dF9378c02Af50c83dc7646e9" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000002a0335fb13cbf86a76a7f9d9d038389788667960", - "method": "addVaultImpl(address)", - "params": [ - "0x2a0335fb13Cbf86A76A7f9D9d038389788667960" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000edebe792c6190be612cbe97f628137faa8c36ee5", - "method": "removeFactory(address)", - "params": [ - "0x8023518b2192FB5384DAdc596765B3dD1cdFe471" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000453056f0bc4631abb15eec656139f88067668e3e", - "method": "addFactory(address)", - "params": [ - "0x453056f0bc4631abB15eEC656139f88067668E3E" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000008750594b33516232e751c8b9c350a660cd5f1bb8", - "method": "addVaultImpl(address)", - "params": [ - "0x8750594B33516232e751C8B9C350a660cD5f1BB8" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000005fcd8bb2e3dde5809b2106039b741c041bd49e4e", - "method": "removeFactory(address)", - "params": [ - "0x90a9428b8c58cA80B28aAF46B936D42e87797449" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000000b4f6bfb694790051e0203db83edbb5888099556", - "method": "addFactory(address)", - "params": [ - "0x0b4F6bFB694790051E0203Db83edbB5888099556" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000005518052f2d898f062ee59964004a560f24e2ee7d", - "method": "addVaultImpl(address)", - "params": [ - "0x5518052f2d898f062ee59964004A560F24E2eE7d" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000439b60d3c886e711dad30cf23a2bbd5388febcd9", - "method": "removeFactory(address)", - "params": [ - "0xc6e7d05B3F6e73E3A86C6deAE0Da1fce993cF833" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000007aa02b4cf39f98ffeb324325775f840d18549733", - "method": "addFactory(address)", - "params": [ - "0x7aa02B4Cf39f98FfEB324325775f840d18549733" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000005f31ed13ebf81b67a9f9498f3d1d2da553058988", - "method": "addVaultImpl(address)", - "params": [ - "0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000ac9125646185cb58e86e77d5f402efa3fafafc84", - "method": "removeFactory(address)", - "params": [ - "0x481f28C0D733614aF87897E43d0D52C451799592" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000decb606ee9140f229df78f9e40041ead61610f8f", - "method": "addFactory(address)", - "params": [ - "0xDecb606ee9140f229Df78F9E40041EAD61610F8f" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000b48e508a78caef2325f8b813c153e81bc3ed44f4", - "method": "addVaultImpl(address)", - "params": [ - "0xB48E508a78CAEF2325f8B813c153E81bc3Ed44f4" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000ebe12d858e55ddc5fc5a8153dc3e117824fbf5d2", - "method": "removeFactory(address)", - "params": [ - "0x82FE8C78CaE0013471179e76224ef89941bAaa75" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000d19e4b1d680a6aa672b08ebf483381bc0c9c8478", - "method": "addFactory(address)", - "params": [ - "0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000135f45e0179dd928e73422b40bdc6c5d7047a035", - "method": "addVaultImpl(address)", - "params": [ - "0x135f45e0179dd928E73422B40Bdc6C5d7047a035" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000007e5198df09fed891e7aecd623cd2231443ceb5d5", - "method": "addVaultImpl(address)", - "params": [ - "0x7E5198DF09fED891e7AecD623cD2231443cEb5d5" - ] - } -] \ No newline at end of file diff --git a/deployments/holesky-vault-v2-upgrades.json b/deployments/holesky-vault-v2-upgrades.json deleted file mode 100644 index e699eabd..00000000 --- a/deployments/holesky-vault-v2-upgrades.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "2": "0x355AB27BC05f6f54632cFA5A7168219DF72ae727" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "2": "0xEBCBADedbd0Dd909B87BBAC44e522aD00E37F075" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "2": "0xE00512e3F38Ec4f4e79152474DA215506b5b1902" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "2": "0x849DA65aFEd8483152f8Baa75F776c6f2C02E540" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "2": "0xF0C1670364d4b5c4e9dc8062cDd45068D9c678d6" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "2": "0x01d34aeE72325F1d4A748f13C2169404523eCEE0" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "2": "0x35dC754f157b32Ba0941ffCD89d16d3D0B2cA6CF" - }, - "0x43d6c07ac63953f42a28f0366affe9895fd54f84336314dd012087bd0941df67": { - "2": "0x288F9dc773Dd0E3DC94F975BD24e5018FFc55293" - }, - "0x333122211e64a98ebf9b5890e3a33144b1208484d235be41b9d0a827eb1b5b0c": { - "2": "0x89EA6d8000f7925c4765cC1374FAD4423A557eB5" - }, - "0x903c7cfddba46ee63384d0bf7016d55c117fc01332779257355a1400c68e97d1": { - "2": "0xA60Cc45A4841c59a3de35a46289DFaEed49f547E" - }, - "0x778168b2049c66a50853dfa28c8d05dfb083907876871d6640cd612be7e580f2": { - "2": "0x9A6102b03be3E64c98eB80Aa9D3187cAA17755f7" - }, - "0x737a47bb3e695a159ef397f75d47c2ca71c770e380ac29b104d3b82ee61be3c8": { - "2": "0xA0328cbb10F501755d841a8a4AD2a3Ac439103e8" - }, - "0x813d21398e0f42fde0737b550f7475616bb950f32cd3f6012ad8b7d81b6c415f": { - "2": "0x3919E9B0E3912eE7b72A1f1AF97d07f6dCFEFFea" - } -} diff --git a/deployments/hoodi-upgrade-v2-tx.json b/deployments/hoodi-upgrade-v2-tx.json new file mode 100644 index 00000000..9aa4fbf4 --- /dev/null +++ b/deployments/hoodi-upgrade-v2-tx.json @@ -0,0 +1,172 @@ +[ + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f0000000000000000000000002a49951faffcfe3bf5247834ead8a5df8638ad9e", + "method": "removeFactory(address)", + "params": [ + "0x2A49951FafFcfe3Bf5247834eAd8A5dF8638Ad9e" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec5000000000000000000000000f0f07383f621370eb59a794f36b7d80063d06147", + "method": "addFactory(address)", + "params": [ + "0xf0F07383F621370Eb59A794f36b7D80063d06147" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000fe974c6502e59d760b3a27e6d5a4315dc668d716", + "method": "addVaultImpl(address)", + "params": [ + "0xFe974c6502E59d760B3a27e6D5a4315DC668d716" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f00000000000000000000000075cfa03086f4832d7ed238dbba59b1c6cba01cfe", + "method": "removeFactory(address)", + "params": [ + "0x75CFa03086F4832D7eD238dbba59B1c6CBa01CFe" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec50000000000000000000000000f8c209445282d937dac0ea0a6706590250f9afd", + "method": "addFactory(address)", + "params": [ + "0x0F8c209445282d937DaC0eA0a6706590250F9aFD" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000003bec3c1cf81a1176c12550b4315bdd53a2b4fd5d", + "method": "addVaultImpl(address)", + "params": [ + "0x3BEc3c1cf81A1176c12550B4315bdd53A2B4Fd5D" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec5000000000000000000000000b4fea836cdd93ac900100bb6462fe73872e5b524", + "method": "addFactory(address)", + "params": [ + "0xB4FEA836CDd93Ac900100bB6462fE73872E5B524" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000d506fe0b3ddf9e685c16e000514a835d3a511b26", + "method": "addVaultImpl(address)", + "params": [ + "0xD506fE0B3dDF9e685C16E000514a835D3a511b26" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f000000000000000000000000a321619a6232bdc03ab1a82affb5783518a9f5bb", + "method": "removeFactory(address)", + "params": [ + "0xa321619a6232BdC03Ab1a82aFFb5783518A9f5BB" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec500000000000000000000000068d17efa7cf9e1d121e9ff6138f2336bdb1ccbca", + "method": "addFactory(address)", + "params": [ + "0x68D17eFa7cf9e1d121e9ff6138f2336bDB1CcBcA" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000000c2ec14603ad9c14a820ad0c91122210ab84a9e5", + "method": "addVaultImpl(address)", + "params": [ + "0x0C2eC14603Ad9c14a820ad0C91122210Ab84A9e5" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f000000000000000000000000f9d18fc3d4f917e87400c445429440ca73d970e4", + "method": "removeFactory(address)", + "params": [ + "0xf9D18Fc3D4F917E87400C445429440CA73D970E4" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec5000000000000000000000000ac40b56e7bb98c2be5ee5b3e8b28568b33fa76ce", + "method": "addFactory(address)", + "params": [ + "0xac40b56E7Bb98C2Be5Ee5b3E8B28568b33Fa76CE" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d00000000000000000000000060ce7c5547ada69042df8ac4f40b74ed0031e90d", + "method": "addVaultImpl(address)", + "params": [ + "0x60CE7c5547Ada69042Df8aC4f40B74ED0031E90d" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec500000000000000000000000076747fee60601be298e84a8a3d4d2d0dc82555f4", + "method": "addFactory(address)", + "params": [ + "0x76747FeE60601be298E84A8a3D4D2D0dc82555F4" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000028dba0ca8c761c7831fa0a681b8b61ba04ce939", + "method": "addVaultImpl(address)", + "params": [ + "0x028DbA0cA8C761C7831fA0A681b8B61bA04ce939" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000be89b8a90018f1bd458803e713575287e23ca04a", + "method": "addVaultImpl(address)", + "params": [ + "0xBe89b8a90018f1bD458803e713575287E23CA04a" + ] + } +] \ No newline at end of file diff --git a/deployments/hoodi-upgrade-v3-tx.json b/deployments/hoodi-upgrade-v3-tx.json new file mode 100644 index 00000000..a6f695d2 --- /dev/null +++ b/deployments/hoodi-upgrade-v3-tx.json @@ -0,0 +1,213 @@ +[ + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x256b5a02000000000000000000000000dc1347cc04d4a8945b98a09c3c5585286bba5c2b", + "method": "addVault(address)", + "params": [ + "0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B" + ] + }, + { + "to": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", + "operation": "0", + "value": "0.0", + "data": "0xe0dba60f000000000000000000000000cd5f3c1ba0342e1de907eee09aec52183ef5d99e0000000000000000000000000000000000000000000000000000000000000001", + "method": "setController(address,bool)", + "params": [ + "0xCd5F3C1BA0342e1de907eEE09aeC52183ef5D99e", + true + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f000000000000000000000000f0f07383f621370eb59a794f36b7d80063d06147", + "method": "removeFactory(address)", + "params": [ + "0xf0F07383F621370Eb59A794f36b7D80063d06147" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec5000000000000000000000000508e82b5119ccfb923c387d62d2ae7b56df79906", + "method": "addFactory(address)", + "params": [ + "0x508e82B5119CCfB923C387d62D2Ae7B56Df79906" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000002b3fd45831bbe53230a5f7e068ca75cd2a8dfaf3", + "method": "addVaultImpl(address)", + "params": [ + "0x2B3Fd45831BBe53230a5f7E068ca75cd2a8DfaF3" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f0000000000000000000000000f8c209445282d937dac0ea0a6706590250f9afd", + "method": "removeFactory(address)", + "params": [ + "0x0F8c209445282d937DaC0eA0a6706590250F9aFD" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec50000000000000000000000009115e176c3d034339036194c3eb7014ef04a2e4b", + "method": "addFactory(address)", + "params": [ + "0x9115E176C3d034339036194c3EB7014Ef04A2e4b" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000c43a7b16a7a167c0318390cba16787c11e9e1fd0", + "method": "addVaultImpl(address)", + "params": [ + "0xc43A7b16A7a167c0318390Cba16787C11e9e1FD0" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f000000000000000000000000b4fea836cdd93ac900100bb6462fe73872e5b524", + "method": "removeFactory(address)", + "params": [ + "0xB4FEA836CDd93Ac900100bB6462fE73872E5B524" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec5000000000000000000000000e2121568066c0a9d794bbb95d0ade0ebd81ccaf9", + "method": "addFactory(address)", + "params": [ + "0xE2121568066C0a9d794bbB95D0Ade0ebd81cCaf9" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000003cc1bde89640e0d32b2d2d66d3098d9bc11b17ee", + "method": "addVaultImpl(address)", + "params": [ + "0x3cc1bde89640E0D32b2D2D66D3098d9Bc11b17Ee" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f00000000000000000000000068d17efa7cf9e1d121e9ff6138f2336bdb1ccbca", + "method": "removeFactory(address)", + "params": [ + "0x68D17eFa7cf9e1d121e9ff6138f2336bDB1CcBcA" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec5000000000000000000000000bb1b3e55315967c65133a0e942d8ea7a992af6c7", + "method": "addFactory(address)", + "params": [ + "0xBb1B3E55315967c65133A0e942d8EA7a992aF6C7" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000fc81d3369fbeaa6e0926eeda71e5c91724f2c079", + "method": "addVaultImpl(address)", + "params": [ + "0xfc81D3369fBEAa6E0926eedA71E5C91724f2c079" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f000000000000000000000000ac40b56e7bb98c2be5ee5b3e8b28568b33fa76ce", + "method": "removeFactory(address)", + "params": [ + "0xac40b56E7Bb98C2Be5Ee5b3E8B28568b33Fa76CE" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec500000000000000000000000076d90928645065b4d4212ee62ce1ba8f90718f14", + "method": "addFactory(address)", + "params": [ + "0x76D90928645065b4D4212eE62ce1ba8f90718f14" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000d935a9f586dfa83df20553b40ce24f3746b258e2", + "method": "addVaultImpl(address)", + "params": [ + "0xD935a9f586dFa83Df20553b40Ce24f3746b258E2" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x4b37c73f00000000000000000000000076747fee60601be298e84a8a3d4d2d0dc82555f4", + "method": "removeFactory(address)", + "params": [ + "0x76747FeE60601be298E84A8a3D4D2D0dc82555F4" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0x29ce1ec50000000000000000000000004e3de90882b3d10d067b8954909d4a4b0bb390d0", + "method": "addFactory(address)", + "params": [ + "0x4E3dE90882B3d10D067b8954909D4A4b0Bb390D0" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000001e86e620567bb877f5ed13607a1a7b7dbcb6be66", + "method": "addVaultImpl(address)", + "params": [ + "0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000e14fa9bbdb7813025309f71ddc0fa8faae1b9141", + "method": "addVaultImpl(address)", + "params": [ + "0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141" + ] + } +] \ No newline at end of file diff --git a/deployments/hoodi-upgrade-v4-tx.json b/deployments/hoodi-upgrade-v4-tx.json new file mode 100644 index 00000000..ed8dc2da --- /dev/null +++ b/deployments/hoodi-upgrade-v4-tx.json @@ -0,0 +1,72 @@ +[ + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000ebf52c2d940f46f2dbfb4982447d15cf589711ad", + "method": "addVaultImpl(address)", + "params": [ + "0xeBF52C2d940F46f2dbFB4982447D15cf589711AD" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000003f2c0a621369fc54f6deec6c9534e980fd2e98d5", + "method": "addVaultImpl(address)", + "params": [ + "0x3F2c0a621369fc54f6DeEC6C9534e980fd2E98d5" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d00000000000000000000000070e1238e3eb4bda45c0e93e114bd5c7d9c512126", + "method": "addVaultImpl(address)", + "params": [ + "0x70E1238e3eb4bda45C0E93e114bD5C7d9c512126" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000e51ee4200510498d5964627b25fe7d4685cb858c", + "method": "addVaultImpl(address)", + "params": [ + "0xE51eE4200510498d5964627B25FE7D4685CB858c" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d00000000000000000000000042427acff6ddc93f73fcb53d1a03aa26a292ba1a", + "method": "addVaultImpl(address)", + "params": [ + "0x42427acFf6DdC93f73Fcb53d1a03AA26A292bA1A" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d000000000000000000000000cd191dfdf52ae7aa2b1ad7b4a6a9d4d4ffb837b5", + "method": "addVaultImpl(address)", + "params": [ + "0xCd191DfDF52ae7aa2B1AD7B4a6A9D4d4FFB837B5" + ] + }, + { + "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "operation": "0", + "value": "0.0", + "data": "0xaff7947d0000000000000000000000008f347eb308707dc1fa1accf3ea889cf554b6b8a5", + "method": "addVaultImpl(address)", + "params": [ + "0x8f347eb308707DC1FA1acCF3ea889CF554b6B8A5" + ] + } +] \ No newline at end of file diff --git a/deployments/holesky-vault-v3-upgrades.json b/deployments/hoodi-vault-v2-upgrades.json similarity index 59% rename from deployments/holesky-vault-v3-upgrades.json rename to deployments/hoodi-vault-v2-upgrades.json index 9c41212e..82c4dd78 100644 --- a/deployments/holesky-vault-v3-upgrades.json +++ b/deployments/hoodi-vault-v2-upgrades.json @@ -1,23 +1,23 @@ { "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "3": "0x2a0335fb13Cbf86A76A7f9D9d038389788667960" + "2": "0xFe974c6502E59d760B3a27e6D5a4315DC668d716" }, "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "3": "0x8750594B33516232e751C8B9C350a660cD5f1BB8" + "2": "0x3BEc3c1cf81A1176c12550B4315bdd53A2B4Fd5D" }, "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "3": "0x5518052f2d898f062ee59964004A560F24E2eE7d" + "2": "0xD506fE0B3dDF9e685C16E000514a835D3a511b26" }, "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "3": "0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988" + "2": "0x0C2eC14603Ad9c14a820ad0C91122210Ab84A9e5" }, "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "3": "0xB48E508a78CAEF2325f8B813c153E81bc3Ed44f4" + "2": "0x60CE7c5547Ada69042Df8aC4f40B74ED0031E90d" }, "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "3": "0x135f45e0179dd928E73422B40Bdc6C5d7047a035" + "2": "0x028DbA0cA8C761C7831fA0A681b8B61bA04ce939" }, "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "3": "0x7E5198DF09fED891e7AecD623cD2231443cEb5d5" + "2": "0xBe89b8a90018f1bD458803e713575287E23CA04a" } } \ No newline at end of file diff --git a/deployments/hoodi-vault-v3-upgrades.json b/deployments/hoodi-vault-v3-upgrades.json new file mode 100644 index 00000000..f4067ab3 --- /dev/null +++ b/deployments/hoodi-vault-v3-upgrades.json @@ -0,0 +1,23 @@ +{ + "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { + "3": "0x2B3Fd45831BBe53230a5f7E068ca75cd2a8DfaF3" + }, + "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { + "3": "0xc43A7b16A7a167c0318390Cba16787C11e9e1FD0" + }, + "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { + "3": "0x3cc1bde89640E0D32b2D2D66D3098d9Bc11b17Ee" + }, + "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { + "3": "0xfc81D3369fBEAa6E0926eedA71E5C91724f2c079" + }, + "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { + "3": "0xD935a9f586dFa83Df20553b40Ce24f3746b258E2" + }, + "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { + "3": "0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66" + }, + "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { + "3": "0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141" + } +} \ No newline at end of file diff --git a/deployments/hoodi-vault-v4-upgrades.json b/deployments/hoodi-vault-v4-upgrades.json new file mode 100644 index 00000000..44390d35 --- /dev/null +++ b/deployments/hoodi-vault-v4-upgrades.json @@ -0,0 +1,23 @@ +{ + "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { + "4": "0xeBF52C2d940F46f2dbFB4982447D15cf589711AD" + }, + "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { + "4": "0x3F2c0a621369fc54f6DeEC6C9534e980fd2E98d5" + }, + "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { + "4": "0x70E1238e3eb4bda45C0E93e114bD5C7d9c512126" + }, + "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { + "4": "0xE51eE4200510498d5964627B25FE7D4685CB858c" + }, + "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { + "4": "0x42427acFf6DdC93f73Fcb53d1a03AA26A292bA1A" + }, + "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { + "4": "0xCd191DfDF52ae7aa2B1AD7B4a6A9D4d4FFB837B5" + }, + "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { + "4": "0x8f347eb308707DC1FA1acCF3ea889CF554b6B8A5" + } +} \ No newline at end of file diff --git a/deployments/hoodi.json b/deployments/hoodi.json new file mode 100644 index 00000000..060bd073 --- /dev/null +++ b/deployments/hoodi.json @@ -0,0 +1,25 @@ +{ + "VaultsRegistry": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "Keeper": "0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f", + "DepositDataRegistry": "0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487", + "EthValidatorsChecker": "0xB790391ee99b9193Ebb80022bf127d24Bac586c4", + "EthGenesisVault": "0xba447498DC4c169f2b4f427B2c4D532320457E89", + "EthFoxVault": "0x468FD65EfA48650F660456a71DC5be32D27D0B46", + "EthVaultFactory": "0x508e82B5119CCfB923C387d62D2Ae7B56Df79906", + "EthPrivVaultFactory": "0x9115E176C3d034339036194c3EB7014Ef04A2e4b", + "EthBlocklistVaultFactory": "0xE2121568066C0a9d794bbB95D0Ade0ebd81cCaf9", + "EthErc20VaultFactory": "0xBb1B3E55315967c65133A0e942d8EA7a992aF6C7", + "EthPrivErc20VaultFactory": "0x76D90928645065b4D4212eE62ce1ba8f90718f14", + "EthBlocklistErc20VaultFactory": "0x4E3dE90882B3d10D067b8954909D4A4b0Bb390D0", + "SharedMevEscrow": "0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd", + "OsToken": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", + "OsTokenConfig": "0x5b817621EBE00622b9a71b53c942b392751c8197", + "OsTokenVaultController": "0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1", + "EthOsTokenVaultEscrow": "0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B", + "OsTokenFlashLoans": "0xCd5F3C1BA0342e1de907eEE09aeC52183ef5D99e", + "PriceFeed": "0xe8a222D887b468a71Ee8a27df4fa3b886A4B7BA1", + "RewardSplitterFactory": "0x80353898B72417AC5701a9809A9eF63F691BdE86", + "CumulativeMerkleDrop": "0xA3bdb3a57626900E4Dd9cC1C2c07bA60F4A44Fbc", + "EthFoxVault1": "0xFb534BB912Eb83b7b629329195b8DF798Ea325b2", + "EthFoxVault2": "0x468FD65EfA48650F660456a71DC5be32D27D0B46" +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 6b017d8a..b93df658 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -73,7 +73,7 @@ const config: HardhatUserConfig = { ], }, networks: { - holesky: getCommonNetworkConfig(Networks.holesky), + hoodi: getCommonNetworkConfig(Networks.hoodi), mainnet: getCommonNetworkConfig(Networks.mainnet), chiado: getCommonNetworkConfig(Networks.chiado), gnosis: getCommonNetworkConfig(Networks.gnosis), @@ -113,11 +113,11 @@ const config: HardhatUserConfig = { apiKey: BLOCK_EXPLORER_KEY, customChains: [ { - network: 'holesky', - chainId: 17000, + network: 'hoodi', + chainId: 560048, urls: { - apiURL: 'https://api-holesky.etherscan.io/api', - browserURL: 'https://holesky.etherscan.io', + apiURL: 'https://api-hoodi.etherscan.io/api', + browserURL: 'https://hoodi.etherscan.io', }, }, ], diff --git a/helpers/constants.ts b/helpers/constants.ts index 83d66c5b..b4f1afc0 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -5,12 +5,12 @@ import { MAX_UINT128, MAX_UINT256 } from '../test/shared/constants' export const NETWORKS: { [network in Networks]: NetworkConfig } = { - [Networks.holesky]: { - url: process.env.HOLESKY_RPC_URL || '', - chainId: 17000, + [Networks.hoodi]: { + url: process.env.HOODI_RPC_URL || '', + chainId: 560048, governor: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - validatorsRegistry: '0x4242424242424242424242424242424242424242', + validatorsRegistry: '0x00000000219ab540356cBB839Cbe05303d7705Fa', securityDeposit: 1000000000n, // 1 gwei exitedAssetsClaimDelay: 24 * 60 * 60, // 24 hours @@ -32,7 +32,7 @@ export const NETWORKS: { validatorsMinOracles: 6, rewardsDelay: 12 * 60 * 60, // 12 hours maxAvgRewardPerSecond: 6341958397n, // 20% APY - oraclesConfigIpfsHash: 'QmPpm82rEJTfgw34noJKugYovHSg7BFdWHWzUV5eNC91Zs', + oraclesConfigIpfsHash: 'Qmb1vAihRCDuEkhe22RL2FkW19MZ2jXKLERuFLwdXvWdQC', // OsToken treasury: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', @@ -48,7 +48,7 @@ export const NETWORKS: { // OsTokenVaultEscrow osTokenVaultEscrow: { - authenticator: '0x4abB9BBb82922A6893A5d6890cd2eE94610BEc48', + authenticator: '0x4a745DFF39bBEa970Da28DBA2ba94DB81938AC39', liqThresholdPercent: parseEther('0.99994'), // 99.994% liqBonusPercent: parseEther('1.000027'), // 0.0027% }, @@ -56,8 +56,8 @@ export const NETWORKS: { // EthGenesisVault genesisVault: { admin: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - poolEscrow: '0xA9f21D016E2846BC9Be972Cf45d9e410283c971e', - rewardToken: '0x2ee2E20702B5881a1171c5dbEd01C3d1e49Bf632', + poolEscrow: '0x291Fa5849215847081B475450cBE5De46CfD4fAE', + rewardToken: '0x75c57bd50A3EB7291Da3429956D3566E0153A38f', capacity: parseEther('1000000'), // 1m ETH feePercent: 500, // 5% }, diff --git a/helpers/types.ts b/helpers/types.ts index 1ecacc30..e073d922 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -2,7 +2,7 @@ export type ThenArg = T extends PromiseLike ? U : T export enum Networks { mainnet = 'mainnet', - holesky = 'holesky', + hoodi = 'hoodi', chiado = 'chiado', gnosis = 'gnosis', } diff --git a/package.json b/package.json index 1a6e2848..7df797c8 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,10 @@ "coverage": "COVERAGE=true npm run compile && COVERAGE=true hardhat coverage", "precommit": "lint-staged", "node": "hardhat node", - "full-deploy:holesky": "hardhat eth-full-deploy --network holesky", + "full-deploy:hoodi": "hardhat eth-full-deploy --network hoodi", "full-deploy:mainnet": "hardhat eth-full-deploy --network mainnet", - "upgrade:holesky": "hardhat eth-upgrade --network holesky", + "upgrade:hoodi": "hardhat eth-upgrade --network hoodi", + "execute-txs:hoodi": "hardhat execute-txs --network hoodi", "upgrade:mainnet": "hardhat eth-upgrade --network mainnet", "upgrade:chiado": "hardhat gno-upgrade --network chiado", "upgrade:gnosis": "hardhat gno-upgrade --network gnosis", diff --git a/tasks/eth-full-deploy-local.ts b/tasks/eth-full-deploy-local.ts index fb9ac00a..597a7522 100644 --- a/tasks/eth-full-deploy-local.ts +++ b/tasks/eth-full-deploy-local.ts @@ -13,7 +13,7 @@ task('eth-full-deploy-local', 'deploys StakeWise V3 for Ethereum to local networ async (taskArgs, hre) => { const ethers = hre.ethers const networkName = hre.network.name - const networkConfig: NetworkConfig = NETWORKS[Networks.holesky] + const networkConfig: NetworkConfig = NETWORKS[Networks.hoodi] const accounts = await ethers.getSigners() const deployer = accounts[0] const governor = accounts[0] From 77bbc2507f1d5f00eaf81b0172cc9a6f16c8c69b Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Tue, 8 Apr 2025 22:50:57 +0300 Subject: [PATCH 04/15] Pectra support (#104) * forge install: openzeppelin-foundry-upgrades v0.4.0 * forge install: openzeppelin-contracts-upgradeable v5.2.0 * Implement changes for pectra support * Add max effective balance check * Fix deposit amount for validators * Add consolidations checker, GnoDaiDistributor * forge install: murky v0.1.0 * WIP * Remove murky * Revert DepositDataRegistry removal, keep backward comp * Fix validator register event emit * WIP * Fix stack too deep * Fix system contract calls * Add snapshots for VaultGnoStaking * Add upgrade and deploy tests * Add upgrade, deploy tests * Add GnoBlocklistVault and GnoErc20Vault tests * Add more tests to GnoErc20Vault * Add upgrade tests to gno vaults * Remove GnoErc20Vault js tests * Remove GnoVault register * Migrate gno genesis vault tests to foundry * Migrate gno priv, priv erc20 vault tests to foundry * Add GNoVault tests * Migrate GnoOsTokenVaultEscrow to foundry * Add EthHelpers * Add DepositDataRegistry.t.sol * Implement test_registerValidator_succeedsWith0x01Validator * Implement DepositDataRegistry tests for single validator * Implement test_registerValidators_successWith0x01Validators * Implement test_registerValidators_successWith0x02Validators * Fix USE_FORK_VAULTS env * Add deposit data registry migrate tests * Add test/EthBlocklistErc20Vault.t.sol * Add EthBlocklistVault.t.sol * add EthErc20Vault tests * Add EthFoxVault tests * Add EthGenesisVault tests * Add EthPrivVault tests * Add EthPrivErc20Vault tests * Add EthVault tests * Add VaultAdmin tests * Add VaultEnterExit tests * Add more VaultEnterExit tests * Add VaultFee tests * Add VaultEthStaking tests * Add VaultOsToken mint tests * Add VaultOsToken burn tests * Add VaultOsToken redeem tests * Add osToken mint event checks * Add event checks * Add liquidation tests * Add event checks to osToken liquidation tests * Add tests for transferOsTokenPositionToEscrow * Add tests for migrating gno vault from v2 to v3 * Add VaultState tests * Extent VaultState tests * Add VaultToken tests * Add VaultVersion tests * Add VaultValidators tests for registering validator * Add fund validators tests * Add withdraw validator tests * Add consolidation tests * Improve consolidations * Add VaultsRegistry tests * Add tests for Consolidations checker, keeper, mev escrows * Add KeeperValidators tests * Add PriceFeed and KeeperValidators tests * Add EthOsTokenVaultEscrow tests * Add EthOsTokenVaultEscrow tests * Add register function tests in EthOsTokenVaultEscrow * Add processExitedAssets tests for EthOsTokenVaultEscrow * Add claimExitedAssets tests for EthOsTokenVaultEscrow * Add test_liquidateOsToken_success * Add redeem and liquidation tests for OsTokenVaultEscrow * Add authenticator and updateLiqConfig tests * Add flashloans tests * Add OsTokenConfig tests * Add OsTokenFlashLoans tests * Add OsToken tests * Add tests for EthValidatorsChecker * Add tests for EthValidatorsChecker * Add Multicall and RewardSplitter tests * Remove unused mocks --- .gitmodules | 6 + abi/Errors.json | 10 + abi/IConsolidationsChecker.json | 103 ++ abi/IEthBlocklistErc20Vault.json | 243 +++ abi/IEthBlocklistVault.json | 243 +++ abi/IEthErc20Vault.json | 243 +++ abi/IEthFoxVault.json | 243 +++ abi/IEthGenesisVault.json | 250 ++- abi/IEthPrivErc20Vault.json | 243 +++ abi/IEthPrivVault.json | 243 +++ abi/IEthVault.json | 243 +++ abi/IGnoBlocklistErc20Vault.json | 250 ++- abi/IGnoBlocklistVault.json | 250 ++- abi/IGnoDaiDistributor.json | 28 + abi/IGnoErc20Vault.json | 250 ++- abi/IGnoGenesisVault.json | 257 ++- abi/IGnoPrivErc20Vault.json | 250 ++- abi/IGnoPrivVault.json | 250 ++- abi/IGnoVault.json | 250 ++- abi/IMerkleDistributor.json | 61 + abi/ISavingsXDaiAdapter.json | 21 + abi/IVaultAdmin.json | 32 + abi/IVaultBlocklist.json | 32 + abi/IVaultEnterExit.json | 64 + abi/IVaultEthStaking.json | 243 +++ abi/IVaultFee.json | 64 + abi/IVaultGnoStaking.json | 250 ++- abi/IVaultMev.json | 64 + abi/IVaultOsToken.json | 64 + abi/IVaultState.json | 64 + abi/IVaultToken.json | 64 + abi/IVaultValidators.json | 243 +++ abi/IVaultVersion.json | 32 + abi/IVaultWhitelist.json | 32 + abi/IXdaiExchange.json | 160 -- .../interfaces/IConsolidationsChecker.sol | 37 + contracts/interfaces/IEthErc20Vault.sol | 30 + contracts/interfaces/IEthGenesisVault.sol | 7 +- contracts/interfaces/IEthVault.sol | 30 + contracts/interfaces/IGnoDaiDistributor.sol | 22 + contracts/interfaces/IGnoErc20Vault.sol | 34 + contracts/interfaces/IGnoGenesisVault.sol | 7 +- contracts/interfaces/IGnoVault.sol | 36 +- contracts/interfaces/IMerkleDistributor.sol | 36 + contracts/interfaces/ISavingsXDaiAdapter.sol | 17 + contracts/interfaces/IValidatorsChecker.sol | 34 +- contracts/interfaces/IVaultAdmin.sol | 13 + contracts/interfaces/IVaultFee.sol | 13 + contracts/interfaces/IVaultGnoStaking.sol | 7 +- contracts/interfaces/IVaultState.sol | 2 +- contracts/interfaces/IVaultValidators.sol | 77 +- contracts/interfaces/IXdaiExchange.sol | 84 - contracts/libraries/Errors.sol | 4 +- contracts/libraries/ExitQueue.sol | 2 +- contracts/misc/GnoDaiDistributor.sol | 58 + contracts/misc/XdaiExchange.sol | 189 --- contracts/mocks/BalancerVaultMock.sol | 75 - contracts/mocks/DepositorMock.sol | 18 - contracts/mocks/ERC20Mock.sol | 17 - contracts/mocks/EthPrivVaultV4Mock.sol | 46 - contracts/mocks/EthVaultMock.sol | 66 - contracts/mocks/EthVaultV5Mock.sol | 46 - contracts/mocks/EthVaultV6Mock.sol | 38 +- contracts/mocks/EthVaultV7Mock.sol | 17 + contracts/mocks/LegacyRewardTokenMock.sol | 55 - contracts/mocks/MulticallMock.sol | 86 +- .../mocks/OsTokenVaultEscrowAuthMock.sol | 31 - contracts/mocks/PoolEscrowMock.sol | 92 - contracts/mocks/PriceFeedMock.sol | 81 - contracts/mocks/UnknownVaultMock.sol | 27 - .../mocks/ValidatorsConsolidationsMock.sol | 23 + contracts/mocks/ValidatorsWithdrawalsMock.sol | 23 + contracts/mocks/XdaiExchangeV2Mock.sol | 19 - .../validators/ConsolidationsChecker.sol | 105 ++ contracts/validators/DepositDataRegistry.sol | 10 +- contracts/validators/ValidatorsChecker.sol | 51 +- .../ethereum/EthBlocklistErc20Vault.sol | 41 +- .../vaults/ethereum/EthBlocklistVault.sol | 41 +- contracts/vaults/ethereum/EthErc20Vault.sol | 65 +- contracts/vaults/ethereum/EthGenesisVault.sol | 157 +- .../vaults/ethereum/EthPrivErc20Vault.sol | 41 +- contracts/vaults/ethereum/EthPrivVault.sol | 41 +- contracts/vaults/ethereum/EthVault.sol | 65 +- .../vaults/ethereum/custom/EthFoxVault.sol | 81 +- .../vaults/gnosis/GnoBlocklistErc20Vault.sol | 44 +- contracts/vaults/gnosis/GnoBlocklistVault.sol | 42 +- contracts/vaults/gnosis/GnoErc20Vault.sol | 90 +- contracts/vaults/gnosis/GnoGenesisVault.sol | 136 +- contracts/vaults/gnosis/GnoPrivErc20Vault.sol | 44 +- contracts/vaults/gnosis/GnoPrivVault.sol | 42 +- contracts/vaults/gnosis/GnoVault.sol | 88 +- contracts/vaults/modules/VaultAdmin.sol | 33 +- contracts/vaults/modules/VaultEnterExit.sol | 1 - contracts/vaults/modules/VaultEthStaking.sol | 81 +- contracts/vaults/modules/VaultFee.sol | 43 +- contracts/vaults/modules/VaultGnoStaking.sol | 131 +- contracts/vaults/modules/VaultImmutables.sol | 7 +- contracts/vaults/modules/VaultOsToken.sol | 2 +- contracts/vaults/modules/VaultState.sol | 15 +- contracts/vaults/modules/VaultValidators.sol | 480 +++++- foundry.toml | 10 +- lib/openzeppelin-contracts-upgradeable | 1 + lib/openzeppelin-foundry-upgrades | 1 + snapshots/DepositDataRegistryTest.json | 9 + snapshots/GnoBlocklistErc20VaultTest.json | 7 + snapshots/GnoBlocklistVaultTest.json | 6 + snapshots/GnoErc20VaultTest.json | 12 + snapshots/GnoGenesisVaultTest.json | 5 + snapshots/GnoOsTokenVaultEscrowTest.json | 5 + snapshots/GnoOwnMevEscrowTest.json | 3 + snapshots/GnoPrivErc20VaultTest.json | 7 + snapshots/GnoPrivVaultTest.json | 8 + snapshots/GnoSharedMevEscrowTest.json | 3 + snapshots/GnoVaultTest.json | 8 + snapshots/VaultGnoStakingTest.json | 14 + test/ConsolidationsChecker.t.sol | 471 +++++ test/DepositDataRegistry.spec.ts | 466 ----- test/DepositDataRegistry.t.sol | 768 +++++++++ test/EthBlocklistErc20Vault.spec.ts | 210 --- test/EthBlocklistErc20Vault.t.sol | 339 ++++ test/EthBlocklistVault.spec.ts | 171 -- test/EthBlocklistVault.t.sol | 288 ++++ test/EthErc20Vault.spec.ts | 346 ---- test/EthErc20Vault.t.sol | 476 ++++++ test/EthFoxVault.spec.ts | 243 --- test/EthFoxVault.t.sol | 296 ++++ test/EthGenesisVault.spec.ts | 582 ------- test/EthGenesisVault.t.sol | 371 ++++ test/EthOsTokenVaultEscrow.t.sol | 1441 ++++++++++++++++ test/EthPrivErc20Vault.spec.ts | 217 --- test/EthPrivErc20Vault.t.sol | 441 +++++ test/EthPrivVault.spec.ts | 88 - test/EthPrivVault.t.sol | 473 ++++++ test/EthRewardSplitter.t.sol | 966 +++++------ test/EthValidatorsChecker.t.sol | 490 ++++++ test/EthVault.t.sol | 374 ++++ test/KeeperOracles.t.sol | 212 +++ test/KeeperRewards.t.sol | 585 +++++++ test/KeeperValidators.t.sol | 480 ++++++ test/Multicall.t.sol | 146 ++ test/OsToken.t.sol | 400 +++++ test/OsTokenConfig.t.sol | 427 +++++ test/OsTokenFlashLoans.t.sol | 203 +++ test/OwnMevEscrow.spec.ts | 46 - test/OwnMevEscrow.t.sol | 205 +++ test/PriceFeed.t.sol | 158 ++ test/RewardSplitterFactory.spec.ts | 68 - test/SharedMevEscrow.spec.ts | 42 - test/SharedMevEscrow.t.sol | 201 +++ test/VaultAdmin.t.sol | 150 ++ test/VaultEnterExit.t.sol | 788 +++++++++ test/VaultEthStaking.t.sol | 571 +++++++ test/VaultExitQueueClaim.t.sol | 436 ----- test/VaultFee.t.sol | 414 +++++ test/VaultOsToken.t.sol | 1470 ++++++++++++++++ test/VaultState.t.sol | 545 ++++++ test/VaultToken.t.sol | 635 +++++++ test/VaultValidators.t.sol | 1510 +++++++++++++++++ test/VaultVersion.t.sol | 283 +++ test/VaultsRegistry.spec.ts | 192 --- test/VaultsRegistry.t.sol | 292 ++++ test/gnosis/GnoBlocklistErc20Vault.spec.ts | 164 -- test/gnosis/GnoBlocklistErc20Vault.t.sol | 331 ++++ test/gnosis/GnoBlocklistVault.spec.ts | 125 -- test/gnosis/GnoBlocklistVault.t.sol | 245 +++ test/gnosis/GnoErc20Vault.spec.ts | 190 --- test/gnosis/GnoErc20Vault.t.sol | 359 ++++ test/gnosis/GnoGenesisVault.spec.ts | 405 ----- test/gnosis/GnoGenesisVault.t.sol | 230 +++ test/gnosis/GnoOsTokenVaultEscrow.spec.ts | 93 - test/gnosis/GnoOsTokenVaultEscrow.t.sol | 134 ++ test/gnosis/GnoOwnMevEscrow.spec.ts | 46 - test/gnosis/GnoOwnMevEscrow.t.sol | 98 ++ test/gnosis/GnoPrivErc20Vault.spec.ts | 166 -- test/gnosis/GnoPrivErc20Vault.t.sol | 352 ++++ test/gnosis/GnoPrivVault.spec.ts | 126 -- test/gnosis/GnoPrivVault.t.sol | 349 ++++ test/gnosis/GnoSharedMevEscrow.spec.ts | 42 - test/gnosis/GnoSharedMevEscrow.t.sol | 121 ++ test/gnosis/GnoVault.register.spec.ts | 521 ------ test/gnosis/GnoVault.spec.ts | 185 -- test/gnosis/GnoVault.state.spec.ts | 153 -- test/gnosis/GnoVault.t.sol | 303 ++++ test/gnosis/GnoVault.upgrade.spec.ts | 230 --- test/gnosis/GnoVaultExitQueue.t.sol | 322 ++++ test/gnosis/VaultGnoStaking.t.sol | 568 +++++++ test/gnosis/XdaiExchange.spec.ts | 235 --- test/helpers/EthHelpers.sol | 430 +++++ test/helpers/GnoHelpers.sol | 440 +++++ test/helpers/KeeperHelpers.sol | 132 ++ test/helpers/ValidatorsHelpers.sol | 197 +++ 191 files changed, 27657 insertions(+), 8531 deletions(-) create mode 100644 abi/IConsolidationsChecker.json create mode 100644 abi/IGnoDaiDistributor.json create mode 100644 abi/IMerkleDistributor.json create mode 100644 abi/ISavingsXDaiAdapter.json delete mode 100644 abi/IXdaiExchange.json create mode 100644 contracts/interfaces/IConsolidationsChecker.sol create mode 100644 contracts/interfaces/IGnoDaiDistributor.sol create mode 100644 contracts/interfaces/IMerkleDistributor.sol create mode 100644 contracts/interfaces/ISavingsXDaiAdapter.sol delete mode 100644 contracts/interfaces/IXdaiExchange.sol create mode 100644 contracts/misc/GnoDaiDistributor.sol delete mode 100644 contracts/misc/XdaiExchange.sol delete mode 100644 contracts/mocks/BalancerVaultMock.sol delete mode 100644 contracts/mocks/DepositorMock.sol delete mode 100644 contracts/mocks/ERC20Mock.sol delete mode 100644 contracts/mocks/EthPrivVaultV4Mock.sol delete mode 100644 contracts/mocks/EthVaultMock.sol delete mode 100644 contracts/mocks/EthVaultV5Mock.sol create mode 100644 contracts/mocks/EthVaultV7Mock.sol delete mode 100644 contracts/mocks/LegacyRewardTokenMock.sol delete mode 100644 contracts/mocks/OsTokenVaultEscrowAuthMock.sol delete mode 100644 contracts/mocks/PoolEscrowMock.sol delete mode 100644 contracts/mocks/PriceFeedMock.sol delete mode 100644 contracts/mocks/UnknownVaultMock.sol create mode 100644 contracts/mocks/ValidatorsConsolidationsMock.sol create mode 100644 contracts/mocks/ValidatorsWithdrawalsMock.sol delete mode 100644 contracts/mocks/XdaiExchangeV2Mock.sol create mode 100644 contracts/validators/ConsolidationsChecker.sol create mode 160000 lib/openzeppelin-contracts-upgradeable create mode 160000 lib/openzeppelin-foundry-upgrades create mode 100644 snapshots/DepositDataRegistryTest.json create mode 100644 snapshots/GnoBlocklistErc20VaultTest.json create mode 100644 snapshots/GnoBlocklistVaultTest.json create mode 100644 snapshots/GnoErc20VaultTest.json create mode 100644 snapshots/GnoGenesisVaultTest.json create mode 100644 snapshots/GnoOsTokenVaultEscrowTest.json create mode 100644 snapshots/GnoOwnMevEscrowTest.json create mode 100644 snapshots/GnoPrivErc20VaultTest.json create mode 100644 snapshots/GnoPrivVaultTest.json create mode 100644 snapshots/GnoSharedMevEscrowTest.json create mode 100644 snapshots/GnoVaultTest.json create mode 100644 snapshots/VaultGnoStakingTest.json create mode 100644 test/ConsolidationsChecker.t.sol delete mode 100644 test/DepositDataRegistry.spec.ts create mode 100644 test/DepositDataRegistry.t.sol delete mode 100644 test/EthBlocklistErc20Vault.spec.ts create mode 100644 test/EthBlocklistErc20Vault.t.sol delete mode 100644 test/EthBlocklistVault.spec.ts create mode 100644 test/EthBlocklistVault.t.sol delete mode 100644 test/EthErc20Vault.spec.ts create mode 100644 test/EthErc20Vault.t.sol delete mode 100644 test/EthFoxVault.spec.ts create mode 100644 test/EthFoxVault.t.sol delete mode 100644 test/EthGenesisVault.spec.ts create mode 100644 test/EthGenesisVault.t.sol create mode 100644 test/EthOsTokenVaultEscrow.t.sol delete mode 100644 test/EthPrivErc20Vault.spec.ts create mode 100644 test/EthPrivErc20Vault.t.sol delete mode 100644 test/EthPrivVault.spec.ts create mode 100644 test/EthPrivVault.t.sol create mode 100644 test/EthValidatorsChecker.t.sol create mode 100644 test/EthVault.t.sol create mode 100644 test/KeeperOracles.t.sol create mode 100644 test/KeeperRewards.t.sol create mode 100644 test/KeeperValidators.t.sol create mode 100644 test/Multicall.t.sol create mode 100644 test/OsToken.t.sol create mode 100644 test/OsTokenConfig.t.sol create mode 100644 test/OsTokenFlashLoans.t.sol delete mode 100644 test/OwnMevEscrow.spec.ts create mode 100644 test/OwnMevEscrow.t.sol create mode 100644 test/PriceFeed.t.sol delete mode 100644 test/RewardSplitterFactory.spec.ts delete mode 100644 test/SharedMevEscrow.spec.ts create mode 100644 test/SharedMevEscrow.t.sol create mode 100644 test/VaultAdmin.t.sol create mode 100644 test/VaultEnterExit.t.sol create mode 100644 test/VaultEthStaking.t.sol delete mode 100644 test/VaultExitQueueClaim.t.sol create mode 100644 test/VaultFee.t.sol create mode 100644 test/VaultOsToken.t.sol create mode 100644 test/VaultState.t.sol create mode 100644 test/VaultToken.t.sol create mode 100644 test/VaultValidators.t.sol create mode 100644 test/VaultVersion.t.sol delete mode 100644 test/VaultsRegistry.spec.ts create mode 100644 test/VaultsRegistry.t.sol delete mode 100644 test/gnosis/GnoBlocklistErc20Vault.spec.ts create mode 100644 test/gnosis/GnoBlocklistErc20Vault.t.sol delete mode 100644 test/gnosis/GnoBlocklistVault.spec.ts create mode 100644 test/gnosis/GnoBlocklistVault.t.sol delete mode 100644 test/gnosis/GnoErc20Vault.spec.ts create mode 100644 test/gnosis/GnoErc20Vault.t.sol delete mode 100644 test/gnosis/GnoGenesisVault.spec.ts create mode 100644 test/gnosis/GnoGenesisVault.t.sol delete mode 100644 test/gnosis/GnoOsTokenVaultEscrow.spec.ts create mode 100644 test/gnosis/GnoOsTokenVaultEscrow.t.sol delete mode 100644 test/gnosis/GnoOwnMevEscrow.spec.ts create mode 100644 test/gnosis/GnoOwnMevEscrow.t.sol delete mode 100644 test/gnosis/GnoPrivErc20Vault.spec.ts create mode 100644 test/gnosis/GnoPrivErc20Vault.t.sol delete mode 100644 test/gnosis/GnoPrivVault.spec.ts create mode 100644 test/gnosis/GnoPrivVault.t.sol delete mode 100644 test/gnosis/GnoSharedMevEscrow.spec.ts create mode 100644 test/gnosis/GnoSharedMevEscrow.t.sol delete mode 100644 test/gnosis/GnoVault.register.spec.ts delete mode 100644 test/gnosis/GnoVault.spec.ts delete mode 100644 test/gnosis/GnoVault.state.spec.ts create mode 100644 test/gnosis/GnoVault.t.sol delete mode 100644 test/gnosis/GnoVault.upgrade.spec.ts create mode 100644 test/gnosis/GnoVaultExitQueue.t.sol create mode 100644 test/gnosis/VaultGnoStaking.t.sol delete mode 100644 test/gnosis/XdaiExchange.spec.ts create mode 100644 test/helpers/EthHelpers.sol create mode 100644 test/helpers/GnoHelpers.sol create mode 100644 test/helpers/KeeperHelpers.sol create mode 100644 test/helpers/ValidatorsHelpers.sol diff --git a/.gitmodules b/.gitmodules index 888d42dc..23acfb1d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/openzeppelin-foundry-upgrades"] + path = lib/openzeppelin-foundry-upgrades + url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable diff --git a/abi/Errors.json b/abi/Errors.json index 2519ffee..cf8739e4 100644 --- a/abi/Errors.json +++ b/abi/Errors.json @@ -144,6 +144,11 @@ "name": "InvalidShares", "type": "error" }, + { + "inputs": [], + "name": "InvalidSignatures", + "type": "error" + }, { "inputs": [], "name": "InvalidTokenMeta", @@ -164,6 +169,11 @@ "name": "InvalidVault", "type": "error" }, + { + "inputs": [], + "name": "InvalidWithdrawalCredentialsPrefix", + "type": "error" + }, { "inputs": [], "name": "LiquidationDisabled", diff --git a/abi/IConsolidationsChecker.json b/abi/IConsolidationsChecker.json new file mode 100644 index 00000000..f81f2150 --- /dev/null +++ b/abi/IConsolidationsChecker.json @@ -0,0 +1,103 @@ +[ + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vault", + "type": "address" + }, + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "isValidSignatures", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vault", + "type": "address" + }, + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "verifySignatures", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/IEthBlocklistErc20Vault.json b/abi/IEthBlocklistErc20Vault.json index ae1820cc..e2ee6afd 100644 --- a/abi/IEthBlocklistErc20Vault.json +++ b/abi/IEthBlocklistErc20Vault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -199,6 +218,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -522,6 +560,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -530,11 +625,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -797,6 +923,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -951,6 +1100,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1307,6 +1474,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1320,6 +1500,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1424,6 +1617,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1669,6 +1881,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1695,6 +1920,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthBlocklistVault.json b/abi/IEthBlocklistVault.json index a8b35c75..328668a9 100644 --- a/abi/IEthBlocklistVault.json +++ b/abi/IEthBlocklistVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -174,6 +193,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -472,6 +510,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -480,11 +575,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -667,6 +793,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -808,6 +957,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1089,6 +1256,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1102,6 +1282,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1180,6 +1373,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1372,6 +1584,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1398,6 +1623,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthErc20Vault.json b/abi/IEthErc20Vault.json index 45e070e3..9149f12f 100644 --- a/abi/IEthErc20Vault.json +++ b/abi/IEthErc20Vault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -155,6 +174,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -478,6 +516,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -486,11 +581,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -721,6 +847,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -875,6 +1024,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1231,6 +1398,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1335,6 +1528,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1562,6 +1774,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1588,6 +1813,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthFoxVault.json b/abi/IEthFoxVault.json index dde352ae..0d22bf10 100644 --- a/abi/IEthFoxVault.json +++ b/abi/IEthFoxVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -211,6 +230,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -380,6 +418,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -388,11 +483,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -556,6 +682,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -681,6 +830,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -868,6 +1035,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -881,6 +1061,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -959,6 +1152,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1076,6 +1288,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1102,6 +1327,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthGenesisVault.json b/abi/IEthGenesisVault.json index b3be59b2..1d5a91ca 100644 --- a/abi/IEthGenesisVault.json +++ b/abi/IEthGenesisVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -484,6 +522,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -497,6 +579,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -535,13 +661,6 @@ "name": "ValidatorsRootUpdated", "type": "event" }, - { - "inputs": [], - "name": "acceptPoolEscrowOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "admin", @@ -654,6 +773,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -795,6 +937,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1100,6 +1260,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1178,6 +1364,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1352,6 +1557,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1378,6 +1596,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthPrivErc20Vault.json b/abi/IEthPrivErc20Vault.json index ac817819..a05f0f12 100644 --- a/abi/IEthPrivErc20Vault.json +++ b/abi/IEthPrivErc20Vault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -155,6 +174,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -478,6 +516,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -486,11 +581,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -765,6 +891,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -919,6 +1068,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1275,6 +1442,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1392,6 +1585,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1637,6 +1849,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1695,6 +1920,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthPrivVault.json b/abi/IEthPrivVault.json index 210981a5..7cce9d82 100644 --- a/abi/IEthPrivVault.json +++ b/abi/IEthPrivVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -428,6 +466,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -436,11 +531,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -635,6 +761,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -776,6 +925,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1057,6 +1224,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1148,6 +1341,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1340,6 +1552,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1398,6 +1623,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IEthVault.json b/abi/IEthVault.json index 9da6b5f0..da1739d5 100644 --- a/abi/IEthVault.json +++ b/abi/IEthVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -428,6 +466,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -436,11 +531,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -591,6 +717,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -732,6 +881,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1013,6 +1180,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1091,6 +1284,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1265,6 +1477,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1291,6 +1516,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoBlocklistErc20Vault.json b/abi/IGnoBlocklistErc20Vault.json index 73ea36bc..3b43554d 100644 --- a/abi/IGnoBlocklistErc20Vault.json +++ b/abi/IGnoBlocklistErc20Vault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -199,6 +218,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -522,6 +560,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -535,6 +617,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -816,6 +942,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -946,6 +1095,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1295,6 +1462,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1308,6 +1488,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1347,13 +1540,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "symbol", @@ -1419,6 +1605,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1557,6 +1762,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1583,6 +1801,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoBlocklistVault.json b/abi/IGnoBlocklistVault.json index 5372368e..7b689079 100644 --- a/abi/IGnoBlocklistVault.json +++ b/abi/IGnoBlocklistVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -174,6 +193,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -472,6 +510,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -485,6 +567,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -686,6 +812,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -803,6 +952,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1077,6 +1244,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1090,6 +1270,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1129,13 +1322,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "totalAssets", @@ -1175,6 +1361,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1260,6 +1465,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1286,6 +1504,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoDaiDistributor.json b/abi/IGnoDaiDistributor.json new file mode 100644 index 00000000..bb8e94e9 --- /dev/null +++ b/abi/IGnoDaiDistributor.json @@ -0,0 +1,28 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vault", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DaiDistributed", + "type": "event" + }, + { + "inputs": [], + "name": "distributeDai", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] diff --git a/abi/IGnoErc20Vault.json b/abi/IGnoErc20Vault.json index 26c3091b..a90731d6 100644 --- a/abi/IGnoErc20Vault.json +++ b/abi/IGnoErc20Vault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -155,6 +174,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -478,6 +516,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -491,6 +573,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -740,6 +866,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -870,6 +1019,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1219,6 +1386,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1258,13 +1451,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "symbol", @@ -1330,6 +1516,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1450,6 +1655,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1476,6 +1694,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoGenesisVault.json b/abi/IGnoGenesisVault.json index 11200c7c..e9d90aa5 100644 --- a/abi/IGnoGenesisVault.json +++ b/abi/IGnoGenesisVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -484,6 +522,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -497,6 +579,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -554,13 +680,6 @@ "name": "XdaiSwapped", "type": "event" }, - { - "inputs": [], - "name": "acceptPoolEscrowOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "admin", @@ -673,6 +792,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -790,6 +932,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1088,6 +1248,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1127,13 +1313,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "totalAssets", @@ -1173,6 +1352,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1240,6 +1438,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1266,6 +1477,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoPrivErc20Vault.json b/abi/IGnoPrivErc20Vault.json index da938586..e278eed9 100644 --- a/abi/IGnoPrivErc20Vault.json +++ b/abi/IGnoPrivErc20Vault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -155,6 +174,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -478,6 +516,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -491,6 +573,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -784,6 +910,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -914,6 +1063,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1263,6 +1430,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1315,13 +1508,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "symbol", @@ -1387,6 +1573,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1525,6 +1730,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1583,6 +1801,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoPrivVault.json b/abi/IGnoPrivVault.json index a185eced..1b308a5b 100644 --- a/abi/IGnoPrivVault.json +++ b/abi/IGnoPrivVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -428,6 +466,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -441,6 +523,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -654,6 +780,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -771,6 +920,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1045,6 +1212,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1097,13 +1290,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "totalAssets", @@ -1143,6 +1329,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1228,6 +1433,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1286,6 +1504,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IGnoVault.json b/abi/IGnoVault.json index ccd87c35..fcc5064c 100644 --- a/abi/IGnoVault.json +++ b/abi/IGnoVault.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -428,6 +466,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -441,6 +523,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -610,6 +736,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -727,6 +876,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1001,6 +1168,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1040,13 +1233,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "totalAssets", @@ -1086,6 +1272,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1153,6 +1358,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "vaultId", @@ -1179,6 +1397,24 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IMerkleDistributor.json b/abi/IMerkleDistributor.json new file mode 100644 index 00000000..c9a13e9b --- /dev/null +++ b/abi/IMerkleDistributor.json @@ -0,0 +1,61 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "rewardsIpfsHash", + "type": "string" + }, + { + "internalType": "bytes", + "name": "extraData", + "type": "bytes" + } + ], + "name": "distributeOneTime", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "distributor", + "type": "address" + }, + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + } + ], + "name": "setDistributor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/ISavingsXDaiAdapter.json b/abi/ISavingsXDaiAdapter.json new file mode 100644 index 00000000..269542b3 --- /dev/null +++ b/abi/ISavingsXDaiAdapter.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "depositXDAI", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + } +] diff --git a/abi/IVaultAdmin.json b/abi/IVaultAdmin.json index 2e433e28..4db86e03 100644 --- a/abi/IVaultAdmin.json +++ b/abi/IVaultAdmin.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -31,6 +50,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultBlocklist.json b/abi/IVaultBlocklist.json index 356ee8a5..4c5545af 100644 --- a/abi/IVaultBlocklist.json +++ b/abi/IVaultBlocklist.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -107,6 +126,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultEnterExit.json b/abi/IVaultEnterExit.json index 52778db8..e4cf9fd5 100644 --- a/abi/IVaultEnterExit.json +++ b/abi/IVaultEnterExit.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -506,6 +544,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultEthStaking.json b/abi/IVaultEthStaking.json index 4601621c..7ebc5bb6 100644 --- a/abi/IVaultEthStaking.json +++ b/abi/IVaultEthStaking.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -280,6 +318,63 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -288,11 +383,42 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -424,6 +550,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -536,6 +685,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -665,6 +832,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -743,6 +936,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -842,6 +1054,37 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IVaultFee.json b/abi/IVaultFee.json index 3baff0e7..f6d7da36 100644 --- a/abi/IVaultFee.json +++ b/abi/IVaultFee.json @@ -1,4 +1,42 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -76,6 +114,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultGnoStaking.json b/abi/IVaultGnoStaking.json index 5b0783da..4d2694c2 100644 --- a/abi/IVaultGnoStaking.json +++ b/abi/IVaultGnoStaking.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -280,6 +318,50 @@ "name": "V2ExitQueueEntered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -293,6 +375,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -443,6 +569,29 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -560,6 +709,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -669,6 +836,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -708,13 +901,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "totalAssets", @@ -754,6 +940,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -802,6 +1007,37 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IVaultMev.json b/abi/IVaultMev.json index aeab8669..cc7af01a 100644 --- a/abi/IVaultMev.json +++ b/abi/IVaultMev.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -31,6 +50,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -242,6 +280,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultOsToken.json b/abi/IVaultOsToken.json index 52501c26..881e1c3f 100644 --- a/abi/IVaultOsToken.json +++ b/abi/IVaultOsToken.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -130,6 +149,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -767,6 +805,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultState.json b/abi/IVaultState.json index af040294..c62d3452 100644 --- a/abi/IVaultState.json +++ b/abi/IVaultState.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -31,6 +50,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -229,6 +267,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultToken.json b/abi/IVaultToken.json index f73a2efa..a2695644 100644 --- a/abi/IVaultToken.json +++ b/abi/IVaultToken.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -155,6 +174,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -724,6 +762,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultValidators.json b/abi/IVaultValidators.json index 0a8b223f..3e3edf14 100644 --- a/abi/IVaultValidators.json +++ b/abi/IVaultValidators.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -31,6 +50,25 @@ "name": "ExitingAssetsPenalized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feePercent", + "type": "uint16" + } + ], + "name": "FeePercentUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -113,6 +151,50 @@ "name": "MetadataUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "fromPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "toPublicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorConsolidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorFunded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -126,6 +208,50 @@ "name": "ValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feePaid", + "type": "uint256" + } + ], + "name": "ValidatorWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -190,6 +316,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "oracleSignatures", + "type": "bytes" + } + ], + "name": "consolidateValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -254,6 +403,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "fundValidators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -344,6 +511,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "_feePercent", + "type": "uint16" + } + ], + "name": "setFeePercent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -422,6 +615,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "name": "trackedValidators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -470,6 +682,37 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "validatorsManagerNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "validators", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "validatorsManagerSignature", + "type": "bytes" + } + ], + "name": "withdrawValidators", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "withdrawableAssets", diff --git a/abi/IVaultVersion.json b/abi/IVaultVersion.json index ded56236..c4c5ab89 100644 --- a/abi/IVaultVersion.json +++ b/abi/IVaultVersion.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -57,6 +76,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IVaultWhitelist.json b/abi/IVaultWhitelist.json index c205ccf9..8467bf6f 100644 --- a/abi/IVaultWhitelist.json +++ b/abi/IVaultWhitelist.json @@ -1,4 +1,23 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -75,6 +94,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "setAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/IXdaiExchange.json b/abi/IXdaiExchange.json deleted file mode 100644 index aeeeef3e..00000000 --- a/abi/IXdaiExchange.json +++ /dev/null @@ -1,160 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes32", - "name": "balancerPoolId", - "type": "bytes32" - } - ], - "name": "BalancerPoolIdUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint128", - "name": "maxSlippage", - "type": "uint128" - } - ], - "name": "MaxSlippageUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint128", - "name": "stalePriceTimeDelta", - "type": "uint128" - } - ], - "name": "StalePriceTimeDeltaUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "balancerPoolId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "initialOwner", - "type": "address" - }, - { - "internalType": "uint128", - "name": "_maxSlippage", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "_stalePriceTimeDelta", - "type": "uint128" - }, - { - "internalType": "bytes32", - "name": "_balancerPoolId", - "type": "bytes32" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "maxSlippage", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "newBalancerPoolId", - "type": "bytes32" - } - ], - "name": "setBalancerPoolId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "newMaxSlippage", - "type": "uint128" - } - ], - "name": "setMaxSlippage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "newStalePriceTimeDelta", - "type": "uint128" - } - ], - "name": "setStalePriceTimeDelta", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "stalePriceTimeDelta", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "swap", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - } -] diff --git a/contracts/interfaces/IConsolidationsChecker.sol b/contracts/interfaces/IConsolidationsChecker.sol new file mode 100644 index 00000000..0e0e1e1a --- /dev/null +++ b/contracts/interfaces/IConsolidationsChecker.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; + +/** + * @title IConsolidationsChecker + * @author StakeWise + * @notice Defines the interface for the ConsolidationsChecker contract + */ +interface IConsolidationsChecker is IERC5267 { + /** + * @notice Verifies the signatures of oracles for validators consolidations. Reverts if the signatures are invalid. + * @param vault The address of the vault + * @param validators The concatenation of the validators' data + * @param signatures The concatenation of the oracles' signatures + */ + function verifySignatures( + address vault, + bytes calldata validators, + bytes calldata signatures + ) external; + + /** + * @notice Function for checking signatures of oracles for validators consolidations + * @param vault The address of the vault + * @param validators The concatenation of the validators' data + * @param signatures The concatenation of the oracles' signatures + * @return `true` if the signatures are valid, `false` otherwise + */ + function isValidSignatures( + address vault, + bytes calldata validators, + bytes calldata signatures + ) external returns (bool); +} diff --git a/contracts/interfaces/IEthErc20Vault.sol b/contracts/interfaces/IEthErc20Vault.sol index fb9db8d1..5e044049 100644 --- a/contracts/interfaces/IEthErc20Vault.sol +++ b/contracts/interfaces/IEthErc20Vault.sol @@ -33,6 +33,36 @@ interface IEthErc20Vault is IVaultEthStaking, IMulticall { + /** + * @dev Struct for deploying the EthErc20Vault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct EthErc20VaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + uint64 exitingAssetsClaimDelay; + } + /** * @dev Struct for initializing the EthErc20Vault contract * @param capacity The Vault stops accepting deposits after exceeding the capacity diff --git a/contracts/interfaces/IEthGenesisVault.sol b/contracts/interfaces/IEthGenesisVault.sol index 2d19047c..07d2fc19 100644 --- a/contracts/interfaces/IEthGenesisVault.sol +++ b/contracts/interfaces/IEthGenesisVault.sol @@ -19,7 +19,7 @@ interface IEthGenesisVault is IEthVault { event Migrated(address receiver, uint256 assets, uint256 shares); /** - * @notice Event emitted on EthGenesisVault creation + * @notice Event emitted on EthGenesisVault creation (deprecated) * @param admin The address of the Vault admin * @param capacity The capacity of the Vault * @param feePercent The fee percent of the Vault @@ -39,9 +39,4 @@ interface IEthGenesisVault is IEthVault { * @return shares The amount of shares minted */ function migrate(address receiver, uint256 assets) external returns (uint256 shares); - - /** - * @notice Function for accepting PoolEscrow contract ownership. Can only be called once by the admin. - */ - function acceptPoolEscrowOwnership() external; } diff --git a/contracts/interfaces/IEthVault.sol b/contracts/interfaces/IEthVault.sol index c67859d3..b554b338 100644 --- a/contracts/interfaces/IEthVault.sol +++ b/contracts/interfaces/IEthVault.sol @@ -31,6 +31,36 @@ interface IEthVault is IVaultEthStaking, IMulticall { + /** + * @dev Struct for deploying the EthVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct EthVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + uint64 exitingAssetsClaimDelay; + } + /** * @dev Struct for initializing the EthVault contract * @param capacity The Vault stops accepting deposits after exceeding the capacity diff --git a/contracts/interfaces/IGnoDaiDistributor.sol b/contracts/interfaces/IGnoDaiDistributor.sol new file mode 100644 index 00000000..16bea413 --- /dev/null +++ b/contracts/interfaces/IGnoDaiDistributor.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IGnoDaiDistributor + * @author StakeWise + * @notice Defines the interface for the GnoDaiDistributor + */ +interface IGnoDaiDistributor { + /** + * @notice Event emitted when sDAI is distributed to the users + * @param vault The address of the vault + * @param amount The amount of sDAI distributed + */ + event SDaiDistributed(address indexed vault, uint256 amount); + + /** + * @notice Distribute sDAI to the users. Can be called only by the vaults. Must transfer xDAI together with the call. + */ + function distributeSDai() external payable; +} diff --git a/contracts/interfaces/IGnoErc20Vault.sol b/contracts/interfaces/IGnoErc20Vault.sol index f3345ad7..2f96c14e 100644 --- a/contracts/interfaces/IGnoErc20Vault.sol +++ b/contracts/interfaces/IGnoErc20Vault.sol @@ -32,6 +32,40 @@ interface IGnoErc20Vault is IVaultGnoStaking, IMulticall { + /** + * @notice Struct for initializing the GnoErc20Vault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param gnoToken The address of the GNO token + * @param gnoDaiDistributor The address of the GnoDaiDistributor contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct GnoErc20VaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + address gnoToken; + address gnoDaiDistributor; + uint256 exitingAssetsClaimDelay; + } + /** * @dev Struct for initializing the GnoErc20Vault contract * @param capacity The Vault stops accepting deposits after exceeding the capacity diff --git a/contracts/interfaces/IGnoGenesisVault.sol b/contracts/interfaces/IGnoGenesisVault.sol index 8a05589d..715f73b3 100644 --- a/contracts/interfaces/IGnoGenesisVault.sol +++ b/contracts/interfaces/IGnoGenesisVault.sol @@ -19,7 +19,7 @@ interface IGnoGenesisVault is IGnoVault { event Migrated(address receiver, uint256 assets, uint256 shares); /** - * @notice Event emitted on GnoGenesisVault creation + * @notice Event emitted on GnoGenesisVault creation (deprecated) * @param admin The address of the Vault admin * @param capacity The capacity of the Vault * @param feePercent The fee percent of the Vault @@ -39,9 +39,4 @@ interface IGnoGenesisVault is IGnoVault { * @return shares The amount of shares minted */ function migrate(address receiver, uint256 assets) external returns (uint256 shares); - - /** - * @notice Function for accepting PoolEscrow contract ownership. Can only be called once by the admin. - */ - function acceptPoolEscrowOwnership() external; } diff --git a/contracts/interfaces/IGnoVault.sol b/contracts/interfaces/IGnoVault.sol index 97cc2227..3c3c3ccc 100644 --- a/contracts/interfaces/IGnoVault.sol +++ b/contracts/interfaces/IGnoVault.sol @@ -31,7 +31,41 @@ interface IGnoVault is IMulticall { /** - * @dev Struct for initializing the GnoVault contract + * @notice Struct for initializing the GnoVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param gnoToken The address of the GNO token + * @param gnoDaiDistributor The address of the GnoDaiDistributor contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct GnoVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + address gnoToken; + address gnoDaiDistributor; + uint256 exitingAssetsClaimDelay; + } + + /** + * @notice Struct for initializing the GnoVault contract * @param capacity The Vault stops accepting deposits after exceeding the capacity * @param feePercent The fee percent that is charged by the Vault * @param metadataIpfsHash The IPFS hash of the Vault's metadata file diff --git a/contracts/interfaces/IMerkleDistributor.sol b/contracts/interfaces/IMerkleDistributor.sol new file mode 100644 index 00000000..76e5636b --- /dev/null +++ b/contracts/interfaces/IMerkleDistributor.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IMerkleDistributor + * @author StakeWise + * @notice Defines the interface for the MerkleDistributor contract + */ +interface IMerkleDistributor { + /** + * @notice Distribute tokens one time + * @param token The address of the token + * @param amount The amount of tokens to distribute + * @param rewardsIpfsHash The IPFS hash of the rewards + * @param extraData The extra data for the distribution + */ + function distributeOneTime( + address token, + uint256 amount, + string calldata rewardsIpfsHash, + bytes calldata extraData + ) external; + + /** + * @notice Add or remove a distributor. Can only be called by the owner. + * @param distributor The address of the distributor + * @param isEnabled The status of the distributor, true for adding distributor, false for removing distributor + */ + function setDistributor(address distributor, bool isEnabled) external; + + /** + * @dev Returns the address of the current owner. + */ + function owner() external view returns (address); +} diff --git a/contracts/interfaces/ISavingsXDaiAdapter.sol b/contracts/interfaces/ISavingsXDaiAdapter.sol new file mode 100644 index 00000000..2c4e47ff --- /dev/null +++ b/contracts/interfaces/ISavingsXDaiAdapter.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title ISavingsXDaiAdapter + * @author StakeWise + * @notice Defines the interface for the SavingsXDaiAdapter + */ +interface ISavingsXDaiAdapter { + /** + * @notice Convert xDAI to sDAI + * @param receiver The address of the receiver + * @return The amount of sDAI received + */ + function depositXDAI(address receiver) external payable returns (uint256); +} diff --git a/contracts/interfaces/IValidatorsChecker.sol b/contracts/interfaces/IValidatorsChecker.sol index 4921ffb3..46b22dff 100644 --- a/contracts/interfaces/IValidatorsChecker.sol +++ b/contracts/interfaces/IValidatorsChecker.sol @@ -20,11 +20,29 @@ interface IValidatorsChecker { INVALID_PROOF } + /** + * @dev Struct for checking deposit data root + * @param vault The address of the vault + * @param validatorsRegistryRoot The validators registry root + * @param validators The concatenation of the validators' public key, deposit signature, deposit root + * @param proof The proof of the deposit data root + * @param proofFlags The flags of the proof + * @param proofIndexes The indexes of the proof + */ + struct DepositDataRootCheckParams { + address vault; + bytes32 validatorsRegistryRoot; + bytes validators; + bytes32[] proof; + bool[] proofFlags; + uint256[] proofIndexes; + } + /** * @notice Function for checking validators manager signature * @param vault The address of the vault * @param validatorsRegistryRoot The validators registry root - * @param validators The concatenation of the validators' public key, deposit signature, deposit root and optionally withdrawal address + * @param validators The concatenation of the validators' public key, deposit signature, deposit root * @param signature The validators manager signature * @return blockNumber Current block number * @return status The status of the verification @@ -38,21 +56,11 @@ interface IValidatorsChecker { /** * @notice Function for checking deposit data root - * @param vault The address of the vault - * @param validatorsRegistryRoot The validators registry root - * @param validators The concatenation of the validators' public key, deposit signature, deposit root and optionally withdrawal address - * @param proof The proof used for the merkle tree verification - * @param proofFlags The multi proof flags for the merkle tree verification - * @param proofIndexes The indexes of the leaves for the merkle tree multi proof verification + * @param params The parameters for checking deposit data root * @return blockNumber Current block number * @return status The status of the verification */ function checkDepositDataRoot( - address vault, - bytes32 validatorsRegistryRoot, - bytes calldata validators, - bytes32[] calldata proof, - bool[] calldata proofFlags, - uint256[] calldata proofIndexes + DepositDataRootCheckParams calldata params ) external view returns (uint256 blockNumber, Status status); } diff --git a/contracts/interfaces/IVaultAdmin.sol b/contracts/interfaces/IVaultAdmin.sol index bde36122..d69be714 100644 --- a/contracts/interfaces/IVaultAdmin.sol +++ b/contracts/interfaces/IVaultAdmin.sol @@ -15,6 +15,13 @@ interface IVaultAdmin { */ event MetadataUpdated(address indexed caller, string metadataIpfsHash); + /** + * @notice Event emitted on admin update + * @param caller The address of the function caller + * @param newAdmin The new admin address + */ + event AdminUpdated(address indexed caller, address newAdmin); + /** * @notice The Vault admin * @return The address of the Vault admin @@ -26,4 +33,10 @@ interface IVaultAdmin { * @param metadataIpfsHash The new metadata IPFS hash */ function setMetadata(string calldata metadataIpfsHash) external; + + /** + * @notice Function for updating the admin address. Can only be called by Vault current admin. + * @param newAdmin The new admin address + */ + function setAdmin(address newAdmin) external; } diff --git a/contracts/interfaces/IVaultFee.sol b/contracts/interfaces/IVaultFee.sol index c515ca8d..13db45c6 100644 --- a/contracts/interfaces/IVaultFee.sol +++ b/contracts/interfaces/IVaultFee.sol @@ -17,6 +17,13 @@ interface IVaultFee is IVaultAdmin { */ event FeeRecipientUpdated(address indexed caller, address indexed feeRecipient); + /** + * @notice Event emitted on fee percent update + * @param caller The address of the function caller + * @param feePercent The new fee percent + */ + event FeePercentUpdated(address indexed caller, uint16 feePercent); + /** * @notice The Vault's fee recipient * @return The address of the Vault's fee recipient @@ -34,4 +41,10 @@ interface IVaultFee is IVaultAdmin { * @param _feeRecipient The address of the new fee recipient */ function setFeeRecipient(address _feeRecipient) external; + + /** + * @notice Function for updating the fee percent. Can only be called by the admin. + * @param _feePercent The new fee percent + */ + function setFeePercent(uint16 _feePercent) external; } diff --git a/contracts/interfaces/IVaultGnoStaking.sol b/contracts/interfaces/IVaultGnoStaking.sol index 1191d914..e0dcfb5f 100644 --- a/contracts/interfaces/IVaultGnoStaking.sol +++ b/contracts/interfaces/IVaultGnoStaking.sol @@ -12,7 +12,7 @@ import {IVaultEnterExit} from './IVaultEnterExit.sol'; */ interface IVaultGnoStaking is IVaultValidators, IVaultEnterExit { /** - * @notice Emitted when xDAI is swapped to GNO + * @notice Emitted when xDAI is swapped to GNO (deprecated) * @param amount The amount of xDAI swapped * @param assets The amount of GNO received */ @@ -30,9 +30,4 @@ interface IVaultGnoStaking is IVaultValidators, IVaultEnterExit { address receiver, address referrer ) external returns (uint256 shares); - - /** - * @notice Swap xDAI accumulated in the vault to GNO - */ - function swapXdaiToGno() external; } diff --git a/contracts/interfaces/IVaultState.sol b/contracts/interfaces/IVaultState.sol index 1513e7d2..3023618b 100644 --- a/contracts/interfaces/IVaultState.sol +++ b/contracts/interfaces/IVaultState.sol @@ -27,7 +27,7 @@ interface IVaultState is IVaultFee { event FeeSharesMinted(address receiver, uint256 shares, uint256 assets); /** - * @notice Event emitted when exiting assets are penalized + * @notice Event emitted when exiting assets are penalized (deprecated) * @param penalty The total penalty amount */ event ExitingAssetsPenalized(uint256 penalty); diff --git a/contracts/interfaces/IVaultValidators.sol b/contracts/interfaces/IVaultValidators.sol index 5eb3347b..810aafa2 100644 --- a/contracts/interfaces/IVaultValidators.sol +++ b/contracts/interfaces/IVaultValidators.sol @@ -13,11 +13,41 @@ import {IVaultState} from './IVaultState.sol'; */ interface IVaultValidators is IVaultAdmin, IVaultState { /** - * @notice Event emitted on validator registration + * @notice Event emitted on V1 validator registration * @param publicKey The public key of the validator that was registered */ event ValidatorRegistered(bytes publicKey); + /** + * @notice Event emitted on V2 validator registration + * @param publicKey The public key of the validator that was registered + * @param amount The amount of assets that was registered + */ + event ValidatorRegistered(bytes publicKey, uint256 amount); + + /** + * @notice Event emitted on validator withdrawal + * @param publicKey The public key of the validator that was withdrawn + * @param amount The amount of assets that was withdrawn + * @param feePaid The amount of fee that was paid + */ + event ValidatorWithdrawalSubmitted(bytes publicKey, uint256 amount, uint256 feePaid); + + /** + * @notice Event emitted on validator balance top-up + * @param publicKey The public key of the validator that was funded + * @param amount The amount of assets that was funded + */ + event ValidatorFunded(bytes publicKey, uint256 amount); + + /** + * @notice Event emitted on validators consolidation + * @param fromPublicKey The public key of the validator that was consolidated + * @param toPublicKey The public key of the validator that was consolidated to + * @param feePaid The amount of fee that was paid + */ + event ValidatorConsolidationSubmitted(bytes fromPublicKey, bytes toPublicKey, uint256 feePaid); + /** * @notice Event emitted on keys manager address update (deprecated) * @param caller The address of the function caller @@ -45,6 +75,51 @@ interface IVaultValidators is IVaultAdmin, IVaultState { */ function validatorsManager() external view returns (address); + /** + * @notice The nonce for the validators manager used for signing + * @return The nonce for the validators manager + */ + function validatorsManagerNonce() external view returns (uint256); + + /** + * @notice Function for checking if the validator is tracked V2 validator + * @param publicKeyHash The keccak256 hash of the public key of the validator + * @return Whether the validator is tracked V2 validator + */ + function v2Validators(bytes32 publicKeyHash) external view returns (bool); + + /** + * @notice Function for funding single or multiple existing validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + */ + function fundValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) external; + + /** + * @notice Function for withdrawing single or multiple validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + */ + function withdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) external payable; + + /** + * @notice Function for consolidating single or multiple validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + * @param oracleSignatures The optional signatures from the oracles + */ + function consolidateValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature, + bytes calldata oracleSignatures + ) external payable; + /** * @notice Function for registering single or multiple validators * @param keeperParams The parameters for getting approval from Keeper oracles diff --git a/contracts/interfaces/IXdaiExchange.sol b/contracts/interfaces/IXdaiExchange.sol deleted file mode 100644 index 56da5394..00000000 --- a/contracts/interfaces/IXdaiExchange.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IXdaiExchange - * @author StakeWise - * @notice Defines the interface for the XdaiExchange contract - */ -interface IXdaiExchange { - /** - * @notice Emitted when the maximum slippage is changed - * @param maxSlippage The new maximum slippage - */ - event MaxSlippageUpdated(uint128 maxSlippage); - - /** - * @notice Emitted when the stale price time delta is changed - * @param stalePriceTimeDelta The new stale price time delta - */ - event StalePriceTimeDeltaUpdated(uint128 stalePriceTimeDelta); - - /** - * @notice Emitted when the Balancer pool ID is updated - * @param balancerPoolId The new Balancer pool ID - */ - event BalancerPoolIdUpdated(bytes32 balancerPoolId); - - /** - * @notice Returns the maximum slippage for the exchange - * @return The maximum slippage in bps (1/10,000) - */ - function maxSlippage() external view returns (uint128); - - /** - * @notice Returns the stale price time delta for the exchange - * @return The stale price time delta in seconds - */ - function stalePriceTimeDelta() external view returns (uint128); - - /** - * @notice Returns the Balancer pool ID for the exchange - * @return The Balancer pool ID - */ - function balancerPoolId() external view returns (bytes32); - - /** - * @notice Initializes the xDAI exchange contract. Can only be called once. - * @param initialOwner The address of the initial owner - * @param _maxSlippage The maximum slippage for the exchange in bps (1/10,000) - * @param _stalePriceTimeDelta The stale price time delta for the exchange in seconds - * @param _balancerPoolId The Balancer pool ID for the exchange - */ - function initialize( - address initialOwner, - uint128 _maxSlippage, - uint128 _stalePriceTimeDelta, - bytes32 _balancerPoolId - ) external; - - /** - * @notice Sets the maximum slippage for the exchange. Can only be called by the owner. - * @param newMaxSlippage The new maximum slippage - */ - function setMaxSlippage(uint128 newMaxSlippage) external; - - /** - * @notice Sets the stale price time delta for the exchange. Can only be called by the owner. - * @param newStalePriceTimeDelta The new stale price time delta - */ - function setStalePriceTimeDelta(uint128 newStalePriceTimeDelta) external; - - /** - * @notice Sets the Balancer pool ID for the exchange. Can only be called by the owner. - * @param newBalancerPoolId The new Balancer pool ID - */ - function setBalancerPoolId(bytes32 newBalancerPoolId) external; - - /** - * @notice Swaps xDAI to GNO. The amount of xDAI to swap is determined by the value of msg.value. - * @return assets The amount of GNO received - */ - function swap() external payable returns (uint256 assets); -} diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index bc533d2d..0883a43b 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -12,7 +12,6 @@ library Errors { error InvalidShares(); error InvalidAssets(); error ZeroAddress(); - error InsufficientAssets(); error CapacityExceeded(); error InvalidCapacity(); error InvalidSecurityDeposit(); @@ -50,6 +49,7 @@ library Errors { error MaxOraclesExceeded(); error ExitRequestNotProcessed(); error ValueNotChanged(); - error InvalidQueuedShares(); error FlashLoanFailed(); + error CannotTopUpV1Validators(); + error InvalidSignatures(); } diff --git a/contracts/libraries/ExitQueue.sol b/contracts/libraries/ExitQueue.sol index 39d1a3dc..6e3ec21d 100644 --- a/contracts/libraries/ExitQueue.sol +++ b/contracts/libraries/ExitQueue.sol @@ -108,7 +108,7 @@ library ExitQueue { } if (currTotalTickets > 1 && checkpointAssets == 0 && checkpointIdx + 1 < length) { - // only one checkpoint created in __VaultState_initV3 should pass this if + // only single checkpoint created during V2 -> V3 migration can pass this if checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx + 1); uint256 totalShares = checkpoint.totalTickets - currTotalTickets; return (positionShares, Math.mulDiv(positionShares, checkpoint.exitedAssets, totalShares)); diff --git a/contracts/misc/GnoDaiDistributor.sol b/contracts/misc/GnoDaiDistributor.sol new file mode 100644 index 00000000..dd71d32f --- /dev/null +++ b/contracts/misc/GnoDaiDistributor.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; +import {IGnoDaiDistributor} from '../interfaces/IGnoDaiDistributor.sol'; +import {IMerkleDistributor} from '../interfaces/IMerkleDistributor.sol'; +import {ISavingsXDaiAdapter} from '../interfaces/ISavingsXDaiAdapter.sol'; +import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; +import {Errors} from '../libraries/Errors.sol'; + +/** + * @title GnoDaiDistributor + * @author StakeWise + * @notice Converts xDAI to sDAI and distributes it to the users using Merkle Distributor on Gnosis chain + */ +contract GnoDaiDistributor is ReentrancyGuard, IGnoDaiDistributor { + address private immutable _sDaiToken; + IVaultsRegistry private immutable _vaultsRegistry; + ISavingsXDaiAdapter private immutable _savingsXDaiAdapter; + IMerkleDistributor private immutable _merkleDistributor; + + /** + * @dev Constructor + * @param sDaiToken The address of the sDaiToken contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param savingsXDaiAdapter The address of the SavingsXDaiAdapter contract + */ + constructor( + address sDaiToken, + address vaultsRegistry, + address savingsXDaiAdapter, + address merkleDistributor + ) ReentrancyGuard() { + _sDaiToken = sDaiToken; + _vaultsRegistry = IVaultsRegistry(vaultsRegistry); + _savingsXDaiAdapter = ISavingsXDaiAdapter(savingsXDaiAdapter); + _merkleDistributor = IMerkleDistributor(merkleDistributor); + IERC20(sDaiToken).approve(merkleDistributor, type(uint256).max); + } + + /// @inheritdoc IGnoDaiDistributor + function distributeSDai() external payable nonReentrant { + // can be called only by vaults + if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); + + // convert xDAI to sDAI + uint256 sDaiAmount = _savingsXDaiAdapter.depositXDAI{value: msg.value}(address(this)); + if (sDaiAmount == 0) revert Errors.InvalidAssets(); + + // distribute tokens to vault users + _merkleDistributor.distributeOneTime(_sDaiToken, sDaiAmount, '', abi.encode(msg.sender)); + + // emit event + emit SDaiDistributed(msg.sender, sDaiAmount); + } +} diff --git a/contracts/misc/XdaiExchange.sol b/contracts/misc/XdaiExchange.sol deleted file mode 100644 index bdf9cc87..00000000 --- a/contracts/misc/XdaiExchange.sol +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {UUPSUpgradeable} from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; -import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; -import {Ownable2StepUpgradeable} from '@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol'; -import {IXdaiExchange} from '../interfaces/IXdaiExchange.sol'; -import {IBalancerVault} from '../interfaces/IBalancerVault.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {IChainlinkV3Aggregator} from '../interfaces/IChainlinkV3Aggregator.sol'; -import {Errors} from '../libraries/Errors.sol'; - -/** - * @title XdaiExchange - * @author StakeWise - * @notice Defines the xDAI to GNO exchange functionality - */ -contract XdaiExchange is - Initializable, - ReentrancyGuardUpgradeable, - Ownable2StepUpgradeable, - UUPSUpgradeable, - IXdaiExchange -{ - error InvalidSlippage(); - error PriceFeedError(); - - uint256 private constant _maxPercent = 10_000; // @dev 100.00 % - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _gnoToken; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IChainlinkV3Aggregator private immutable _daiPriceFeed; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IChainlinkV3Aggregator private immutable _gnoPriceFeed; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IBalancerVault private immutable _balancerVault; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IVaultsRegistry private immutable _vaultsRegistry; - - /// @inheritdoc IXdaiExchange - bytes32 public override balancerPoolId; - - /// @inheritdoc IXdaiExchange - uint128 public override maxSlippage; - - /// @inheritdoc IXdaiExchange - uint128 public override stalePriceTimeDelta; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param gnoToken The address of the GNO token - * @param balancerVault The address of the Balancer Vault - * @param vaultsRegistry The address of the Vaults Registry - * @param daiPriceFeed The address of the DAI <-> USD price feed - * @param gnoPriceFeed The address of the GNO <-> USD price feed - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address gnoToken, - address balancerVault, - address vaultsRegistry, - address daiPriceFeed, - address gnoPriceFeed - ) { - _gnoToken = gnoToken; - _balancerVault = IBalancerVault(balancerVault); - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - _daiPriceFeed = IChainlinkV3Aggregator(daiPriceFeed); - _gnoPriceFeed = IChainlinkV3Aggregator(gnoPriceFeed); - _disableInitializers(); - } - - /// @inheritdoc IXdaiExchange - function initialize( - address initialOwner, - uint128 _maxSlippage, - uint128 _stalePriceTimeDelta, - bytes32 _balancerPoolId - ) external override initializer { - __ReentrancyGuard_init(); - __Ownable_init(initialOwner); - _setMaxSlippage(_maxSlippage); - _setStalePriceTimeDelta(_stalePriceTimeDelta); - _setBalancerPoolId(_balancerPoolId); - } - - /// @inheritdoc IXdaiExchange - function setMaxSlippage(uint128 newMaxSlippage) external override onlyOwner { - _setMaxSlippage(newMaxSlippage); - } - - /// @inheritdoc IXdaiExchange - function setStalePriceTimeDelta(uint128 newStalePriceTimeDelta) external override onlyOwner { - _setStalePriceTimeDelta(newStalePriceTimeDelta); - } - - /// @inheritdoc IXdaiExchange - function setBalancerPoolId(bytes32 newBalancerPoolId) external override onlyOwner { - _setBalancerPoolId(newBalancerPoolId); - } - - /// @inheritdoc IXdaiExchange - function swap() external payable nonReentrant returns (uint256 assets) { - if (msg.value == 0) revert Errors.InvalidAssets(); - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); - - // SLOAD to memory - uint256 _maxSlippage = maxSlippage; - uint256 _stalePriceTimeDelta = stalePriceTimeDelta; - - // fetch prices from oracles - (, int256 answer, , uint256 updatedAt, ) = _daiPriceFeed.latestRoundData(); - if (answer <= 0 || block.timestamp - updatedAt > _stalePriceTimeDelta) revert PriceFeedError(); - uint256 daiUsdPrice = uint256(answer); - - (, answer, , updatedAt, ) = _gnoPriceFeed.latestRoundData(); - if (answer <= 0 || block.timestamp - updatedAt > _stalePriceTimeDelta) revert PriceFeedError(); - uint256 gnoUsdPrice = uint256(answer); - - // calculate xDAI <-> GNO exchange rate from the price feeds - uint256 limit = Math.mulDiv(msg.value, daiUsdPrice, gnoUsdPrice); - - // apply slippage - limit = Math.mulDiv(limit, _maxPercent - _maxSlippage, _maxPercent); - - // define balancer swap - IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap({ - poolId: balancerPoolId, - kind: IBalancerVault.SwapKind.GIVEN_IN, - assetIn: address(0), - assetOut: _gnoToken, - amount: msg.value, - userData: '' - }); - - // define balancer funds - IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({ - sender: address(this), - fromInternalBalance: false, - recipient: payable(msg.sender), - toInternalBalance: false - }); - - // swap xDAI to GNO - assets = _balancerVault.swap{value: msg.value}(singleSwap, funds, limit, block.timestamp); - } - - /** - * @dev Internal function to set the maximum slippage for the exchange - * @param newMaxSlippage The new maximum slippage - */ - function _setMaxSlippage(uint128 newMaxSlippage) private { - if (newMaxSlippage >= _maxPercent) revert InvalidSlippage(); - maxSlippage = newMaxSlippage; - emit MaxSlippageUpdated(newMaxSlippage); - } - - /** - * @dev Internal function to set the stale price time delta for the exchange - * @param newStalePriceTimeDelta The new stale price time delta - */ - function _setStalePriceTimeDelta(uint128 newStalePriceTimeDelta) private { - stalePriceTimeDelta = newStalePriceTimeDelta; - emit StalePriceTimeDeltaUpdated(newStalePriceTimeDelta); - } - - /** - * @dev Internal function to set the Balancer pool ID for the exchange - * @param newBalancerPoolId The new Balancer pool ID - */ - function _setBalancerPoolId(bytes32 newBalancerPoolId) private { - balancerPoolId = newBalancerPoolId; - emit BalancerPoolIdUpdated(newBalancerPoolId); - } - - /// @inheritdoc UUPSUpgradeable - function _authorizeUpgrade(address) internal override onlyOwner {} -} diff --git a/contracts/mocks/BalancerVaultMock.sol b/contracts/mocks/BalancerVaultMock.sol deleted file mode 100644 index 7599e2a2..00000000 --- a/contracts/mocks/BalancerVaultMock.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IBalancerVault} from '../interfaces/IBalancerVault.sol'; - -/** - * @title BalancerVaultMock - * @author StakeWise - * @notice Defines the mock for the Balancer Vault contract - */ -contract BalancerVaultMock is Ownable, IBalancerVault { - using SafeERC20 for IERC20; - - error SwapExpired(); - error InvalidSingleSwap(); - error InvalidFundManagement(); - error LimitExceeded(); - - uint256 private constant _wad = 1e18; - - address private immutable _outputToken; - uint256 public xdaiGnoRate; - - constructor( - address outputToken, - uint256 _xdaiGnoRate, - address _initialOwner - ) Ownable(_initialOwner) { - _outputToken = outputToken; - xdaiGnoRate = _xdaiGnoRate; - } - - function swap( - SingleSwap calldata singleSwap, - FundManagement calldata funds, - uint256 limit, - uint256 deadline - ) external payable returns (uint256 amountOut) { - if (deadline < block.timestamp) { - revert SwapExpired(); - } - - if ( - singleSwap.kind != SwapKind.GIVEN_IN || - singleSwap.assetIn != address(0) || - singleSwap.assetOut != _outputToken - ) { - revert InvalidSingleSwap(); - } - - if (funds.sender != msg.sender || funds.fromInternalBalance || funds.toInternalBalance) { - revert InvalidFundManagement(); - } - - amountOut = (msg.value * xdaiGnoRate) / _wad; - if (amountOut < limit) { - revert LimitExceeded(); - } - IERC20(_outputToken).safeTransfer(funds.recipient, amountOut); - } - - function setXdaiGnoRate(uint256 newRate) external onlyOwner { - xdaiGnoRate = newRate; - } - - function drain() external onlyOwner { - Address.sendValue(payable(msg.sender), address(this).balance); - IERC20(_outputToken).safeTransfer(msg.sender, IERC20(_outputToken).balanceOf(address(this))); - } -} diff --git a/contracts/mocks/DepositorMock.sol b/contracts/mocks/DepositorMock.sol deleted file mode 100644 index 68e170cc..00000000 --- a/contracts/mocks/DepositorMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -error DepositFailed(); - -contract DepositorMock { - address public immutable vault; - - constructor(address _vault) { - vault = _vault; - } - - function depositToVault() public payable { - (bool success, ) = vault.call{value: msg.value}(''); - if (!success) revert DepositFailed(); - } -} diff --git a/contracts/mocks/ERC20Mock.sol b/contracts/mocks/ERC20Mock.sol deleted file mode 100644 index 647176c9..00000000 --- a/contracts/mocks/ERC20Mock.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.22; - -import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; - -contract ERC20Mock is ERC20 { - constructor() ERC20('ERC20Mock', 'E20M') {} - - function mint(address account, uint256 amount) external { - _mint(account, amount); - } - - function burn(address account, uint256 amount) external { - _burn(account, amount); - } -} diff --git a/contracts/mocks/EthPrivVaultV4Mock.sol b/contracts/mocks/EthPrivVaultV4Mock.sol deleted file mode 100644 index bf329fc2..00000000 --- a/contracts/mocks/EthPrivVaultV4Mock.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EthPrivVault} from '../vaults/ethereum/EthPrivVault.sol'; - -contract EthPrivVaultV4Mock is EthPrivVault { - uint128 public newVar; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthPrivVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} - - function initialize(bytes calldata data) external payable virtual override reinitializer(4) { - (newVar) = abi.decode(data, (uint128)); - } - - function somethingNew() external pure returns (bool) { - return true; - } - - function version() public pure virtual override returns (uint8) { - return 4; - } -} diff --git a/contracts/mocks/EthVaultMock.sol b/contracts/mocks/EthVaultMock.sol deleted file mode 100644 index 68ad90f4..00000000 --- a/contracts/mocks/EthVaultMock.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {IEthValidatorsRegistry} from '../interfaces/IEthValidatorsRegistry.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {EthVault} from '../vaults/ethereum/EthVault.sol'; -import {ExitQueue} from '../libraries/ExitQueue.sol'; - -/** - * @title EthVaultMock - * @author StakeWise - * @notice Adds mocked functions to the EthVault contract - */ -contract EthVaultMock is EthVault { - using ExitQueue for ExitQueue.History; - - uint256 private constant _securityDeposit = 1e9; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} - - function getGasCostOfGetExitQueueIndex(uint256 positionTicket) external view returns (uint256) { - uint256 gasBefore = gasleft(); - _exitQueue.getCheckpointIndex(positionTicket); - return gasBefore - gasleft(); - } - - function _setTotalAssets(uint128 value) external { - _totalAssets = value; - } - - function _setTotalShares(uint128 value) external { - _totalShares = value; - } - - function resetSecurityDeposit() external { - _balances[address(this)] -= _securityDeposit; - _totalShares -= SafeCast.toUint128(_securityDeposit); - _totalAssets -= SafeCast.toUint128(_securityDeposit); - _transferVaultAssets(address(0), _securityDeposit); - } -} diff --git a/contracts/mocks/EthVaultV5Mock.sol b/contracts/mocks/EthVaultV5Mock.sol deleted file mode 100644 index bea25d3c..00000000 --- a/contracts/mocks/EthVaultV5Mock.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {EthVault} from '../vaults/ethereum/EthVault.sol'; - -contract EthVaultV5Mock is EthVault { - uint128 public newVar; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} - - function initialize(bytes calldata data) external payable virtual override reinitializer(5) { - (newVar) = abi.decode(data, (uint128)); - } - - function somethingNew() external pure returns (bool) { - return true; - } - - function version() public pure virtual override returns (uint8) { - return 5; - } -} diff --git a/contracts/mocks/EthVaultV6Mock.sol b/contracts/mocks/EthVaultV6Mock.sol index 7039ee52..c5b12554 100644 --- a/contracts/mocks/EthVaultV6Mock.sol +++ b/contracts/mocks/EthVaultV6Mock.sol @@ -2,35 +2,21 @@ pragma solidity ^0.8.22; -import {EthVaultV5Mock} from './EthVaultV5Mock.sol'; +import {EthVault, IEthVault} from '../vaults/ethereum/EthVault.sol'; + +contract EthVaultV6Mock is EthVault { + uint128 public newVar; -contract EthVaultV6Mock is EthVaultV5Mock { /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthVaultV5Mock( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} + constructor(IEthVault.EthVaultConstructorArgs memory args) EthVault(args) {} + + function initialize(bytes calldata data) external payable virtual override reinitializer(6) { + (newVar) = abi.decode(data, (uint128)); + } - function initialize(bytes calldata data) external payable override reinitializer(6) {} + function somethingNew() external pure returns (bool) { + return true; + } function version() public pure virtual override returns (uint8) { return 6; diff --git a/contracts/mocks/EthVaultV7Mock.sol b/contracts/mocks/EthVaultV7Mock.sol new file mode 100644 index 00000000..2d875606 --- /dev/null +++ b/contracts/mocks/EthVaultV7Mock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IEthVault} from '../interfaces/IEthVault.sol'; +import {EthVaultV6Mock} from './EthVaultV6Mock.sol'; + +contract EthVaultV7Mock is EthVaultV6Mock { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(IEthVault.EthVaultConstructorArgs memory args) EthVaultV6Mock(args) {} + + function initialize(bytes calldata data) external payable override reinitializer(7) {} + + function version() public pure virtual override returns (uint8) { + return 7; + } +} diff --git a/contracts/mocks/LegacyRewardTokenMock.sol b/contracts/mocks/LegacyRewardTokenMock.sol deleted file mode 100644 index 9b22821b..00000000 --- a/contracts/mocks/LegacyRewardTokenMock.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -pragma solidity ^0.8.22; - -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IEthGenesisVault} from '../interfaces/IEthGenesisVault.sol'; - -contract LegacyRewardTokenMock { - address public vault; - uint256 public totalStaked; - uint256 public totalRewards; - uint256 public totalPenalty; - - function setVault(address _vault) external { - vault = _vault; - } - - function totalAssets() public view returns (uint256) { - return totalStaked + totalRewards; - } - - function setTotalStaked(uint256 _totalStaked) external { - totalStaked = _totalStaked; - } - - function setTotalPenalty(uint256 _totalPenalty) external { - totalPenalty = _totalPenalty; - } - - function setTotalRewards(uint256 _totalRewards) external { - totalRewards = _totalRewards; - } - - function updateTotalRewards(int256 rewardsDelta) external { - if (rewardsDelta > 0) { - totalRewards += uint256(rewardsDelta); - } else { - totalPenalty += uint256(-rewardsDelta); - } - } - - function migrate(address receiver, uint256 principal, uint256 reward) external { - uint256 assets = principal + reward; - - uint256 _totalPenalty = totalPenalty; // gas savings - if (_totalPenalty > 0) { - uint256 _totalAssets = totalAssets(); // gas savings - // apply penalty to assets - uint256 assetsAfterPenalty = Math.mulDiv(assets, _totalAssets - _totalPenalty, _totalAssets); - totalPenalty = _totalPenalty + assetsAfterPenalty - assets; - assets = assetsAfterPenalty; - } - IEthGenesisVault(vault).migrate(receiver, assets); - } -} diff --git a/contracts/mocks/MulticallMock.sol b/contracts/mocks/MulticallMock.sol index b0614a54..4ea24ea8 100644 --- a/contracts/mocks/MulticallMock.sol +++ b/contracts/mocks/MulticallMock.sol @@ -1,36 +1,56 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -/// @dev Copied from https://github.com/mds1/multicall/blob/main/src/Multicall3.sol -contract MulticallMock { - struct Call { - address target; - bool isPayable; - bytes callData; - } - - /// @notice Backwards-compatible call aggregation with Multicall - /// @param calls An array of Call structs - /// @return blockNumber The block number where the calls were executed - /// @return returnData An array of bytes containing the responses - function aggregate( - Call[] calldata calls - ) public payable returns (uint256 blockNumber, bytes[] memory returnData) { - blockNumber = block.number; - uint256 length = calls.length; - returnData = new bytes[](length); - Call calldata call; - for (uint256 i = 0; i < length; i++) { - bool success; - call = calls[i]; - if (call.isPayable) { - (success, returnData[i]) = call.target.call{value: msg.value}(call.callData); - } else { - (success, returnData[i]) = call.target.call(call.callData); - } - require(success, 'Multicall3: call failed'); - } - } - - receive() external payable {} +import {Test} from 'forge-std/Test.sol'; +import {Multicall} from '../base/Multicall.sol'; + +contract MulticallMock is Multicall { + uint256 public value; + string public message; + bool public flag; + address public caller; + + function setValue(uint256 _value) external returns (uint256) { + value = _value; + return value; + } + + function setMessage(string calldata _message) external returns (string memory) { + message = _message; + return message; + } + + function setFlag(bool _flag) external returns (bool) { + flag = _flag; + return flag; + } + + function revertWithMessage() external pure { + revert('Intentional revert with message'); + } + + function revertWithoutMessage() external pure { + revert(); + } + + function multipleParams( + uint256 a, + string calldata b, + bool c + ) external returns (uint256, string memory, bool) { + value = a; + message = b; + flag = c; + return (a, b, c); + } + + function checkCaller() external returns (address) { + caller = msg.sender; + return caller; + } + + function addToValue(uint256 amount) external returns (uint256) { + value += amount; + return value; + } } diff --git a/contracts/mocks/OsTokenVaultEscrowAuthMock.sol b/contracts/mocks/OsTokenVaultEscrowAuthMock.sol deleted file mode 100644 index 1f3e0c89..00000000 --- a/contracts/mocks/OsTokenVaultEscrowAuthMock.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IOsTokenVaultEscrowAuth} from '../interfaces/IOsTokenVaultEscrowAuth.sol'; - -/** - * @title OsTokenVaultEscrowAuthMock - * @author StakeWise - * @notice Mocks the OsTokenVaultEscrowAuth contract for testing purposes - */ -contract OsTokenVaultEscrowAuthMock is Ownable, IOsTokenVaultEscrowAuth { - mapping(address => bool) public _canRegister; - - constructor(address _owner) Ownable(_owner) {} - - function setCanRegister(address user, bool canRegister_) external onlyOwner { - _canRegister[user] = canRegister_; - } - - /// @inheritdoc IOsTokenVaultEscrowAuth - function canRegister( - address, - address owner, - uint256, - uint256 - ) external view override returns (bool) { - return _canRegister[owner]; - } -} diff --git a/contracts/mocks/PoolEscrowMock.sol b/contracts/mocks/PoolEscrowMock.sol deleted file mode 100644 index 66e8fb4f..00000000 --- a/contracts/mocks/PoolEscrowMock.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -pragma solidity ^0.8.22; - -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IGnoPoolEscrow} from '../interfaces/IGnoPoolEscrow.sol'; - -/** - * @title PoolEscrowMock - * - * @dev PoolEscrow contract is used to receive transfers from ETH2 system contract for the pool validators. - * The withdrawal credentials of the Pool must be set to - * https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.2/specs/phase0/validator.md#eth1_address_withdrawal_prefix - * using the address of this contract as a destination. - */ -contract PoolEscrowMock is IGnoPoolEscrow { - using Address for address payable; - using SafeERC20 for IERC20; - - // @dev The address of the current contract owner. - address public override owner; - - // @dev The address the ownership is planned to be transferred to. - address public override futureOwner; - - /** - * @dev Constructor for initializing the PoolEscrow contract. - * @param _owner - address of the contract owner. - */ - constructor(address _owner) { - owner = _owner; - emit OwnershipTransferApplied(address(0), _owner); - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(owner == msg.sender, 'PoolEscrow: caller is not the owner'); - _; - } - - /** - * @dev See {IPoolEscrow-commitOwnershipTransfer}. - */ - function commitOwnershipTransfer(address newOwner) external override onlyOwner { - // can be zero address to reset incorrect future owner - futureOwner = newOwner; - emit OwnershipTransferCommitted(msg.sender, newOwner); - } - - /** - * @dev See {IPoolEscrow-applyOwnershipTransfer}. - */ - function applyOwnershipTransfer() external override { - address newOwner = futureOwner; - require(newOwner == msg.sender, 'PoolEscrow: caller is not the future owner'); - - emit OwnershipTransferApplied(owner, newOwner); - (owner, futureOwner) = (newOwner, address(0)); - } - - /** - * @dev See {IPoolEscrow-withdraw}. - */ - function withdraw(address payable payee, uint256 amount) external override onlyOwner { - require(payee != address(0), 'PoolEscrow: payee is the zero address'); - emit Withdrawn(msg.sender, payee, amount); - payee.sendValue(amount); - } - - /** - * @dev See {IPoolEscrow-withdraw}. - */ - function withdrawTokens( - address token, - address payee, - uint256 amount - ) external override onlyOwner { - require(payee != address(0), 'PoolEscrow: payee is the zero address'); - require(token != address(0), 'PoolEscrow: token is the zero address'); - emit Withdrawn(msg.sender, payee, amount); - IERC20(token).safeTransfer(payee, amount); - } - - /** - * @dev Function for receiving withdrawals from ETH2 system contract. - */ - receive() external payable {} -} diff --git a/contracts/mocks/PriceFeedMock.sol b/contracts/mocks/PriceFeedMock.sol deleted file mode 100644 index e777d319..00000000 --- a/contracts/mocks/PriceFeedMock.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol'; -import {IChainlinkV3Aggregator} from '../interfaces/IChainlinkV3Aggregator.sol'; -import {IBalancerRateProvider} from '../interfaces/IBalancerRateProvider.sol'; - -/** - * @title PriceFeed - * @author StakeWise - * @notice Price feed mock - */ -contract PriceFeedMock is - Ownable, - IBalancerRateProvider, - IChainlinkAggregator, - IChainlinkV3Aggregator -{ - /// @inheritdoc IChainlinkV3Aggregator - uint256 public constant override version = 0; - - /// @inheritdoc IChainlinkV3Aggregator - string public override description; - - int256 private _latestAnswer; - uint256 private _latestTimestamp; - - /** - * @dev Constructor - * @param _description The description of the price feed - */ - constructor(string memory _description) Ownable(msg.sender) { - description = _description; - } - - /// @inheritdoc IBalancerRateProvider - function getRate() public view override returns (uint256) { - return SafeCast.toUint256(latestAnswer()); - } - - function setLatestAnswer(int256 latestAnswer_) external onlyOwner { - _latestAnswer = latestAnswer_; - } - - function setLatestTimestamp(uint256 latestTimestamp_) external onlyOwner { - _latestTimestamp = latestTimestamp_; - } - - /// @inheritdoc IChainlinkAggregator - function latestAnswer() public view override returns (int256) { - return _latestAnswer; - } - - /// @inheritdoc IChainlinkAggregator - function latestTimestamp() external view returns (uint256) { - return block.timestamp; - } - - /// @inheritdoc IChainlinkV3Aggregator - function decimals() public pure returns (uint8) { - return 18; - } - - /// @inheritdoc IChainlinkV3Aggregator - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return (0, latestAnswer(), _latestTimestamp, _latestTimestamp, 0); - } -} diff --git a/contracts/mocks/UnknownVaultMock.sol b/contracts/mocks/UnknownVaultMock.sol deleted file mode 100644 index 9e18cd89..00000000 --- a/contracts/mocks/UnknownVaultMock.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; - -contract UnknownVaultMock { - IOsTokenVaultController private immutable _osTokenVaultController; - address private immutable _implementation; - - constructor(IOsTokenVaultController osTokenVaultController, address implementation_) { - _osTokenVaultController = osTokenVaultController; - _implementation = implementation_; - } - - function mintOsToken(address account, uint256 amount) external { - _osTokenVaultController.mintShares(account, amount); - } - - function burnOsToken(uint256 amount) external { - _osTokenVaultController.burnShares(msg.sender, amount); - } - - function implementation() external view returns (address) { - return _implementation; - } -} diff --git a/contracts/mocks/ValidatorsConsolidationsMock.sol b/contracts/mocks/ValidatorsConsolidationsMock.sol new file mode 100644 index 00000000..e8394b49 --- /dev/null +++ b/contracts/mocks/ValidatorsConsolidationsMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity ^0.8.22; + +contract ValidatorsConsolidationsMock { + error InvalidFeeError(); + + event ValidatorConsolidated(bytes fromPubkey, bytes toPubkey); + + uint256 private constant _fee = 0.1 ether; + + fallback(bytes calldata input) external payable returns (bytes memory output) { + if (input.length == 0) { + return abi.encode(_fee); + } + if (msg.value != _fee) { + revert InvalidFeeError(); + } + + emit ValidatorConsolidated(input[:48], input[48:96]); + return ''; + } +} diff --git a/contracts/mocks/ValidatorsWithdrawalsMock.sol b/contracts/mocks/ValidatorsWithdrawalsMock.sol new file mode 100644 index 00000000..40b3121f --- /dev/null +++ b/contracts/mocks/ValidatorsWithdrawalsMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity ^0.8.22; + +contract ValidatorsWithdrawalsMock { + error InvalidFeeError(); + + event ValidatorWithdrawn(address sender, bytes fromPubkey, uint64 amount); + + uint256 private constant _fee = 0.1 ether; + + fallback(bytes calldata input) external payable returns (bytes memory output) { + if (input.length == 0) { + return abi.encode(_fee); + } + if (msg.value != _fee) { + revert InvalidFeeError(); + } + + emit ValidatorWithdrawn(msg.sender, input[:48], uint64(bytes8(input[48:56]))); + return ''; + } +} diff --git a/contracts/mocks/XdaiExchangeV2Mock.sol b/contracts/mocks/XdaiExchangeV2Mock.sol deleted file mode 100644 index 1788c7af..00000000 --- a/contracts/mocks/XdaiExchangeV2Mock.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {XdaiExchange} from '../misc/XdaiExchange.sol'; - -contract XdaiExchangeV2Mock is XdaiExchange { - uint256 public newVar; - - constructor( - address gnoToken, - address balancerVault, - address vaultsRegistry, - address daiPriceFeed, - address gnoPriceFeed - ) XdaiExchange(gnoToken, balancerVault, vaultsRegistry, daiPriceFeed, gnoPriceFeed) {} - - function initializeV2(address initialOwner) external reinitializer(2) {} -} diff --git a/contracts/validators/ConsolidationsChecker.sol b/contracts/validators/ConsolidationsChecker.sol new file mode 100644 index 00000000..6ae24b37 --- /dev/null +++ b/contracts/validators/ConsolidationsChecker.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; +import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; +import {IConsolidationsChecker} from '../interfaces/IConsolidationsChecker.sol'; +import {Errors} from '../libraries/Errors.sol'; +import {IKeeper} from '../interfaces/IKeeper.sol'; + +/** + * @title ConsolidationsChecker + * @author StakeWise + * @notice Defines the functionality for checking signatures of oracles for validators consolidations + */ +contract ConsolidationsChecker is EIP712, IConsolidationsChecker { + uint256 private constant _signatureLength = 65; + bytes32 private constant _consolidationsCheckerTypeHash = + keccak256('ConsolidationsChecker(address vault,bytes validators)'); + + IKeeper private immutable _keeper; + + /** + * @dev Constructor + * @param keeper The address of the Keeper contract + */ + constructor(address keeper) EIP712('ConsolidationsChecker', '1') { + _keeper = IKeeper(keeper); + } + + /// @inheritdoc IConsolidationsChecker + function verifySignatures( + address vault, + bytes calldata validators, + bytes calldata signatures + ) external view override { + if (!isValidSignatures(vault, validators, signatures)) { + revert Errors.InvalidSignatures(); + } + } + + /// @inheritdoc IConsolidationsChecker + function isValidSignatures( + address vault, + bytes calldata validators, + bytes calldata signatures + ) public view override returns (bool) { + return + _isValidSignatures( + _keeper.validatorsMinOracles(), + keccak256(abi.encode(_consolidationsCheckerTypeHash, vault, keccak256(validators))), + signatures + ); + } + + /** + * @notice Internal function for verifying oracles' signatures + * @param requiredSignatures The number of signatures required for the verification to pass + * @param message The message that was signed + * @param signatures The concatenation of the oracles' signatures + * @return True if the signatures are valid, otherwise false + */ + function _isValidSignatures( + uint256 requiredSignatures, + bytes32 message, + bytes calldata signatures + ) private view returns (bool) { + if (requiredSignatures == 0) { + return false; + } + + // check whether enough signatures + unchecked { + // cannot realistically overflow + if (signatures.length < requiredSignatures * _signatureLength) { + return false; + } + } + + bytes32 data = _hashTypedDataV4(message); + address lastOracle; + address currentOracle; + uint256 startIndex; + for (uint256 i = 0; i < requiredSignatures; i++) { + unchecked { + // cannot overflow as signatures.length is checked above + currentOracle = ECDSA.recover(data, signatures[startIndex:startIndex + _signatureLength]); + } + // signatures must be sorted by oracles' addresses and not repeat + if (currentOracle <= lastOracle || !_keeper.isOracle(currentOracle)) { + return false; + } + + // update last oracle + lastOracle = currentOracle; + + unchecked { + // cannot realistically overflow + startIndex += _signatureLength; + } + } + + return true; + } +} diff --git a/contracts/validators/DepositDataRegistry.sol b/contracts/validators/DepositDataRegistry.sol index 89e3355d..5243a527 100644 --- a/contracts/validators/DepositDataRegistry.sol +++ b/contracts/validators/DepositDataRegistry.sol @@ -135,18 +135,17 @@ contract DepositDataRegistry is Multicall, IDepositDataRegistry { // SLOAD to memory uint256 currentIndex = depositDataIndexes[vault]; - bytes32 depositDataRoot = depositDataRoots[vault]; // define leaves for multiproof uint256 validatorsCount = indexes.length; if (validatorsCount == 0) revert Errors.InvalidValidators(); - bytes32[] memory leaves = new bytes32[](validatorsCount); // calculate validator length uint256 validatorLength = keeperParams.validators.length / validatorsCount; if (validatorLength == 0) revert Errors.InvalidValidators(); // calculate leaves + bytes32[] memory leaves = new bytes32[](validatorsCount); { uint256 startIndex; uint256 endIndex; @@ -167,13 +166,14 @@ contract DepositDataRegistry is Multicall, IDepositDataRegistry { } } + // increment index for the next validator + depositDataIndexes[vault] = currentIndex; + // check matches merkle root and next validator index + bytes32 depositDataRoot = depositDataRoots[vault]; if (!MerkleProof.multiProofVerifyCalldata(proof, proofFlags, depositDataRoot, leaves)) { revert Errors.InvalidProof(); } - - // increment index for the next validator - depositDataIndexes[vault] = currentIndex; } /// @inheritdoc IDepositDataRegistry diff --git a/contracts/validators/ValidatorsChecker.sol b/contracts/validators/ValidatorsChecker.sol index e4c12841..84de72aa 100644 --- a/contracts/validators/ValidatorsChecker.sol +++ b/contracts/validators/ValidatorsChecker.sol @@ -95,33 +95,27 @@ abstract contract ValidatorsChecker is IValidatorsChecker { /// @inheritdoc IValidatorsChecker function checkDepositDataRoot( - address vault, - bytes32 validatorsRegistryRoot, - bytes calldata validators, - bytes32[] calldata proof, - bool[] calldata proofFlags, - uint256[] calldata proofIndexes + DepositDataRootCheckParams calldata params ) external view override returns (uint256 blockNumber, Status status) { - if (_validatorsRegistry.get_deposit_root() != validatorsRegistryRoot) { + if (_validatorsRegistry.get_deposit_root() != params.validatorsRegistryRoot) { return (block.number, Status.INVALID_VALIDATORS_REGISTRY_ROOT); } - if (!_vaultsRegistry.vaults(vault)) { + if (!_vaultsRegistry.vaults(params.vault)) { return (block.number, Status.INVALID_VAULT); } // verify vault has enough assets if ( - !_keeper.isCollateralized(vault) && IVaultState(vault).withdrawableAssets() < _depositAmount() + !_keeper.isCollateralized(params.vault) && + IVaultState(params.vault).withdrawableAssets() < _depositAmount() ) { return (block.number, Status.INSUFFICIENT_ASSETS); } - uint8 vaultVersion = IVaultVersion(vault).version(); + uint8 vaultVersion = IVaultVersion(params.vault).version(); if (vaultVersion >= 2) { - address validatorsManager = IVaultValidators(vault).validatorsManager(); - // verify vault did not set custom validators manager - if (validatorsManager != address(_depositDataRegistry)) { + if (IVaultValidators(params.vault).validatorsManager() != address(_depositDataRegistry)) { return (block.number, Status.INVALID_VALIDATORS_MANAGER); } } @@ -130,34 +124,34 @@ abstract contract ValidatorsChecker is IValidatorsChecker { bytes32 depositDataRoot; if (vaultVersion >= 2) { - currentIndex = _depositDataRegistry.depositDataIndexes(vault); - depositDataRoot = _depositDataRegistry.depositDataRoots(vault); + currentIndex = _depositDataRegistry.depositDataIndexes(params.vault); + depositDataRoot = _depositDataRegistry.depositDataRoots(params.vault); } else { - currentIndex = IVaultValidatorsV1(vault).validatorIndex(); - depositDataRoot = IVaultValidatorsV1(vault).validatorsRoot(); + currentIndex = IVaultValidatorsV1(params.vault).validatorIndex(); + depositDataRoot = IVaultValidatorsV1(params.vault).validatorsRoot(); } // define leaves for multiproof - uint256 validatorsCount = proofIndexes.length; + uint256 validatorsCount = params.proofIndexes.length; if (validatorsCount == 0) { return (block.number, Status.INVALID_VALIDATORS_COUNT); } - bytes32[] memory leaves = new bytes32[](validatorsCount); // calculate validator length - uint256 validatorLength = validators.length / validatorsCount; - if (validatorLength == 0 || validatorsCount * validatorLength != validators.length) { + uint256 validatorLength = params.validators.length / params.proofIndexes.length; + if (validatorLength == 0 || params.validators.length % validatorLength != 0) { return (block.number, Status.INVALID_VALIDATORS_LENGTH); } // calculate leaves + bytes32[] memory leaves = new bytes32[](validatorsCount); { uint256 startIndex; uint256 endIndex; for (uint256 i = 0; i < validatorsCount; ) { endIndex += validatorLength; - leaves[proofIndexes[i]] = keccak256( - bytes.concat(keccak256(abi.encode(validators[startIndex:endIndex], currentIndex))) + leaves[params.proofIndexes[i]] = keccak256( + bytes.concat(keccak256(abi.encode(params.validators[startIndex:endIndex], currentIndex))) ); startIndex = endIndex; @@ -170,7 +164,14 @@ abstract contract ValidatorsChecker is IValidatorsChecker { } // check matches merkle root and next validator index - if (!MerkleProof.multiProofVerifyCalldata(proof, proofFlags, depositDataRoot, leaves)) { + if ( + !MerkleProof.multiProofVerifyCalldata( + params.proof, + params.proofFlags, + depositDataRoot, + leaves + ) + ) { return (block.number, Status.INVALID_PROOF); } @@ -181,7 +182,7 @@ abstract contract ValidatorsChecker is IValidatorsChecker { * @notice Get the hash to be signed by the validators manager * @param vault The address of the vault * @param validatorsRegistryRoot The validators registry root - * @param validators The concatenation of the validators' public key, deposit signature, deposit root and optionally withdrawal address + * @param validators The concatenation of the validators' public key, deposit signature, deposit root * @return The hash to be signed by the validators manager */ function _getValidatorsManagerMessageHash( diff --git a/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol b/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol index 42e522b6..37d38873 100644 --- a/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol +++ b/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol @@ -24,53 +24,26 @@ contract EthBlocklistErc20Vault is IEthBlocklistErc20Vault { // slither-disable-next-line shadowing-state - uint8 private constant _version = 4; + uint8 private constant _version = 5; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthErc20Vault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} + constructor(EthErc20VaultConstructorArgs memory args) EthErc20Vault(args) { + _disableInitializers(); + } /// @inheritdoc IEthErc20Vault function initialize( bytes calldata params ) external payable virtual override(IEthErc20Vault, EthErc20Vault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 + // if admin is already set, it's an upgrade from version 4 to 5 if (admin != address(0)) { + __EthErc20Vault_upgrade(); return; } diff --git a/contracts/vaults/ethereum/EthBlocklistVault.sol b/contracts/vaults/ethereum/EthBlocklistVault.sol index c6b1c2cc..a656eec5 100644 --- a/contracts/vaults/ethereum/EthBlocklistVault.sol +++ b/contracts/vaults/ethereum/EthBlocklistVault.sol @@ -18,53 +18,26 @@ import {EthVault, IEthVault} from './EthVault.sol'; */ contract EthBlocklistVault is Initializable, EthVault, VaultBlocklist, IEthBlocklistVault { // slither-disable-next-line shadowing-state - uint8 private constant _version = 4; + uint8 private constant _version = 5; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} + constructor(EthVaultConstructorArgs memory args) EthVault(args) { + _disableInitializers(); + } /// @inheritdoc IEthVault function initialize( bytes calldata params ) external payable virtual override(IEthVault, EthVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 + // if admin is already set, it's an upgrade from version 4 to 5 if (admin != address(0)) { + __EthVault_upgrade(); return; } diff --git a/contracts/vaults/ethereum/EthErc20Vault.sol b/contracts/vaults/ethereum/EthErc20Vault.sol index 643806f4..9533b953 100644 --- a/contracts/vaults/ethereum/EthErc20Vault.sol +++ b/contracts/vaults/ethereum/EthErc20Vault.sol @@ -7,6 +7,7 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {IEthErc20Vault} from '../../interfaces/IEthErc20Vault.sol'; import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; +import {Errors} from '../../libraries/Errors.sol'; import {Multicall} from '../../base/Multicall.sol'; import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; import {VaultValidators} from '../modules/VaultValidators.sol'; @@ -42,39 +43,29 @@ contract EthErc20Vault is Multicall, IEthErc20Vault { - uint8 private constant _version = 4; + uint8 private constant _version = 5; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay + EthErc20VaultConstructorArgs memory args ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) - VaultEnterExit(exitingAssetsClaimDelay) - VaultOsToken(osTokenVaultController, osTokenConfig, osTokenVaultEscrow) - VaultMev(sharedMevEscrow) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) { _disableInitializers(); } @@ -83,8 +74,9 @@ contract EthErc20Vault is function initialize( bytes calldata params ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 + // if admin is already set, it's an upgrade from version 4 to 5 if (admin != address(0)) { + __EthErc20Vault_upgrade(); return; } @@ -188,6 +180,29 @@ contract EthErc20Vault is super._burnShares(owner, shares); } + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) internal override { + if ( + !_isValidatorsManager( + validators, + bytes32(validatorsManagerNonce), + validatorsManagerSignature + ) && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /** + * @dev Upgrades the EthErc20Vault contract + */ + function __EthErc20Vault_upgrade() internal { + __VaultValidators_upgrade(); + } + /** * @dev Initializes the EthErc20Vault contract * @param admin The address of the admin of the Vault diff --git a/contracts/vaults/ethereum/EthGenesisVault.sol b/contracts/vaults/ethereum/EthGenesisVault.sol index 2b1c220b..ef245f12 100644 --- a/contracts/vaults/ethereum/EthGenesisVault.sol +++ b/contracts/vaults/ethereum/EthGenesisVault.sol @@ -9,7 +9,6 @@ import {IVaultVersion} from '../../interfaces/IVaultVersion.sol'; import {IEthPoolEscrow} from '../../interfaces/IEthPoolEscrow.sol'; import {IEthGenesisVault} from '../../interfaces/IEthGenesisVault.sol'; import {IRewardEthToken} from '../../interfaces/IRewardEthToken.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; import {Errors} from '../../libraries/Errors.sol'; import {VaultValidators} from '../modules/VaultValidators.sol'; import {VaultEnterExit} from '../modules/VaultEnterExit.sol'; @@ -24,7 +23,7 @@ import {EthVault, IEthVault} from './EthVault.sol'; */ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { // slither-disable-next-line shadowing-state - uint8 private constant _version = 4; + uint8 private constant _version = 5; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IEthPoolEscrow private immutable _poolEscrow; @@ -32,82 +31,32 @@ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IRewardEthToken private immutable _rewardEthToken; - error InvalidInitialHarvest(); - /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param poolEscrow The address of the pool escrow from StakeWise Legacy - * @param rewardEthToken The address of the rETH2 token from StakeWise Legacy - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthVault contract + * @param poolEscrow The address of the pool escrow contract + * @param rewardEthToken The address of the reward ETH token contract */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, + EthVaultConstructorArgs memory args, address poolEscrow, - address rewardEthToken, - uint256 exitingAssetsClaimDelay - ) - EthVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - { + address rewardEthToken + ) EthVault(args) { _poolEscrow = IEthPoolEscrow(poolEscrow); _rewardEthToken = IRewardEthToken(rewardEthToken); } /// @inheritdoc IEthVault function initialize( - bytes calldata params + bytes calldata ) external payable virtual override(IEthVault, EthVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 - if (admin != address(0)) { - return; + if (admin == address(0)) { + revert Errors.UpgradeFailed(); } - - // initialize deployed vault - (address _admin, EthVaultInitParams memory initParams) = abi.decode( - params, - (address, EthVaultInitParams) - ); - // use shared MEV escrow - __EthVault_init(_admin, address(0), initParams); - emit GenesisVaultCreated( - _admin, - initParams.capacity, - initParams.feePercent, - initParams.metadataIpfsHash - ); - } - - /// @inheritdoc IEthGenesisVault - function acceptPoolEscrowOwnership() external override { - _checkAdmin(); - _poolEscrow.applyOwnershipTransfer(); + __EthVault_upgrade(); } /// @inheritdoc IVaultVersion @@ -120,31 +69,6 @@ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { return _version; } - /// @inheritdoc IVaultState - function updateState( - IKeeperRewards.HarvestParams calldata harvestParams - ) public override(IVaultState, VaultState) { - bool isCollateralized = IKeeperRewards(_keeper).isCollateralized(address(this)); - - // process total assets delta since last update - (int256 totalAssetsDelta, bool harvested) = _harvestAssets(harvestParams); - - if (!isCollateralized) { - // it's the first harvest, deduct rewards accumulated so far in legacy pool - totalAssetsDelta -= SafeCast.toInt256(_rewardEthToken.totalRewards()); - // the first state update must be with positive delta - if (_poolEscrow.owner() != address(this) || totalAssetsDelta < 0) { - revert InvalidInitialHarvest(); - } - } - - // process total assets delta - _processTotalAssetsDelta(totalAssetsDelta); - - // update exit queue every time new update is harvested - if (harvested) _updateExitQueue(); - } - /// @inheritdoc IEthGenesisVault function migrate(address receiver, uint256 assets) external override returns (uint256 shares) { if (msg.sender != address(_rewardEthToken) || _poolEscrow.owner() != address(this)) { @@ -205,43 +129,6 @@ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { } } - /// @inheritdoc VaultState - function _processTotalAssetsDelta(int256 totalAssetsDelta) internal override { - // skip processing if there is no change in assets - if (totalAssetsDelta == 0) return; - - // fetch total assets controlled by legacy pool - uint256 legacyPrincipal = _rewardEthToken.totalAssets() - _rewardEthToken.totalPenalty(); - if (legacyPrincipal == 0) { - // legacy pool has no assets, process total assets delta as usual - super._processTotalAssetsDelta(totalAssetsDelta); - return; - } - - // calculate total principal - uint256 totalPrincipal = _totalAssets + legacyPrincipal; - if (totalAssetsDelta < 0) { - // calculate and update penalty for legacy pool - int256 legacyPenalty = SafeCast.toInt256( - Math.mulDiv(uint256(-totalAssetsDelta), legacyPrincipal, totalPrincipal) - ); - _rewardEthToken.updateTotalRewards(-legacyPenalty); - // deduct penalty from total assets delta - totalAssetsDelta += legacyPenalty; - } else { - // calculate and update reward for legacy pool - int256 legacyReward = SafeCast.toInt256( - Math.mulDiv(uint256(totalAssetsDelta), legacyPrincipal, totalPrincipal) - ); - _rewardEthToken.updateTotalRewards(legacyReward); - // deduct reward from total assets delta - totalAssetsDelta -= legacyReward; - } - - // process total assets delta - super._processTotalAssetsDelta(totalAssetsDelta); - } - /// @inheritdoc VaultEnterExit function _transferVaultAssets( address receiver, @@ -266,19 +153,17 @@ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { } /// @inheritdoc VaultValidators - function _registerSingleValidator( - bytes calldata validator - ) internal virtual override(VaultValidators, VaultEthStaking) { - _pullWithdrawals(); - super._registerSingleValidator(validator); - } - - /// @inheritdoc VaultValidators - function _registerMultipleValidators( - bytes calldata validators - ) internal virtual override(VaultValidators, VaultEthStaking) { + function _registerValidator( + bytes calldata validator, + bool isV1Validator + ) + internal + virtual + override(VaultValidators, VaultEthStaking) + returns (uint256 depositAmount, bytes calldata publicKey) + { _pullWithdrawals(); - return super._registerMultipleValidators(validators); + return super._registerValidator(validator, isV1Validator); } /** diff --git a/contracts/vaults/ethereum/EthPrivErc20Vault.sol b/contracts/vaults/ethereum/EthPrivErc20Vault.sol index c1b66888..9f9259f8 100644 --- a/contracts/vaults/ethereum/EthPrivErc20Vault.sol +++ b/contracts/vaults/ethereum/EthPrivErc20Vault.sol @@ -19,53 +19,26 @@ import {EthErc20Vault, IEthErc20Vault} from './EthErc20Vault.sol'; */ contract EthPrivErc20Vault is Initializable, EthErc20Vault, VaultWhitelist, IEthPrivErc20Vault { // slither-disable-next-line shadowing-state - uint8 private constant _version = 4; + uint8 private constant _version = 5; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthErc20Vault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} + constructor(EthErc20VaultConstructorArgs memory args) EthErc20Vault(args) { + _disableInitializers(); + } /// @inheritdoc IEthErc20Vault function initialize( bytes calldata params ) external payable virtual override(IEthErc20Vault, EthErc20Vault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 + // if admin is already set, it's an upgrade from version 4 to 5 if (admin != address(0)) { + __EthErc20Vault_upgrade(); return; } diff --git a/contracts/vaults/ethereum/EthPrivVault.sol b/contracts/vaults/ethereum/EthPrivVault.sol index b8bbf013..206f5180 100644 --- a/contracts/vaults/ethereum/EthPrivVault.sol +++ b/contracts/vaults/ethereum/EthPrivVault.sol @@ -18,53 +18,26 @@ import {EthVault, IEthVault} from './EthVault.sol'; */ contract EthPrivVault is Initializable, EthVault, VaultWhitelist, IEthPrivVault { // slither-disable-next-line shadowing-state - uint8 private constant _version = 4; + uint8 private constant _version = 5; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - EthVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - {} + constructor(EthVaultConstructorArgs memory args) EthVault(args) { + _disableInitializers(); + } /// @inheritdoc IEthVault function initialize( bytes calldata params ) external payable virtual override(IEthVault, EthVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 + // if admin is already set, it's an upgrade from version 4 to 5 if (admin != address(0)) { + __EthVault_upgrade(); return; } diff --git a/contracts/vaults/ethereum/EthVault.sol b/contracts/vaults/ethereum/EthVault.sol index 70f4757a..1f97d18b 100644 --- a/contracts/vaults/ethereum/EthVault.sol +++ b/contracts/vaults/ethereum/EthVault.sol @@ -6,6 +6,7 @@ import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Ini import {IEthVault} from '../../interfaces/IEthVault.sol'; import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; +import {Errors} from '../../libraries/Errors.sol'; import {Multicall} from '../../base/Multicall.sol'; import {VaultValidators} from '../modules/VaultValidators.sol'; import {VaultAdmin} from '../modules/VaultAdmin.sol'; @@ -38,39 +39,29 @@ contract EthVault is Multicall, IEthVault { - uint8 private constant _version = 4; + uint8 private constant _version = 5; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay + EthVaultConstructorArgs memory args ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) - VaultEnterExit(exitingAssetsClaimDelay) - VaultOsToken(osTokenVaultController, osTokenConfig, osTokenVaultEscrow) - VaultMev(sharedMevEscrow) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) { _disableInitializers(); } @@ -79,8 +70,9 @@ contract EthVault is function initialize( bytes calldata params ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 + // if admin is already set, it's an upgrade from version 4 to 5 if (admin != address(0)) { + __EthVault_upgrade(); return; } @@ -136,6 +128,29 @@ contract EthVault is return _version; } + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) internal override { + if ( + !_isValidatorsManager( + validators, + bytes32(validatorsManagerNonce), + validatorsManagerSignature + ) && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /** + * @dev Upgrades the EthVault contract + */ + function __EthVault_upgrade() internal { + __VaultValidators_upgrade(); + } + /** * @dev Initializes the EthVault contract * @param admin The address of the admin of the Vault diff --git a/contracts/vaults/ethereum/custom/EthFoxVault.sol b/contracts/vaults/ethereum/custom/EthFoxVault.sol index 1ebeeee7..0bede682 100644 --- a/contracts/vaults/ethereum/custom/EthFoxVault.sol +++ b/contracts/vaults/ethereum/custom/EthFoxVault.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.22; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {IEthFoxVault} from '../../../interfaces/IEthFoxVault.sol'; +import {Errors} from '../../../libraries/Errors.sol'; import {Multicall} from '../../../base/Multicall.sol'; import {VaultValidators} from '../../modules/VaultValidators.sol'; import {VaultAdmin} from '../../modules/VaultAdmin.sol'; @@ -42,24 +43,36 @@ contract EthFoxVault is * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations * @param sharedMevEscrow The address of the shared MEV escrow * @param depositDataRegistry The address of the DepositDataRegistry contract * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, + address keeper, + address vaultsRegistry, + address validatorsRegistry, + address validatorsWithdrawals, + address validatorsConsolidations, + address consolidationsChecker, address sharedMevEscrow, address depositDataRegistry, uint256 exitingAssetsClaimDelay ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) + VaultImmutables(keeper, vaultsRegistry) + VaultValidators( + depositDataRegistry, + validatorsRegistry, + validatorsWithdrawals, + validatorsConsolidations, + consolidationsChecker + ) VaultEnterExit(exitingAssetsClaimDelay) VaultMev(sharedMevEscrow) { @@ -67,24 +80,11 @@ contract EthFoxVault is } /// @inheritdoc IEthFoxVault - function initialize( - bytes calldata params - ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade - if (admin != address(0)) { - __EthFoxVault_initV2(); - return; + function initialize(bytes calldata) external payable virtual override reinitializer(_version) { + if (admin == address(0)) { + revert Errors.UpgradeFailed(); } - // initialize deployed vault - EthFoxVaultInitParams memory initParams = abi.decode(params, (EthFoxVaultInitParams)); - __EthFoxVault_init(initParams); - emit EthFoxVaultCreated( - initParams.admin, - initParams.ownMevEscrow, - initParams.capacity, - initParams.feePercent, - initParams.metadataIpfsHash - ); + __VaultValidators_upgrade(); } /// @inheritdoc IVaultEthStaking @@ -127,27 +127,16 @@ contract EthFoxVault is return _version; } - /** - * @dev Initializes the EthFoxVault contract - * @param params The decoded parameters for initializing the EthFoxVault contract - */ - function __EthFoxVault_init(EthFoxVaultInitParams memory params) internal onlyInitializing { - __VaultAdmin_init(params.admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(params.admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(params.ownMevEscrow); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(params.admin); - __VaultEthStaking_init(); - } - - /** - * @dev Initializes the EthFoxVault V2 contract - */ - function __EthFoxVault_initV2() internal onlyInitializing { - __VaultValidators_initV2(); + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) internal override { + if ( + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) + ) { + revert Errors.AccessDenied(); + } } /** diff --git a/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol b/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol index 52936827..735fac1e 100644 --- a/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol @@ -30,46 +30,12 @@ contract GnoBlocklistErc20Vault is * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the GnoErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, - uint256 exitingAssetsClaimDelay - ) - GnoErc20Vault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - exitingAssetsClaimDelay - ) - {} + constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { + _disableInitializers(); + } /// @inheritdoc IGnoErc20Vault function initialize( @@ -77,7 +43,7 @@ contract GnoBlocklistErc20Vault is ) external virtual override(IGnoErc20Vault, GnoErc20Vault) reinitializer(_version) { // if admin is already set, it's an upgrade from version 2 to 3 if (admin != address(0)) { - __GnoErc20Vault_initV3(); + __GnoErc20Vault_upgrade(); return; } diff --git a/contracts/vaults/gnosis/GnoBlocklistVault.sol b/contracts/vaults/gnosis/GnoBlocklistVault.sol index 62e70ff7..69a97dbf 100644 --- a/contracts/vaults/gnosis/GnoBlocklistVault.sol +++ b/contracts/vaults/gnosis/GnoBlocklistVault.sol @@ -24,46 +24,10 @@ contract GnoBlocklistVault is Initializable, GnoVault, VaultBlocklist, IGnoBlock * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the GnoVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, - uint256 exitingAssetsClaimDelay - ) - GnoVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - exitingAssetsClaimDelay - ) - {} + constructor(GnoVaultConstructorArgs memory args) GnoVault(args) {} /// @inheritdoc IGnoVault function initialize( @@ -71,7 +35,7 @@ contract GnoBlocklistVault is Initializable, GnoVault, VaultBlocklist, IGnoBlock ) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { // if admin is already set, it's an upgrade from version 2 to 3 if (admin != address(0)) { - __GnoVault_initV3(); + __GnoVault_upgrade(); return; } diff --git a/contracts/vaults/gnosis/GnoErc20Vault.sol b/contracts/vaults/gnosis/GnoErc20Vault.sol index 891d9366..0d0e4bfe 100644 --- a/contracts/vaults/gnosis/GnoErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoErc20Vault.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.22; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {IGnoErc20Vault} from '../../interfaces/IGnoErc20Vault.sol'; import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {Errors} from '../../libraries/Errors.sol'; import {Multicall} from '../../base/Multicall.sol'; import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; import {VaultValidators} from '../modules/VaultValidators.sol'; @@ -47,38 +48,24 @@ contract GnoErc20Vault is * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the GnoErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, - uint256 exitingAssetsClaimDelay + GnoErc20VaultConstructorArgs memory args ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) - VaultEnterExit(exitingAssetsClaimDelay) - VaultOsToken(osTokenVaultController, osTokenConfig, osTokenVaultEscrow) - VaultMev(sharedMevEscrow) - VaultGnoStaking(gnoToken, xdaiExchange) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) + VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) { _disableInitializers(); } @@ -87,7 +74,7 @@ contract GnoErc20Vault is function initialize(bytes calldata params) external virtual override reinitializer(_version) { // if admin is already set, it's an upgrade from version 2 to 3 if (admin != address(0)) { - __GnoErc20Vault_initV3(); + __GnoErc20Vault_upgrade(); return; } @@ -144,6 +131,13 @@ contract GnoErc20Vault is return _version; } + /// @inheritdoc VaultState + function _processTotalAssetsDelta( + int256 assetsDelta + ) internal virtual override(VaultState, VaultGnoStaking) { + super._processTotalAssetsDelta(assetsDelta); + } + /// @inheritdoc VaultState function _updateExitQueue() internal @@ -170,12 +164,40 @@ contract GnoErc20Vault is super._burnShares(owner, shares); } + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) internal override { + if ( + !_isValidatorsManager( + validators, + bytes32(validatorsManagerNonce), + validatorsManagerSignature + ) && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /// @inheritdoc VaultValidators + function _withdrawValidator( + bytes calldata validator + ) + internal + override(VaultValidators, VaultGnoStaking) + returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) + { + return super._withdrawValidator(validator); + } + /** - * @dev Initializes the GnoErc20Vault contract upgrade to V3 + * @dev Upgrades the GnoErc20Vault contract */ - function __GnoErc20Vault_initV3() internal { - __VaultState_initV3(); - __VaultValidators_initV3(); + function __GnoErc20Vault_upgrade() internal { + __VaultState_upgrade(); + __VaultValidators_upgrade(); + __VaultGnoStaking_upgrade(); } /** diff --git a/contracts/vaults/gnosis/GnoGenesisVault.sol b/contracts/vaults/gnosis/GnoGenesisVault.sol index 0e1a89ba..9e89408c 100644 --- a/contracts/vaults/gnosis/GnoGenesisVault.sol +++ b/contracts/vaults/gnosis/GnoGenesisVault.sol @@ -10,10 +10,7 @@ import {IVaultVersion} from '../../interfaces/IVaultVersion.sol'; import {IGnoPoolEscrow} from '../../interfaces/IGnoPoolEscrow.sol'; import {IGnoGenesisVault} from '../../interfaces/IGnoGenesisVault.sol'; import {IRewardGnoToken} from '../../interfaces/IRewardGnoToken.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; import {Errors} from '../../libraries/Errors.sol'; -import {VaultValidators} from '../modules/VaultValidators.sol'; -import {VaultEnterExit} from '../modules/VaultEnterExit.sol'; import {VaultGnoStaking} from '../modules/VaultGnoStaking.sol'; import {VaultState, IVaultState} from '../modules/VaultState.sol'; import {GnoVault, IGnoVault} from './GnoVault.sol'; @@ -39,83 +36,28 @@ contract GnoGenesisVault is Initializable, GnoVault, IGnoGenesisVault { * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange + * @param args The arguments for initializing the GnoVault contract * @param poolEscrow The address of the pool escrow from StakeWise Legacy * @param rewardGnoToken The address of the rGNO token from StakeWise Legacy - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, + GnoVaultConstructorArgs memory args, address poolEscrow, - address rewardGnoToken, - uint256 exitingAssetsClaimDelay - ) - GnoVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - exitingAssetsClaimDelay - ) - { + address rewardGnoToken + ) GnoVault(args) { _poolEscrow = IGnoPoolEscrow(poolEscrow); _rewardGnoToken = IRewardGnoToken(rewardGnoToken); } /// @inheritdoc IGnoVault function initialize( - bytes calldata params + bytes calldata ) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 3 to 4 - if (admin != address(0)) { - __GnoVault_initV3(); - return; + if (admin == address(0)) { + revert Errors.UpgradeFailed(); } - - // initialize deployed vault - (address _admin, GnoVaultInitParams memory initParams) = abi.decode( - params, - (address, GnoVaultInitParams) - ); - // use shared MEV escrow - __GnoVault_init(_admin, address(0), initParams); - emit GenesisVaultCreated( - _admin, - initParams.capacity, - initParams.feePercent, - initParams.metadataIpfsHash - ); - } - - /// @inheritdoc IGnoGenesisVault - function acceptPoolEscrowOwnership() external override { - _checkAdmin(); - _poolEscrow.applyOwnershipTransfer(); + __GnoVault_upgrade(); } /// @inheritdoc IVaultVersion @@ -128,31 +70,6 @@ contract GnoGenesisVault is Initializable, GnoVault, IGnoGenesisVault { return _version; } - /// @inheritdoc IVaultState - function updateState( - IKeeperRewards.HarvestParams calldata harvestParams - ) public override(IVaultState, VaultState) { - bool isCollateralized = IKeeperRewards(_keeper).isCollateralized(address(this)); - - // process total assets delta since last update - (int256 totalAssetsDelta, bool harvested) = _harvestAssets(harvestParams); - - if (!isCollateralized) { - // it's the first harvest, deduct rewards accumulated so far in legacy pool - totalAssetsDelta -= SafeCast.toInt256(_rewardGnoToken.totalRewards()); - // the first state update must be with positive delta - if (_poolEscrow.owner() != address(this) || totalAssetsDelta < 0) { - revert InvalidInitialHarvest(); - } - } - - // process total assets delta - _processTotalAssetsDelta(totalAssetsDelta); - - // update exit queue every time new update is harvested - if (harvested) _updateExitQueue(); - } - /// @inheritdoc IGnoGenesisVault function migrate(address receiver, uint256 assets) external override returns (uint256 shares) { if (msg.sender != address(_rewardGnoToken) || _poolEscrow.owner() != address(this)) { @@ -204,43 +121,6 @@ contract GnoGenesisVault is Initializable, GnoVault, IGnoGenesisVault { } } - /// @inheritdoc VaultState - function _processTotalAssetsDelta(int256 totalAssetsDelta) internal override { - // skip processing if there is no change in assets - if (totalAssetsDelta == 0) return; - - // fetch total assets controlled by legacy pool - uint256 legacyPrincipal = _rewardGnoToken.totalAssets() - _rewardGnoToken.totalPenalty(); - if (legacyPrincipal == 0) { - // legacy pool has no assets, process total assets delta as usual - super._processTotalAssetsDelta(totalAssetsDelta); - return; - } - - // calculate total principal - uint256 totalPrincipal = _totalAssets + legacyPrincipal; - if (totalAssetsDelta < 0) { - // calculate and update penalty for legacy pool - int256 legacyPenalty = SafeCast.toInt256( - Math.mulDiv(uint256(-totalAssetsDelta), legacyPrincipal, totalPrincipal) - ); - _rewardGnoToken.updateTotalRewards(-legacyPenalty); - // deduct penalty from total assets delta - totalAssetsDelta += legacyPenalty; - } else { - // calculate and update reward for legacy pool - int256 legacyReward = SafeCast.toInt256( - Math.mulDiv(uint256(totalAssetsDelta), legacyPrincipal, totalPrincipal) - ); - _rewardGnoToken.updateTotalRewards(legacyReward); - // deduct reward from total assets delta - totalAssetsDelta -= legacyReward; - } - - // process total assets delta - super._processTotalAssetsDelta(totalAssetsDelta); - } - /// @inheritdoc VaultState function _vaultAssets() internal diff --git a/contracts/vaults/gnosis/GnoPrivErc20Vault.sol b/contracts/vaults/gnosis/GnoPrivErc20Vault.sol index b58147c7..def22260 100644 --- a/contracts/vaults/gnosis/GnoPrivErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoPrivErc20Vault.sol @@ -25,46 +25,12 @@ contract GnoPrivErc20Vault is Initializable, GnoErc20Vault, VaultWhitelist, IGno * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the GnoErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, - uint256 exitingAssetsClaimDelay - ) - GnoErc20Vault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - exitingAssetsClaimDelay - ) - {} + constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { + _disableInitializers(); + } /// @inheritdoc IGnoErc20Vault function initialize( @@ -72,7 +38,7 @@ contract GnoPrivErc20Vault is Initializable, GnoErc20Vault, VaultWhitelist, IGno ) external virtual override(IGnoErc20Vault, GnoErc20Vault) reinitializer(_version) { // if admin is already set, it's an upgrade from version 2 to 3 if (admin != address(0)) { - __GnoErc20Vault_initV3(); + __GnoErc20Vault_upgrade(); return; } diff --git a/contracts/vaults/gnosis/GnoPrivVault.sol b/contracts/vaults/gnosis/GnoPrivVault.sol index 133edca4..e9fad519 100644 --- a/contracts/vaults/gnosis/GnoPrivVault.sol +++ b/contracts/vaults/gnosis/GnoPrivVault.sol @@ -24,46 +24,10 @@ contract GnoPrivVault is Initializable, GnoVault, VaultWhitelist, IGnoPrivVault * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the GnoVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, - uint256 exitingAssetsClaimDelay - ) - GnoVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - exitingAssetsClaimDelay - ) - {} + constructor(GnoVaultConstructorArgs memory args) GnoVault(args) {} /// @inheritdoc IGnoVault function initialize( @@ -71,7 +35,7 @@ contract GnoPrivVault is Initializable, GnoVault, VaultWhitelist, IGnoPrivVault ) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { // if admin is already set, it's an upgrade from version 2 to 3 if (admin != address(0)) { - __GnoVault_initV3(); + __GnoVault_upgrade(); return; } diff --git a/contracts/vaults/gnosis/GnoVault.sol b/contracts/vaults/gnosis/GnoVault.sol index 03ad31c4..f91f563e 100644 --- a/contracts/vaults/gnosis/GnoVault.sol +++ b/contracts/vaults/gnosis/GnoVault.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.22; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {IGnoVault} from '../../interfaces/IGnoVault.sol'; import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; +import {Errors} from '../../libraries/Errors.sol'; import {Multicall} from '../../base/Multicall.sol'; import {VaultValidators} from '../modules/VaultValidators.sol'; import {VaultAdmin} from '../modules/VaultAdmin.sol'; @@ -43,38 +44,24 @@ contract GnoVault is * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param _keeper The address of the Keeper contract - * @param _vaultsRegistry The address of the VaultsRegistry contract - * @param _validatorsRegistry The contract address used for registering validators in beacon chain - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the GnoVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( - address _keeper, - address _vaultsRegistry, - address _validatorsRegistry, - address osTokenVaultController, - address osTokenConfig, - address osTokenVaultEscrow, - address sharedMevEscrow, - address depositDataRegistry, - address gnoToken, - address xdaiExchange, - uint256 exitingAssetsClaimDelay + GnoVaultConstructorArgs memory args ) - VaultImmutables(_keeper, _vaultsRegistry, _validatorsRegistry) - VaultValidators(depositDataRegistry) - VaultEnterExit(exitingAssetsClaimDelay) - VaultOsToken(osTokenVaultController, osTokenConfig, osTokenVaultEscrow) - VaultMev(sharedMevEscrow) - VaultGnoStaking(gnoToken, xdaiExchange) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) + VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) { _disableInitializers(); } @@ -83,7 +70,7 @@ contract GnoVault is function initialize(bytes calldata params) external virtual override reinitializer(_version) { // if admin is already set, it's an upgrade from version 2 to 3 if (admin != address(0)) { - __GnoVault_initV3(); + __GnoVault_upgrade(); return; } @@ -118,12 +105,47 @@ contract GnoVault is return _version; } + /// @inheritdoc VaultState + function _processTotalAssetsDelta( + int256 assetsDelta + ) internal virtual override(VaultState, VaultGnoStaking) { + super._processTotalAssetsDelta(assetsDelta); + } + + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) internal override { + if ( + !_isValidatorsManager( + validators, + bytes32(validatorsManagerNonce), + validatorsManagerSignature + ) && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /// @inheritdoc VaultValidators + function _withdrawValidator( + bytes calldata validator + ) + internal + override(VaultValidators, VaultGnoStaking) + returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) + { + return super._withdrawValidator(validator); + } + /** - * @dev Initializes the GnoVault contract upgrade to V3 + * @dev Upgrades the GnoVault contract */ - function __GnoVault_initV3() internal { - __VaultState_initV3(); - __VaultValidators_initV3(); + function __GnoVault_upgrade() internal { + __VaultState_upgrade(); + __VaultValidators_upgrade(); + __VaultGnoStaking_upgrade(); } /** diff --git a/contracts/vaults/modules/VaultAdmin.sol b/contracts/vaults/modules/VaultAdmin.sol index ce1a8162..20443e73 100644 --- a/contracts/vaults/modules/VaultAdmin.sol +++ b/contracts/vaults/modules/VaultAdmin.sol @@ -21,6 +21,29 @@ abstract contract VaultAdmin is Initializable, IVaultAdmin { emit MetadataUpdated(msg.sender, metadataIpfsHash); } + /// @inheritdoc IVaultAdmin + function setAdmin(address newAdmin) external override { + _checkAdmin(); + _setAdmin(newAdmin); + } + + /** + * @dev Internal method for checking whether the caller is admin + */ + function _checkAdmin() internal view { + if (msg.sender != admin) revert Errors.AccessDenied(); + } + + /** + * @dev Internal method for updating the admin + * @param newAdmin The address of the new admin + */ + function _setAdmin(address newAdmin) private { + if (newAdmin == address(0)) revert Errors.ZeroAddress(); + admin = newAdmin; + emit AdminUpdated(msg.sender, newAdmin); + } + /** * @dev Initializes the VaultAdmin contract * @param _admin The address of the Vault admin @@ -29,18 +52,10 @@ abstract contract VaultAdmin is Initializable, IVaultAdmin { address _admin, string memory metadataIpfsHash ) internal onlyInitializing { - if (_admin == address(0)) revert Errors.ZeroAddress(); - admin = _admin; + _setAdmin(_admin); emit MetadataUpdated(msg.sender, metadataIpfsHash); } - /** - * @dev Internal method for checking whether the caller is admin - */ - function _checkAdmin() internal view { - if (msg.sender != admin) revert Errors.AccessDenied(); - } - /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. diff --git a/contracts/vaults/modules/VaultEnterExit.sol b/contracts/vaults/modules/VaultEnterExit.sol index 7ca84bd1..04d692c4 100644 --- a/contracts/vaults/modules/VaultEnterExit.sol +++ b/contracts/vaults/modules/VaultEnterExit.sol @@ -5,7 +5,6 @@ pragma solidity ^0.8.22; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; import {IVaultEnterExit} from '../../interfaces/IVaultEnterExit.sol'; import {ExitQueue} from '../../libraries/ExitQueue.sol'; import {Errors} from '../../libraries/Errors.sol'; diff --git a/contracts/vaults/modules/VaultEthStaking.sol b/contracts/vaults/modules/VaultEthStaking.sol index 0e74f716..30533ef5 100644 --- a/contracts/vaults/modules/VaultEthStaking.sol +++ b/contracts/vaults/modules/VaultEthStaking.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.22; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; import {Address} from '@openzeppelin/contracts/utils/Address.sol'; import {IEthValidatorsRegistry} from '../../interfaces/IEthValidatorsRegistry.sol'; import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; @@ -21,7 +20,6 @@ import {VaultMev} from './VaultMev.sol'; */ abstract contract VaultEthStaking is Initializable, - ReentrancyGuardUpgradeable, VaultState, VaultValidators, VaultEnterExit, @@ -61,45 +59,32 @@ abstract contract VaultEthStaking is } /// @inheritdoc VaultValidators - function _registerSingleValidator(bytes calldata validator) internal virtual override { - bytes calldata publicKey = validator[:48]; - IEthValidatorsRegistry(_validatorsRegistry).deposit{value: _validatorDeposit()}( + function _registerValidator( + bytes calldata validator, + bool isV1Validator + ) internal virtual override returns (uint256 depositAmount, bytes calldata publicKey) { + publicKey = validator[:48]; + bytes calldata signature = validator[48:144]; + bytes32 depositDataRoot = bytes32(validator[144:176]); + + // get the deposit amount and withdrawal credentials prefix + bytes1 withdrawalCredsPrefix; + if (isV1Validator) { + withdrawalCredsPrefix = 0x01; + depositAmount = _validatorMinEffectiveBalance(); + } else { + withdrawalCredsPrefix = 0x02; + // extract amount from data, convert gwei to wei by multiplying by 1 gwei + depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei); + } + + // deposit to the validators registry + IEthValidatorsRegistry(_validatorsRegistry).deposit{value: depositAmount}( publicKey, - _withdrawalCredentials(), - validator[48:144], - bytes32(validator[144:_validatorLength()]) + abi.encodePacked(withdrawalCredsPrefix, bytes11(0x0), address(this)), + signature, + depositDataRoot ); - emit ValidatorRegistered(publicKey); - } - - /// @inheritdoc VaultValidators - function _registerMultipleValidators(bytes calldata validators) internal virtual override { - uint256 startIndex; - uint256 endIndex; - uint256 validatorsCount = validators.length / _validatorLength(); - bytes memory withdrawalCredentials = _withdrawalCredentials(); - bytes calldata validator; - bytes calldata publicKey; - for (uint256 i = 0; i < validatorsCount; ) { - unchecked { - // cannot realistically overflow - endIndex += _validatorLength(); - } - validator = validators[startIndex:endIndex]; - publicKey = validator[:48]; - IEthValidatorsRegistry(_validatorsRegistry).deposit{value: _validatorDeposit()}( - publicKey, - withdrawalCredentials, - validator[48:144], - bytes32(validator[144:_validatorLength()]) - ); - emit ValidatorRegistered(publicKey); - startIndex = endIndex; - unchecked { - // cannot realistically overflow - ++i; - } - } } /// @inheritdoc VaultState @@ -116,29 +101,19 @@ abstract contract VaultEthStaking is } /// @inheritdoc VaultValidators - function _validatorLength() internal pure virtual override returns (uint256) { - return 176; - } - - /// @inheritdoc VaultValidators - function _validatorDeposit() internal pure virtual override returns (uint256) { + function _validatorMinEffectiveBalance() internal pure virtual override returns (uint256) { return 32 ether; } - /** - * @dev Internal function for calculating Vault withdrawal credentials - * @return The credentials used for the validators withdrawals - */ - function _withdrawalCredentials() private view returns (bytes memory) { - return abi.encodePacked(bytes1(0x01), bytes11(0x0), address(this)); + /// @inheritdoc VaultValidators + function _validatorMaxEffectiveBalance() internal pure virtual override returns (uint256) { + return 2048 ether; } /** * @dev Initializes the VaultEthStaking contract */ function __VaultEthStaking_init() internal onlyInitializing { - __ReentrancyGuard_init(); - // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 if (msg.value < _securityDeposit) revert Errors.InvalidSecurityDeposit(); _deposit(address(this), msg.value, address(0)); diff --git a/contracts/vaults/modules/VaultFee.sol b/contracts/vaults/modules/VaultFee.sol index eb7eb094..0d28586f 100644 --- a/contracts/vaults/modules/VaultFee.sol +++ b/contracts/vaults/modules/VaultFee.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.22; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {IVaultFee} from '../../interfaces/IVaultFee.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; import {Errors} from '../../libraries/Errors.sol'; import {VaultAdmin} from './VaultAdmin.sol'; import {VaultImmutables} from './VaultImmutables.sol'; @@ -16,6 +15,7 @@ import {VaultImmutables} from './VaultImmutables.sol'; */ abstract contract VaultFee is VaultImmutables, Initializable, VaultAdmin, IVaultFee { uint256 internal constant _maxFeePercent = 10_000; // @dev 100.00 % + uint256 private constant _feeUpdateDelay = 7 days; /// @inheritdoc IVaultFee address public override feeRecipient; @@ -23,12 +23,20 @@ abstract contract VaultFee is VaultImmutables, Initializable, VaultAdmin, IVault /// @inheritdoc IVaultFee uint16 public override feePercent; + uint64 private _lastUpdateTimestamp; + /// @inheritdoc IVaultFee function setFeeRecipient(address _feeRecipient) external override { _checkAdmin(); _setFeeRecipient(_feeRecipient); } + /// @inheritdoc IVaultFee + function setFeePercent(uint16 _feePercent) external override { + _checkAdmin(); + _setFeePercent(_feePercent, false); + } + /** * @dev Internal function for updating the fee recipient externally or from the initializer * @param _feeRecipient The address of the new fee recipient @@ -42,16 +50,43 @@ abstract contract VaultFee is VaultImmutables, Initializable, VaultAdmin, IVault emit FeeRecipientUpdated(msg.sender, _feeRecipient); } + /** + * @dev Internal function for updating the fee percent + * @param _feePercent The new fee percent + * @param isVaultCreation Flag indicating whether the fee percent is set during the vault creation + */ + function _setFeePercent(uint16 _feePercent, bool isVaultCreation) private { + _checkHarvested(); + if (_feePercent > _maxFeePercent) revert Errors.InvalidFeePercent(); + + if (!isVaultCreation) { + if (_lastUpdateTimestamp + _feeUpdateDelay > block.timestamp) { + revert Errors.TooEarlyUpdate(); + } + + // check that the fee percent can be increase only by 20% at a time + // if the current fee is 0, then it can cannot exceed 1% initially + uint256 currentFeePercent = feePercent; + uint256 maxFeePercent = currentFeePercent > 0 ? (currentFeePercent * 120) / 100 : 100; + if (maxFeePercent < _feePercent) { + revert Errors.InvalidFeePercent(); + } + } + + // update fee percent + feePercent = _feePercent; + _lastUpdateTimestamp = uint64(block.timestamp); + emit FeePercentUpdated(msg.sender, _feePercent); + } + /** * @dev Initializes the VaultFee contract * @param _feeRecipient The address of the fee recipient * @param _feePercent The fee percent that is charged by the Vault */ function __VaultFee_init(address _feeRecipient, uint16 _feePercent) internal onlyInitializing { - if (_feePercent > _maxFeePercent) revert Errors.InvalidFeePercent(); - _setFeeRecipient(_feeRecipient); - feePercent = _feePercent; + _setFeePercent(_feePercent, true); } /** diff --git a/contracts/vaults/modules/VaultGnoStaking.sol b/contracts/vaults/modules/VaultGnoStaking.sol index e6e376f4..8f483237 100644 --- a/contracts/vaults/modules/VaultGnoStaking.sol +++ b/contracts/vaults/modules/VaultGnoStaking.sol @@ -4,13 +4,10 @@ pragma solidity ^0.8.22; import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; import {IGnoValidatorsRegistry} from '../../interfaces/IGnoValidatorsRegistry.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {IXdaiExchange} from '../../interfaces/IXdaiExchange.sol'; import {IVaultGnoStaking} from '../../interfaces/IVaultGnoStaking.sol'; +import {IGnoDaiDistributor} from '../../interfaces/IGnoDaiDistributor.sol'; import {Errors} from '../../libraries/Errors.sol'; import {VaultAdmin} from './VaultAdmin.sol'; import {VaultState} from './VaultState.sol'; @@ -24,7 +21,6 @@ import {VaultEnterExit} from './VaultEnterExit.sol'; */ abstract contract VaultGnoStaking is Initializable, - ReentrancyGuardUpgradeable, VaultAdmin, VaultState, VaultValidators, @@ -34,19 +30,19 @@ abstract contract VaultGnoStaking is uint256 private constant _securityDeposit = 1e9; IERC20 internal immutable _gnoToken; - address private immutable _xdaiExchange; + IGnoDaiDistributor private immutable _gnoDaiDistributor; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. * @param gnoToken The address of the GNO token - * @param xdaiExchange The address of the xDAI exchange + * @param gnoDaiDistributor The address of the xDAI distributor contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address gnoToken, address xdaiExchange) { + constructor(address gnoToken, address gnoDaiDistributor) { _gnoToken = IERC20(gnoToken); - _xdaiExchange = xdaiExchange; + _gnoDaiDistributor = IGnoDaiDistributor(gnoDaiDistributor); } /// @inheritdoc IVaultGnoStaking @@ -60,18 +56,14 @@ abstract contract VaultGnoStaking is shares = _deposit(receiver, assets, referrer); } - /// @inheritdoc IVaultGnoStaking - function swapXdaiToGno() external override nonReentrant { - uint256 balance = address(this).balance; - // skip swapping for small amounts - if (balance < 1 gwei) return; + /// @inheritdoc VaultState + function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override { + super._processTotalAssetsDelta(assetsDelta); - // swap through xDAI exchange - uint256 assets = IXdaiExchange(_xdaiExchange).swap{value: balance}(); + uint256 balance = address(this).balance; + if (balance < 0.1 ether) return; - // update total assets - _processTotalAssetsDelta(SafeCast.toInt256(assets)); - emit XdaiSwapped(balance, assets); + _gnoDaiDistributor.distributeSDai{value: balance}(); } /** @@ -80,51 +72,53 @@ abstract contract VaultGnoStaking is receive() external payable {} /// @inheritdoc VaultValidators - function _registerSingleValidator(bytes calldata validator) internal virtual override { - _registerMultipleValidators(validator); - } - - /// @inheritdoc VaultValidators - function _registerMultipleValidators(bytes calldata validators) internal virtual override { + function _registerValidator( + bytes calldata validator, + bool isV1Validator + ) internal virtual override returns (uint256 depositAmount, bytes calldata publicKey) { // pull withdrawals from the deposit contract _pullWithdrawals(); - // variables used for batch deposit - bytes memory publicKeys; - bytes memory signatures; - - // prepare deposit data - uint256 startIndex; - uint256 endIndex; - bytes calldata validator; - uint256 validatorLength = _validatorLength(); - uint256 validatorsCount = validators.length / validatorLength; - bytes32[] memory depositDataRoots = new bytes32[](validatorsCount); - for (uint256 i = 0; i < validatorsCount; ) { - endIndex += validatorLength; - validator = validators[startIndex:endIndex]; - publicKeys = bytes.concat(publicKeys, validator[:48]); - signatures = bytes.concat(signatures, validator[48:144]); - depositDataRoots[i] = bytes32(validator[144:validatorLength]); - startIndex = endIndex; - emit ValidatorRegistered(validator[:48]); - startIndex = endIndex; - unchecked { - // cannot realistically overflow - ++i; - } + publicKey = validator[:48]; + bytes calldata signature = validator[48:144]; + bytes32 depositDataRoot = bytes32(validator[144:176]); + + // get the deposit amount and withdrawal credentials prefix + bytes1 withdrawalCredsPrefix; + if (isV1Validator) { + withdrawalCredsPrefix = 0x01; + depositAmount = _validatorMinEffectiveBalance(); + } else { + withdrawalCredsPrefix = 0x02; + // extract amount from data, convert gwei to wei by multiplying by 1 gwei + // divide by 32 to convert mGNO to GNO + depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei) / 32; } - // register validators batch - _gnoToken.approve(_validatorsRegistry, _validatorDeposit() * validatorsCount); - IGnoValidatorsRegistry(_validatorsRegistry).batchDeposit( - publicKeys, - _withdrawalCredentials(), - signatures, - depositDataRoots + // deposit GNO tokens to the validators registry + IGnoValidatorsRegistry(_validatorsRegistry).deposit( + publicKey, + abi.encodePacked(withdrawalCredsPrefix, bytes11(0x0), address(this)), + signature, + depositDataRoot, + depositAmount ); } + /// @inheritdoc VaultValidators + function _withdrawValidator( + bytes calldata validator + ) + internal + virtual + override + returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) + { + (publicKey, withdrawnAmount, feePaid) = super._withdrawValidator(validator); + // convert mGNO to GNO + withdrawnAmount /= 32; + } + /// @inheritdoc VaultState function _vaultAssets() internal view virtual override returns (uint256) { return @@ -144,35 +138,36 @@ abstract contract VaultGnoStaking is } /// @inheritdoc VaultValidators - function _validatorLength() internal pure virtual override returns (uint256) { - return 176; + function _validatorMinEffectiveBalance() internal pure override returns (uint256) { + return 1 ether; } /// @inheritdoc VaultValidators - function _validatorDeposit() internal pure virtual override returns (uint256) { - return 1 ether; + function _validatorMaxEffectiveBalance() internal pure override returns (uint256) { + return 64 ether; } /** - * @dev Internal function for calculating Vault withdrawal credentials - * @return The credentials used for the validators withdrawals + * @dev Pulls assets from withdrawal contract */ - function _withdrawalCredentials() internal view virtual returns (bytes memory) { - return abi.encodePacked(bytes1(0x01), bytes11(0x0), address(this)); + function _pullWithdrawals() internal virtual { + IGnoValidatorsRegistry(_validatorsRegistry).claimWithdrawal(address(this)); } /** - * @dev Pulls assets from withdrawal contract + * @dev Upgrades the VaultGnoStaking contract */ - function _pullWithdrawals() internal virtual { - IGnoValidatorsRegistry(_validatorsRegistry).claimWithdrawal(address(this)); + function __VaultGnoStaking_upgrade() internal onlyInitializing { + // approve transferring GNO for validators registration + _gnoToken.approve(_validatorsRegistry, type(uint256).max); } /** * @dev Initializes the VaultGnoStaking contract */ function __VaultGnoStaking_init() internal onlyInitializing { - __ReentrancyGuard_init(); + // approve transferring GNO for validators registration + _gnoToken.approve(_validatorsRegistry, type(uint256).max); _deposit(address(this), _securityDeposit, address(0)); // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 diff --git a/contracts/vaults/modules/VaultImmutables.sol b/contracts/vaults/modules/VaultImmutables.sol index 81845902..848475bf 100644 --- a/contracts/vaults/modules/VaultImmutables.sol +++ b/contracts/vaults/modules/VaultImmutables.sol @@ -17,22 +17,17 @@ abstract contract VaultImmutables { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address internal immutable _vaultsRegistry; - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address internal immutable _validatorsRegistry; - /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. * @param keeper The address of the Keeper contract * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address keeper, address vaultsRegistry, address validatorsRegistry) { + constructor(address keeper, address vaultsRegistry) { _keeper = keeper; _vaultsRegistry = vaultsRegistry; - _validatorsRegistry = validatorsRegistry; } /** diff --git a/contracts/vaults/modules/VaultOsToken.sol b/contracts/vaults/modules/VaultOsToken.sol index 05ece992..5c077ace 100644 --- a/contracts/vaults/modules/VaultOsToken.sol +++ b/contracts/vaults/modules/VaultOsToken.sol @@ -28,7 +28,7 @@ abstract contract VaultOsToken is VaultImmutables, VaultState, VaultEnterExit, I IOsTokenVaultController private immutable _osTokenVaultController; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IOsTokenConfig private immutable _osTokenConfig; + IOsTokenConfig internal immutable _osTokenConfig; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IOsTokenVaultEscrow private immutable _osTokenVaultEscrow; diff --git a/contracts/vaults/modules/VaultState.sol b/contracts/vaults/modules/VaultState.sol index d4eff4bb..c8a03618 100644 --- a/contracts/vaults/modules/VaultState.sol +++ b/contracts/vaults/modules/VaultState.sol @@ -316,20 +316,9 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault } /** - * @dev Initializes the VaultState contract upgrade to V3 + * @dev Upgrades the VaultState contract */ - function __VaultState_initV3() internal onlyInitializing { - // SLOAD to memory - uint256 _queuedShares = queuedShares; - if (_queuedShares > 1) revert Errors.InvalidQueuedShares(); - if (_queuedShares == 1) { - // burn the rounding error queued share - _totalShares -= 1; - queuedShares = 0; - _exitQueue.push(1, 0); - emit CheckpointCreated(1, 0); - } - + function __VaultState_upgrade() internal onlyInitializing { // SLOAD to memory uint256 totalExitedTickets = _totalExitedTickets; uint256 exitQueueTicket = _exitQueue.getLatestTotalTickets(); diff --git a/contracts/vaults/modules/VaultValidators.sol b/contracts/vaults/modules/VaultValidators.sol index 976292f8..aef7c739 100644 --- a/contracts/vaults/modules/VaultValidators.sol +++ b/contracts/vaults/modules/VaultValidators.sol @@ -2,13 +2,15 @@ pragma solidity ^0.8.22; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; +import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; import {IKeeperValidators} from '../../interfaces/IKeeperValidators.sol'; -import {IDepositDataRegistry} from '../../interfaces/IDepositDataRegistry.sol'; import {IVaultValidators} from '../../interfaces/IVaultValidators.sol'; +import {IConsolidationsChecker} from '../../interfaces/IConsolidationsChecker.sol'; +import {IDepositDataRegistry} from '../../interfaces/IDepositDataRegistry.sol'; import {Errors} from '../../libraries/Errors.sol'; import {VaultImmutables} from './VaultImmutables.sol'; import {VaultAdmin} from './VaultAdmin.sol'; @@ -22,12 +24,17 @@ import {VaultState} from './VaultState.sol'; abstract contract VaultValidators is VaultImmutables, Initializable, + ReentrancyGuardUpgradeable, VaultAdmin, VaultState, IVaultValidators { - bytes32 private constant _registerValidatorsTypeHash = + bytes32 private constant _validatorsManagerTypeHash = keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'); + uint256 internal constant _validatorV1DepositLength = 176; + uint256 internal constant _validatorV2DepositLength = 184; + uint256 private constant _validatorWithdrawalLength = 56; + uint256 private constant _validatorConsolidationLength = 96; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable _depositDataRegistry; @@ -35,26 +42,58 @@ abstract contract VaultValidators is /// @custom:oz-upgrades-unsafe-allow state-variable-immutable uint256 private immutable _initialChainId; + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address internal immutable _validatorsRegistry; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _validatorsWithdrawals; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _validatorsConsolidations; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _consolidationsChecker; + /// deprecated. Deposit data management is moved to DepositDataRegistry contract - bytes32 private _validatorsRoot; + bytes32 private __deprecated__validatorsRoot; /// deprecated. Deposit data management is moved to DepositDataRegistry contract - uint256 private _validatorIndex; + uint256 private __deprecated__validatorIndex; address private _validatorsManager; bytes32 private _initialDomainSeparator; + /// @inheritdoc IVaultValidators + mapping(bytes32 publicKeyHash => bool isRegistered) public override v2Validators; + + /// @inheritdoc IVaultValidators + uint256 public override validatorsManagerNonce; + /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param depositDataRegistry The address of the deposit data registry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for verifying consolidation approvals */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address depositDataRegistry) { - _depositDataRegistry = depositDataRegistry; + constructor( + address depositDataRegistry, + address validatorsRegistry, + address validatorsWithdrawals, + address validatorsConsolidations, + address consolidationsChecker + ) { _initialChainId = block.chainid; + _depositDataRegistry = depositDataRegistry; + _validatorsRegistry = validatorsRegistry; + _validatorsWithdrawals = validatorsWithdrawals; + _validatorsConsolidations = validatorsConsolidations; + _consolidationsChecker = consolidationsChecker; } /// @inheritdoc IVaultValidators @@ -70,47 +109,153 @@ abstract contract VaultValidators is IKeeperValidators.ApprovalParams calldata keeperParams, bytes calldata validatorsManagerSignature ) external override { - // get approval from oracles + // check whether oracles have approve validators registration IKeeperValidators(_keeper).approveValidators(keeperParams); + _registerValidators( + keeperParams.validators, + keeperParams.validatorsRegistryRoot, + validatorsManagerSignature, + false + ); + } - // check vault is up to date - _checkHarvested(); + /// @inheritdoc IVaultValidators + function fundValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) external override { + _registerValidators( + validators, + bytes32(validatorsManagerNonce), + validatorsManagerSignature, + true + ); + } - // check access - address validatorsManager_ = validatorsManager(); + /// @inheritdoc IVaultValidators + function withdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) external payable override nonReentrant { + _checkCollateralized(); + _checkCanWithdrawValidators(validators, validatorsManagerSignature); + + // check validators length is valid + uint256 validatorsCount = validators.length / _validatorWithdrawalLength; + unchecked { + if (validatorsCount == 0 || validators.length % _validatorWithdrawalLength != 0) { + revert Errors.InvalidValidators(); + } + } + + uint256 feePaid; + uint256 withdrawnAmount; + uint256 totalFeeAssets = msg.value; + bytes calldata publicKey; + uint256 startIndex; + for (uint256 i = 0; i < validatorsCount; ) { + (publicKey, withdrawnAmount, feePaid) = _withdrawValidator( + validators[startIndex:startIndex + _validatorWithdrawalLength] + ); + totalFeeAssets -= feePaid; + emit ValidatorWithdrawalSubmitted(publicKey, withdrawnAmount, feePaid); + + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorWithdrawalLength; + } + } + + if (totalFeeAssets > 0) { + Address.sendValue(payable(msg.sender), totalFeeAssets); + } + } + + /// @inheritdoc IVaultValidators + function consolidateValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature, + bytes calldata oracleSignatures + ) external payable override { + _checkCollateralized(); if ( - msg.sender != validatorsManager_ && - !SignatureChecker.isValidSignatureNow( - validatorsManager_, - _getSignedMessageHash(keeperParams), - validatorsManagerSignature - ) + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) ) { revert Errors.AccessDenied(); } - // check validators length is valid - uint256 validatorLength = _validatorLength(); - uint256 validatorsCount = keeperParams.validators.length / validatorLength; + // Check validators length is valid + uint256 validatorsCount = validators.length / _validatorConsolidationLength; unchecked { - if ( - validatorsCount == 0 || validatorsCount * validatorLength != keeperParams.validators.length - ) { + if (validatorsCount == 0 || validators.length % _validatorConsolidationLength != 0) { revert Errors.InvalidValidators(); } } - // check enough withdrawable assets - if (withdrawableAssets() < _validatorDeposit() * validatorsCount) { - revert Errors.InsufficientAssets(); + // Check for oracle approval if signatures provided + bool consolidationsApproved = false; + if (oracleSignatures.length > 0) { + // Check whether oracles have approved validators consolidation + IConsolidationsChecker(_consolidationsChecker).verifySignatures( + address(this), + validators, + oracleSignatures + ); + consolidationsApproved = true; + } + + // Process the consolidation in smaller batches to avoid stack depth issues + _processConsolidation(validators, validatorsCount, consolidationsApproved); + } + + /** + * @dev Internal function to process validator consolidations + * @param validators The concatenated validators data + * @param validatorsCount The number of validators to consolidate + * @param consolidationsApproved Whether the consolidations are approved by oracles + */ + function _processConsolidation( + bytes calldata validators, + uint256 validatorsCount, + bool consolidationsApproved + ) private { + uint256 totalFeeAssets = msg.value; + + // Process each validator + bytes32 destPubKeyHash; + bytes calldata sourcePublicKey; + bytes calldata destPublicKey; + uint256 feePaid; + uint256 startIndex; + for (uint256 i = 0; i < validatorsCount; ) { + // consolidate validators + (sourcePublicKey, destPublicKey, feePaid) = _consolidateValidator( + validators[startIndex:startIndex + _validatorConsolidationLength] + ); + + // check whether the destination public key is tracked or approved + destPubKeyHash = keccak256(destPublicKey); + if (consolidationsApproved) { + v2Validators[destPubKeyHash] = true; + } else if (!v2Validators[destPubKeyHash]) { + revert Errors.InvalidValidators(); + } + + // Update fees and emit event + unchecked { + // cannot realistically overflow + totalFeeAssets -= feePaid; + startIndex += _validatorConsolidationLength; + ++i; + } + + emit ValidatorConsolidationSubmitted(sourcePublicKey, destPublicKey, feePaid); } - if (keeperParams.validators.length == validatorLength) { - // register single validator - _registerSingleValidator(keeperParams.validators); - } else { - // register multiple validators - _registerMultipleValidators(keeperParams.validators); + // refund unused fees + if (totalFeeAssets > 0) { + Address.sendValue(payable(msg.sender), totalFeeAssets); } } @@ -123,76 +268,217 @@ abstract contract VaultValidators is } /** - * @dev Internal function for registering validator. Must emit ValidatorRegistered event. + * @dev Internal function for registering validator * @param validator The validator registration data + * @param isV1Validator Whether the validator is V1 or V2 + * @return depositAmount The amount of assets that was deposited + * @return publicKey The public key of the registered validator */ - function _registerSingleValidator(bytes calldata validator) internal virtual; + function _registerValidator( + bytes calldata validator, + bool isV1Validator + ) internal virtual returns (uint256 depositAmount, bytes calldata publicKey); /** - * @dev Internal function for registering multiple validators. Must emit ValidatorRegistered event for every validator. - * @param validators The validators registration data + * @dev Internal function for withdrawing validator + * @param validator The validator withdrawal data + * @return publicKey The public key of the withdrawn validator + * @return withdrawnAmount The amount of assets that was withdrawn + * @return feePaid The amount of fee that was paid */ - function _registerMultipleValidators(bytes calldata validators) internal virtual; + function _withdrawValidator( + bytes calldata validator + ) internal virtual returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) { + publicKey = validator[:48]; + // convert gwei to wei by multiplying by 1 gwei + withdrawnAmount = (uint256(uint64(bytes8(validator[48:56]))) * 1 gwei); + feePaid = uint256(bytes32(Address.functionStaticCall(_validatorsWithdrawals, ''))); + + Address.functionCallWithValue(_validatorsWithdrawals, validator, feePaid); + } /** - * @dev Internal function for defining the length of the validator data - * @return The length of the single validator data + * @dev Internal function for consolidating validators + * @param fromPublicKey The public key of the validator that was consolidated + * @param toPublicKey The public key of the validator that was consolidated to + * @param feePaid The amount of fee that was paid */ - function _validatorLength() internal pure virtual returns (uint256); + function _consolidateValidator( + bytes calldata validator + ) private returns (bytes calldata fromPublicKey, bytes calldata toPublicKey, uint256 feePaid) { + fromPublicKey = validator[:48]; + toPublicKey = validator[48:96]; + feePaid = uint256(bytes32(Address.functionStaticCall(_validatorsConsolidations, ''))); + + Address.functionCallWithValue(_validatorsConsolidations, validator, feePaid); + } /** - * @dev Internal function for fetching validator deposit amount + * @dev Internal function for fetching validator minimum effective balance + * @return The minimum effective balance for the validator */ - function _validatorDeposit() internal pure virtual returns (uint256); + function _validatorMinEffectiveBalance() internal pure virtual returns (uint256); /** - * @dev Initializes the VaultValidators contract - * @dev NB! This initializer must be called after VaultState initializer + * @dev Internal function for fetching validator maximum effective balance + * @return The maximum effective balance for the validator */ - function __VaultValidators_init() internal onlyInitializing { - if (capacity() < _validatorDeposit()) revert Errors.InvalidCapacity(); - // initialize domain separator - _initialDomainSeparator = _computeVaultValidatorsDomain(); - } + function _validatorMaxEffectiveBalance() internal pure virtual returns (uint256); /** - * @dev Initializes the V2 of the VaultValidators contract + * @dev Internal function for registering validators + * @param validators The concatenated validators data + * @param nonce The nonce of the signature + * @param validatorsManagerSignature The optional signature from the validators manager + * @param isTopUp Whether the registration is a balance top-up */ - function __VaultValidators_initV2() internal onlyInitializing { - // initialize domain separator - _initialDomainSeparator = _computeVaultValidatorsDomain(); + function _registerValidators( + bytes calldata validators, + bytes32 nonce, + bytes calldata validatorsManagerSignature, + bool isTopUp + ) private { + // check vault is up to date + _checkHarvested(); - // migrate deposit data variables to DepositDataRegistry contract - IDepositDataRegistry(_depositDataRegistry).migrate( - _validatorsRoot, - _validatorIndex, - _validatorsManager + // check access + if (!_isValidatorsManager(validators, nonce, validatorsManagerSignature)) { + revert Errors.AccessDenied(); + } + + // check validators length is valid + uint256 validatorsLength = validators.length; + bool isV1Validators = validatorsLength % _validatorV1DepositLength == 0; + bool isV2Validators = validatorsLength % _validatorV2DepositLength == 0; + if ( + validatorsLength == 0 || + (isV1Validators && isV2Validators) || + (!isV1Validators && !isV2Validators) + ) { + revert Errors.InvalidValidators(); + } + + // top up is only allowed for V2 validators + if (isTopUp && isV1Validators) { + revert Errors.CannotTopUpV1Validators(); + } + + uint256 _validatorDepositLength = ( + isV1Validators ? _validatorV1DepositLength : _validatorV2DepositLength ); + uint256 validatorsCount = validatorsLength / _validatorDepositLength; + + uint256 startIndex; + uint256 availableDeposits = withdrawableAssets(); + bytes calldata validators_ = validators; // push down the stack + for (uint256 i = 0; i < validatorsCount; ) { + (uint256 depositAmount, bytes calldata publicKey) = _registerValidator( + validators_[startIndex:startIndex + _validatorDepositLength], + isV1Validators + ); + availableDeposits -= depositAmount; + + bytes32 publicKeyHash = keccak256(publicKey); + if (isTopUp) { + // check whether validator is tracked in case of the top-up + if (!v2Validators[publicKeyHash]) revert Errors.InvalidValidators(); + emit ValidatorFunded(publicKey, depositAmount); + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorDepositLength; + } + continue; + } + + // check the registration amount + if ( + depositAmount > _validatorMaxEffectiveBalance() || + depositAmount < _validatorMinEffectiveBalance() + ) { + revert Errors.InvalidAssets(); + } + + // mark v2 validator public key as tracked + if (!isV1Validators) { + v2Validators[publicKeyHash] = true; + emit ValidatorRegistered(publicKey, depositAmount); + } else { + emit ValidatorRegistered(publicKey); + } - // clean up variables - delete _validatorsRoot; - delete _validatorIndex; - delete _validatorsManager; + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorDepositLength; + } + } } /** - * @dev Initializes the V3 of the VaultValidators contract + * @dev Internal function for checking whether the caller can withdraw validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager */ - function __VaultValidators_initV3() internal onlyInitializing { - // initialize domain separator - bytes32 newInitialDomainSeparator = _computeVaultValidatorsDomain(); - if (newInitialDomainSeparator != _initialDomainSeparator) { - _initialDomainSeparator = newInitialDomainSeparator; + function _checkCanWithdrawValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature + ) internal virtual; + + /** + * @dev Internal function for checking whether the caller is the validators manager. + * If the valid signature is provided, update the nonce. + * @param validators The concatenated validators data + * @param nonce The nonce of the signature + * @param validatorsManagerSignature The optional signature from the validators manager + * @return true if the caller is the validators manager + */ + function _isValidatorsManager( + bytes calldata validators, + bytes32 nonce, + bytes calldata validatorsManagerSignature + ) internal returns (bool) { + // SLOAD to memory + address validatorsManager_ = validatorsManager(); + if (msg.sender == validatorsManager_) { + return true; + } + + if ( + validatorsManager_ == address(0) || + validators.length == 0 || + validatorsManagerSignature.length == 0 + ) { + return false; + } + + // check signature + bool isValidSignature = SignatureChecker.isValidSignatureNow( + validatorsManager_, + _getValidatorsManagerSigningMessage(nonce, validators), + validatorsManagerSignature + ); + + // update signature nonce + if (isValidSignature) { + unchecked { + // cannot realistically overflow + validatorsManagerNonce += 1; + } } + + return isValidSignature; } /** - * @notice Get the hash to be signed by the validators manager - * @param keeperParams The keeper approval parameters - * @return The hash to be signed + * @notice Get the message to be signed by the validators manager + * @param nonce The nonce of the message + * @param validators The concatenated validators data + * @return The message to be signed */ - function _getSignedMessageHash( - IKeeperValidators.ApprovalParams calldata keeperParams + function _getValidatorsManagerSigningMessage( + bytes32 nonce, + bytes calldata validators ) private view returns (bytes32) { bytes32 domainSeparator = block.chainid == _initialChainId ? _initialDomainSeparator @@ -201,13 +487,7 @@ abstract contract VaultValidators is return MessageHashUtils.toTypedDataHash( domainSeparator, - keccak256( - abi.encode( - _registerValidatorsTypeHash, - keeperParams.validatorsRegistryRoot, - keccak256(keeperParams.validators) - ) - ) + keccak256(abi.encode(_validatorsManagerTypeHash, nonce, keccak256(validators))) ); } @@ -231,10 +511,44 @@ abstract contract VaultValidators is ); } + /** + * @dev Upgrades the VaultValidators contract + */ + function __VaultValidators_upgrade() internal onlyInitializing { + __ReentrancyGuard_init(); + // initialize domain separator + bytes32 newInitialDomainSeparator = _computeVaultValidatorsDomain(); + if (newInitialDomainSeparator != _initialDomainSeparator) { + _initialDomainSeparator = newInitialDomainSeparator; + } + + // migrate deposit data variables to DepositDataRegistry contract + if (__deprecated__validatorsRoot != bytes32(0)) { + IDepositDataRegistry(_depositDataRegistry).migrate( + __deprecated__validatorsRoot, + __deprecated__validatorIndex, + _validatorsManager + ); + delete __deprecated__validatorIndex; + delete __deprecated__validatorsRoot; + delete _validatorsManager; + } + } + + /** + * @dev Initializes the VaultValidators contract + * @dev NB! This initializer must be called after VaultState initializer + */ + function __VaultValidators_init() internal onlyInitializing { + __ReentrancyGuard_init(); + if (capacity() < _validatorMinEffectiveBalance()) revert Errors.InvalidCapacity(); + _initialDomainSeparator = _computeVaultValidatorsDomain(); + } + /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[49] private __gap; + uint256[47] private __gap; } diff --git a/foundry.toml b/foundry.toml index 0ce470b1..decb1c80 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,6 +4,12 @@ out = 'out' libs = ['node_modules', 'lib'] test = 'test' cache_path = 'cache_forge' -via_ir = true +via_ir = false solc = "0.8.22" -evm_version = "cancun" \ No newline at end of file +evm_version = "cancun" +optimizer = true +optimizer_runs = 1000 +ffi = true +ast = true +build_info = true +extra_output = ["storageLayout"] diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 00000000..3d5fa5c2 --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit 3d5fa5c24c411112bab47bec25cfa9ad0af0e6e8 diff --git a/lib/openzeppelin-foundry-upgrades b/lib/openzeppelin-foundry-upgrades new file mode 160000 index 00000000..cbce1e00 --- /dev/null +++ b/lib/openzeppelin-foundry-upgrades @@ -0,0 +1 @@ +Subproject commit cbce1e00305e943aa1661d43f41e5ac72c662b07 diff --git a/snapshots/DepositDataRegistryTest.json b/snapshots/DepositDataRegistryTest.json new file mode 100644 index 00000000..ed4b30fb --- /dev/null +++ b/snapshots/DepositDataRegistryTest.json @@ -0,0 +1,9 @@ +{ + "DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator": "287227", + "DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator": "287865", + "DepositDataRegistryTest_test_registerValidators_successWith0x01Validators": "347824", + "DepositDataRegistryTest_test_registerValidators_successWith0x02Validators": "349319", + "DepositDataRegistryTest_test_setDepositDataManager_succeeds": "64040", + "DepositDataRegistryTest_test_setDepositDataRoot_succeeds": "64979", + "DepositDataRegistryTest_test_updateVaultState_succeeds": "123935" +} \ No newline at end of file diff --git a/snapshots/GnoBlocklistErc20VaultTest.json b/snapshots/GnoBlocklistErc20VaultTest.json new file mode 100644 index 00000000..5880491e --- /dev/null +++ b/snapshots/GnoBlocklistErc20VaultTest.json @@ -0,0 +1,7 @@ +{ + "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "162316", + "GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161296", + "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "817154", + "GnoBlocklistErc20VaultTest_test_transfer": "61604", + "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "111723" +} \ No newline at end of file diff --git a/snapshots/GnoBlocklistVaultTest.json b/snapshots/GnoBlocklistVaultTest.json new file mode 100644 index 00000000..4dc89d1e --- /dev/null +++ b/snapshots/GnoBlocklistVaultTest.json @@ -0,0 +1,6 @@ +{ + "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "160362", + "GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161279", + "GnoBlocklistVaultTest_test_deploysCorrectly": "535557", + "GnoBlocklistVaultTest_test_upgradesCorrectly": "111056" +} \ No newline at end of file diff --git a/snapshots/GnoErc20VaultTest.json b/snapshots/GnoErc20VaultTest.json new file mode 100644 index 00000000..727df3be --- /dev/null +++ b/snapshots/GnoErc20VaultTest.json @@ -0,0 +1,12 @@ +{ + "GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv": "89861", + "GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "95982", + "GnoErc20VaultTest_test_deploysCorrectly": "585920", + "GnoErc20VaultTest_test_deposit_emitsTransfer": "100513", + "GnoErc20VaultTest_test_enterExitQueue_emitsTransfer": "89588", + "GnoErc20VaultTest_test_redeem_emitsEvent": "76768", + "GnoErc20VaultTest_test_upgradesCorrectly": "111580", + "VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "66365", + "VaultGnoErc20VaultTest_test_withdrawValidator_unknown": "51492", + "VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager": "61047" +} \ No newline at end of file diff --git a/snapshots/GnoGenesisVaultTest.json b/snapshots/GnoGenesisVaultTest.json new file mode 100644 index 00000000..ee2d2629 --- /dev/null +++ b/snapshots/GnoGenesisVaultTest.json @@ -0,0 +1,5 @@ +{ + "GnoGenesisVaultTest_test_migrate_works": "201309", + "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "769734", + "GnoGenesisVaultTest_test_upgradesCorrectly": "6448921" +} \ No newline at end of file diff --git a/snapshots/GnoOsTokenVaultEscrowTest.json b/snapshots/GnoOsTokenVaultEscrowTest.json new file mode 100644 index 00000000..31d1352b --- /dev/null +++ b/snapshots/GnoOsTokenVaultEscrowTest.json @@ -0,0 +1,5 @@ +{ + "GnoOsTokenVaultEscrowTest_test_transferAssets_claim": "118345", + "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "713279", + "GnoOsTokenVaultEscrowTest_test_transferAssets_transfer": "163008" +} \ No newline at end of file diff --git a/snapshots/GnoOwnMevEscrowTest.json b/snapshots/GnoOwnMevEscrowTest.json new file mode 100644 index 00000000..16b8527c --- /dev/null +++ b/snapshots/GnoOwnMevEscrowTest.json @@ -0,0 +1,3 @@ +{ + "GnoOwnMevEscrowTest_test_ownMevEscrowDeploymentGas": "252843" +} \ No newline at end of file diff --git a/snapshots/GnoPrivErc20VaultTest.json b/snapshots/GnoPrivErc20VaultTest.json new file mode 100644 index 00000000..c4e99689 --- /dev/null +++ b/snapshots/GnoPrivErc20VaultTest.json @@ -0,0 +1,7 @@ +{ + "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "158245", + "GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161315", + "GnoPrivErc20VaultTest_test_deploysCorrectly": "817176", + "GnoPrivErc20VaultTest_test_transfer": "59533", + "GnoPrivErc20VaultTest_test_upgradesCorrectly": "111749" +} \ No newline at end of file diff --git a/snapshots/GnoPrivVaultTest.json b/snapshots/GnoPrivVaultTest.json new file mode 100644 index 00000000..62e2617a --- /dev/null +++ b/snapshots/GnoPrivVaultTest.json @@ -0,0 +1,8 @@ +{ + "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "156378", + "GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161298", + "GnoPrivVaultTest_test_deploysCorrectly": "535512", + "GnoPrivVaultTest_test_setWhitelister": "36440", + "GnoPrivVaultTest_test_updateWhitelist": "54390", + "GnoPrivVaultTest_test_upgradesCorrectly": "111036" +} \ No newline at end of file diff --git a/snapshots/GnoSharedMevEscrowTest.json b/snapshots/GnoSharedMevEscrowTest.json new file mode 100644 index 00000000..9408113d --- /dev/null +++ b/snapshots/GnoSharedMevEscrowTest.json @@ -0,0 +1,3 @@ +{ + "GnoSharedMevEscrowTest_test_sharedEscrowDeploymentGas": "259099" +} \ No newline at end of file diff --git a/snapshots/GnoVaultTest.json b/snapshots/GnoVaultTest.json new file mode 100644 index 00000000..bb9156bb --- /dev/null +++ b/snapshots/GnoVaultTest.json @@ -0,0 +1,8 @@ +{ + "GnoVaultTest_test_deploysCorrectly": "511667", + "GnoVaultTest_test_exitQueue_works": "94571", + "GnoVaultTest_test_upgradesCorrectly": "110935", + "GnoVaultTest_test_withdrawValidator_osTokenRedeemer": "66354", + "GnoVaultTest_test_withdrawValidator_unknown": "51481", + "GnoVaultTest_test_withdrawValidator_validatorsManager": "61025" +} \ No newline at end of file diff --git a/snapshots/VaultGnoStakingTest.json b/snapshots/VaultGnoStakingTest.json new file mode 100644 index 00000000..c1e01b88 --- /dev/null +++ b/snapshots/VaultGnoStakingTest.json @@ -0,0 +1,14 @@ +{ + "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "136389", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid": "129765", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "164448", + "VaultGnoStakingTest_test_deposit": "100895", + "VaultGnoStakingTest_test_processTotalAssetsDelta": "219087", + "VaultGnoStakingTest_test_pullWithdrawals": "85025", + "VaultGnoStakingTest_test_receive_xDai": "33397", + "VaultGnoStakingTest_test_transferVaultAssets": "81956", + "VaultGnoStakingTest_test_vaultGnoStaking_init": "511667", + "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "61019", + "test_registerValidators_succeeds_0x01": "297898", + "test_registerValidators_succeeds_0x02": "488267" +} \ No newline at end of file diff --git a/test/ConsolidationsChecker.t.sol b/test/ConsolidationsChecker.t.sol new file mode 100644 index 00000000..e9cfa2c8 --- /dev/null +++ b/test/ConsolidationsChecker.t.sol @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {ConsolidationsChecker} from '../contracts/validators/ConsolidationsChecker.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; + +contract ConsolidationsCheckerTest is Test, EthHelpers { + ForkContracts public contracts; + ConsolidationsChecker public consolidationsChecker; + + address public admin; + address public vault; + + // Oracle-related variables + address[] private _oracleAddresses; + uint256[] private _oraclePrivateKeys; + uint256 private _validatorsMinOraclesBefore; + + // Constants for testing + uint256 private constant SIGNATURE_LENGTH = 65; + bytes32 private constant _consolidationsCheckerTypeHash = + keccak256('ConsolidationsChecker(address vault,bytes validators)'); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + consolidationsChecker = ConsolidationsChecker(address(contracts.consolidationsChecker)); + + // Set up test accounts + admin = makeAddr('admin'); + vault = makeAddr('vault'); + + // Store initial min oracles value + _validatorsMinOraclesBefore = contracts.keeper.validatorsMinOracles(); + + // Create test oracles (we'll create 4 oracles) + _oracleAddresses = new address[](4); + _oraclePrivateKeys = new uint256[](4); + + for (uint i = 0; i < 4; i++) { + (_oracleAddresses[i], _oraclePrivateKeys[i]) = makeAddrAndKey( + string(abi.encodePacked('oracle', vm.toString(i))) + ); + } + + // Configure keeper with our test oracles + _setupOracles(); + } + + function tearDown() public { + // Clean up oracles to restore original state + _cleanupOracles(); + } + + // Setup oracle configuration for testing + function _setupOracles() internal { + vm.startPrank(contracts.keeper.owner()); + + // Set min oracles to 3 for testing + contracts.keeper.setValidatorsMinOracles(3); + + // Add our test oracles + for (uint i = 0; i < _oracleAddresses.length; i++) { + contracts.keeper.addOracle(_oracleAddresses[i]); + } + + vm.stopPrank(); + } + + // Cleanup after tests + function _cleanupOracles() internal { + vm.startPrank(contracts.keeper.owner()); + + // Remove test oracles + for (uint i = 0; i < _oracleAddresses.length; i++) { + if (contracts.keeper.isOracle(_oracleAddresses[i])) { + contracts.keeper.removeOracle(_oracleAddresses[i]); + } + } + + // Restore original min oracles setting + contracts.keeper.setValidatorsMinOracles(_validatorsMinOraclesBefore); + + vm.stopPrank(); + } + + // Helper to create a message hash for signing + function _getMessageHash( + address _vault, + bytes memory validators + ) internal view returns (bytes32) { + bytes32 domainSeparator = keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256('ConsolidationsChecker'), + keccak256('1'), + block.chainid, + address(consolidationsChecker) + ) + ); + + bytes32 structHash = keccak256( + abi.encode(_consolidationsCheckerTypeHash, _vault, keccak256(validators)) + ); + + return MessageHashUtils.toTypedDataHash(domainSeparator, structHash); + } + + // Helper to generate valid signatures for test oracles + function _generateValidSignatures( + address _vault, + bytes memory validators, + uint numSigners + ) internal returns (bytes memory) { + require(numSigners <= _oracleAddresses.length, 'Too many signers requested'); + + bytes32 messageHash = _getMessageHash(_vault, validators); + bytes memory signatures = new bytes(0); + + // Create signatures from oracles in ascending order + address[] memory signers = new address[](numSigners); + for (uint i = 0; i < numSigners; i++) { + signers[i] = _oracleAddresses[i]; + } + + // Sort signers by address (ascending) + for (uint i = 0; i < signers.length; i++) { + for (uint j = i + 1; j < signers.length; j++) { + if (signers[i] > signers[j]) { + address temp = signers[i]; + signers[i] = signers[j]; + signers[j] = temp; + + // Also swap corresponding private keys + uint256 tempKey = _oraclePrivateKeys[i]; + _oraclePrivateKeys[i] = _oraclePrivateKeys[j]; + _oraclePrivateKeys[j] = tempKey; + } + } + } + + // Generate signatures + for (uint i = 0; i < numSigners; i++) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKeys[i], messageHash); + signatures = bytes.concat(signatures, abi.encodePacked(r, s, v)); + } + + return signatures; + } + + // Helper function to create a deterministic validator public key (48 bytes) + function _createPublicKey(string memory seed) internal pure returns (bytes memory) { + // Create a deterministic bytes array based on the seed + bytes32 hash = keccak256(abi.encodePacked(seed)); + bytes memory result = new bytes(48); + + // Use the hash to fill the first 32 bytes + for (uint i = 0; i < 32; i++) { + result[i] = hash[i]; + } + + // Fill the remaining 16 bytes with values derived from the hash + for (uint i = 32; i < 48; i++) { + result[i] = hash[i - 32]; + } + + return result; + } + + // Test successful signature verification + function test_verifySignatures_success() public { + // Create test validator data with proper length public keys (48 bytes each) + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate valid signatures from the required number of oracles + bytes memory validSignatures = _generateValidSignatures( + vault, + validatorsData, + contracts.keeper.validatorsMinOracles() + ); + + // Verify that signature verification succeeds + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_success'); + consolidationsChecker.verifySignatures(vault, validatorsData, validSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, validSignatures); + assertTrue(isValid, 'Signatures should be valid'); + } + + // Test failure with too few signatures + function test_verifySignatures_tooFewSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Required signatures is 3, generate only 2 + bytes memory insufficientSignatures = _generateValidSignatures(vault, validatorsData, 2); + + // Verify that signature verification fails + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_tooFewSignatures'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, insufficientSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures( + vault, + validatorsData, + insufficientSignatures + ); + assertFalse(isValid, 'Signatures should be invalid due to insufficient count'); + } + + // Test failure with unsorted signatures + function test_verifySignatures_unsortedSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create message hash for signing + bytes32 messageHash = _getMessageHash(vault, validatorsData); + + // Generate unsorted signatures manually + bytes memory unsortedSignatures = new bytes(0); + + // Generate in reverse order (assuming _oracleAddresses is not already sorted) + for (uint i = 3; i > 0; i--) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKeys[i - 1], messageHash); + unsortedSignatures = bytes.concat(unsortedSignatures, abi.encodePacked(r, s, v)); + } + + // Verify that signature verification fails + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_unsortedSignatures'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, unsortedSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures( + vault, + validatorsData, + unsortedSignatures + ); + assertFalse(isValid, 'Signatures should be invalid due to incorrect ordering'); + } + + // Test failure with repeated signer + function test_verifySignatures_repeatedSigner() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create message hash for signing + bytes32 messageHash = _getMessageHash(vault, validatorsData); + + // Generate signatures with a repeated signer + bytes memory repeatedSignatures = new bytes(0); + + // First oracle signs + (uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(_oraclePrivateKeys[0], messageHash); + repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r1, s1, v1)); + + // Second oracle signs + (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(_oraclePrivateKeys[1], messageHash); + repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r2, s2, v2)); + + // First oracle signs again (repeated) + repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r1, s1, v1)); + + // Verify that signature verification fails + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_repeatedSigner'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, repeatedSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures( + vault, + validatorsData, + repeatedSignatures + ); + assertFalse(isValid, 'Signatures should be invalid due to repeated signer'); + } + + // Test failure with non-oracle signer + function test_verifySignatures_nonOracleSigner() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create message hash for signing + bytes32 messageHash = _getMessageHash(vault, validatorsData); + + // Create a non-oracle signer + (, uint256 nonOracleKey) = makeAddrAndKey('nonOracle'); + + // Generate signatures with a non-oracle signer + bytes memory invalidSignatures = new bytes(0); + + // First valid oracle signs + (uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(_oraclePrivateKeys[0], messageHash); + invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r1, s1, v1)); + + // Non-oracle signer signs + (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(nonOracleKey, messageHash); + invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r2, s2, v2)); + + bytes memory validatorsData_ = validatorsData; + + // Third valid oracle signs + (uint8 v3, bytes32 r3, bytes32 s3) = vm.sign(_oraclePrivateKeys[2], messageHash); + invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r3, s3, v3)); + + // Verify that signature verification fails + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_nonOracleSigner'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData_, invalidSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures( + vault, + validatorsData_, + invalidSignatures + ); + assertFalse(isValid, 'Signatures should be invalid due to non-oracle signer'); + } + + // Test with empty signatures + function test_verifySignatures_emptySignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Empty signatures + bytes memory emptySignatures = new bytes(0); + + // Verify that signature verification fails + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_emptySignatures'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, emptySignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, emptySignatures); + assertFalse(isValid, 'Signatures should be invalid because they are empty'); + } + + // Test with minimum required signatures (edge case) + function test_verifySignatures_exactMinimumSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate signatures with exactly the minimum required number of oracles + bytes memory signatures = _generateValidSignatures( + vault, + validatorsData, + contracts.keeper.validatorsMinOracles() + ); + + // Verify that signature verification succeeds + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_exactMinimumSignatures'); + consolidationsChecker.verifySignatures(vault, validatorsData, signatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, signatures); + assertTrue(isValid, 'Signatures should be valid with exactly minimum required signatures'); + } + + // Test with more than minimum required signatures + function test_verifySignatures_moreThanMinimumSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate signatures with more than the minimum required number of oracles + bytes memory signatures = _generateValidSignatures( + vault, + validatorsData, + contracts.keeper.validatorsMinOracles() + 1 + ); + + // Verify that signature verification succeeds + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_moreThanMinimumSignatures'); + consolidationsChecker.verifySignatures(vault, validatorsData, signatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, signatures); + assertTrue(isValid, 'Signatures should be valid with more than minimum required signatures'); + } + + // Test with different validator data + function test_verifySignatures_differentValidatorData() public { + // Create test validator data sets with different public keys + bytes memory sourcePublicKey1 = _createPublicKey('source_key_1'); + bytes memory destPublicKey1 = _createPublicKey('dest_key_1'); + bytes memory validatorsData1 = bytes.concat(sourcePublicKey1, destPublicKey1); + + bytes memory sourcePublicKey2 = _createPublicKey('source_key_2'); + bytes memory destPublicKey2 = _createPublicKey('dest_key_2'); + bytes memory validatorsData2 = bytes.concat(sourcePublicKey2, destPublicKey2); + + // Generate valid signatures for validatorsData1 + bytes memory validSignatures = _generateValidSignatures( + vault, + validatorsData1, + contracts.keeper.validatorsMinOracles() + ); + + // Try to verify signatures with validatorsData2 + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_differentValidatorData'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData2, validSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData2, validSignatures); + assertFalse(isValid, 'Signatures should be invalid for different validator data'); + } + + // Test with different vault address + function test_verifySignatures_differentVault() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey('source_key'); + bytes memory destPublicKey = _createPublicKey('dest_key'); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate valid signatures for original vault + bytes memory validSignatures = _generateValidSignatures( + vault, + validatorsData, + contracts.keeper.validatorsMinOracles() + ); + + // Create a different vault address + address differentVault = makeAddr('differentVault'); + + // Try to verify signatures with different vault + _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_differentVault'); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(differentVault, validatorsData, validSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures( + differentVault, + validatorsData, + validSignatures + ); + assertFalse(isValid, 'Signatures should be invalid for different vault address'); + } +} diff --git a/test/DepositDataRegistry.spec.ts b/test/DepositDataRegistry.spec.ts deleted file mode 100644 index c0c749bb..00000000 --- a/test/DepositDataRegistry.spec.ts +++ /dev/null @@ -1,466 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { UintNumberType } from '@chainsafe/ssz' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - DepositDataRegistry, - EthVault, - IKeeperRewards, - IKeeperValidators, - Keeper, - VaultsRegistry, -} from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { expect } from './shared/expect' -import { setBalance, toHexString } from './shared/utils' -import { - createEthValidatorsData, - EthValidatorsData, - exitSignatureIpfsHashes, - getEthValidatorsSigningData, - getValidatorProof, - getValidatorsMultiProof, - getWithdrawalCredentials, - ValidatorsMultiProof, -} from './shared/validators' -import { - deployEthVaultV1, - encodeEthVaultInitParams, - ethVaultFixture, - getOraclesSignatures, -} from './shared/fixtures' -import { - MAX_UINT256, - PANIC_CODES, - VALIDATORS_DEADLINE, - VALIDATORS_MIN_ORACLES, - ZERO_ADDRESS, - ZERO_BYTES32, -} from './shared/constants' -import { getEthVaultV1Factory } from './shared/contracts' -import { getHarvestParams, getRewardsRootProof, updateRewards } from './shared/rewards' - -const gwei = 1000000000n -const uintSerializer = new UintNumberType(8) - -describe('DepositDataRegistry', () => { - const validatorDeposit = ethers.parseEther('32') - const capacity = MAX_UINT256 - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const deadline = VALIDATORS_DEADLINE - - let admin: Signer, other: Wallet, manager: Wallet, dao: Wallet - let vault: EthVault, - keeper: Keeper, - validatorsRegistry: Contract, - vaultsRegistry: VaultsRegistry, - depositDataRegistry: DepositDataRegistry, - v1Vault: Contract - let validatorsData: EthValidatorsData - let validatorsRegistryRoot: string - - before('create fixture loader', async () => { - ;[dao, admin, other, manager] = await (ethers as any).getSigners() - }) - - beforeEach('deploy fixture', async () => { - const fixture = await loadFixture(ethVaultFixture) - validatorsRegistry = fixture.validatorsRegistry - keeper = fixture.keeper - depositDataRegistry = fixture.depositDataRegistry - vaultsRegistry = fixture.vaultsRegistry - - vault = await fixture.createEthVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - v1Vault = await deployEthVaultV1( - await getEthVaultV1Factory(), - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - fixture.osTokenVaultController, - fixture.osTokenConfig, - fixture.sharedMevEscrow, - encodeEthVaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - }) - ) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - validatorsData = await createEthValidatorsData(vault) - validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: validatorDeposit }) - }) - - describe('deposit data manager update', () => { - it('fails for non-vault', async () => { - await expect( - depositDataRegistry.connect(admin).setDepositDataManager(other.address, manager.address) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - - it('fails for V1 vault', async () => { - await expect( - depositDataRegistry - .connect(admin) - .setDepositDataManager(await v1Vault.getAddress(), manager.address) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - - it('fails for non-admin', async () => { - await expect( - depositDataRegistry - .connect(other) - .setDepositDataManager(await vault.getAddress(), manager.address) - ).to.be.revertedWithCustomError(depositDataRegistry, 'AccessDenied') - }) - - it('succeeds', async () => { - const vaultAddr = await vault.getAddress() - const adminAddr = await admin.getAddress() - expect(await depositDataRegistry.getDepositDataManager(vaultAddr)).to.eq(adminAddr) - const receipt = await depositDataRegistry - .connect(admin) - .setDepositDataManager(vaultAddr, manager.address) - await expect(receipt) - .to.emit(depositDataRegistry, 'DepositDataManagerUpdated') - .withArgs(vaultAddr, manager.address) - expect(await depositDataRegistry.getDepositDataManager(vaultAddr)).to.eq(manager.address) - await snapshotGasCost(receipt) - }) - }) - - describe('deposit data root update', () => { - beforeEach('set manager', async () => { - await depositDataRegistry - .connect(admin) - .setDepositDataManager(await vault.getAddress(), manager.address) - }) - - it('fails for invalid vault', async () => { - await expect( - depositDataRegistry.connect(manager).setDepositDataRoot(other.address, validatorsData.root) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - - it('fails for V1 vault', async () => { - await expect( - depositDataRegistry - .connect(admin) - .setDepositDataRoot(await v1Vault.getAddress(), validatorsData.root) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - - it('fails from non-manager', async () => { - await expect( - depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), validatorsData.root) - ).to.be.revertedWithCustomError(depositDataRegistry, 'AccessDenied') - }) - - it('fails for same root', async () => { - const vaultAddr = await vault.getAddress() - await depositDataRegistry.connect(manager).setDepositDataRoot(vaultAddr, validatorsData.root) - await expect( - depositDataRegistry.connect(manager).setDepositDataRoot(vaultAddr, validatorsData.root) - ).to.be.revertedWithCustomError(depositDataRegistry, 'ValueNotChanged') - }) - - it('success', async () => { - const vaultAddr = await vault.getAddress() - const receipt = await depositDataRegistry - .connect(manager) - .setDepositDataRoot(vaultAddr, validatorsData.root) - await expect(receipt) - .to.emit(depositDataRegistry, 'DepositDataRootUpdated') - .withArgs(vaultAddr, validatorsData.root) - await snapshotGasCost(receipt) - }) - }) - - describe('single validator', () => { - let validator: Buffer - let proof: string[] - let approvalParams: IKeeperValidators.ApprovalParamsStruct - - beforeEach(async () => { - validator = validatorsData.validators[0] - proof = getValidatorProof(validatorsData.tree, validator, 0) - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), validatorsData.root) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - validator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - approvalParams = { - validatorsRegistryRoot, - validators: validator, - signatures, - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails for invalid vault', async () => { - await expect( - depositDataRegistry.registerValidator(other.address, approvalParams, proof) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - - it('fails with invalid proof', async () => { - const invalidProof = getValidatorProof(validatorsData.tree, validatorsData.validators[1], 1) - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - approvalParams, - invalidProof - ) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidProof') - }) - - it('can update state and register validator', async () => { - const vaultAddress = await vault.getAddress() - const vaultReward = getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - - const calls: string[] = [ - depositDataRegistry.interface.encodeFunctionData('updateVaultState', [ - vaultAddress, - harvestParams, - ]), - depositDataRegistry.interface.encodeFunctionData('registerValidator', [ - vaultAddress, - approvalParams, - proof, - ]), - ] - const receipt = await depositDataRegistry.multicall(calls) - const publicKey = `0x${validator.subarray(0, 48).toString('hex')}` - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await snapshotGasCost(receipt) - }) - - it('succeeds', async () => { - const index = await validatorsRegistry.get_deposit_count() - const receipt = await depositDataRegistry.registerValidator( - await vault.getAddress(), - approvalParams, - proof - ) - const publicKey = `0x${validator.subarray(0, 48).toString('hex')}` - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - index - ) - expect(await depositDataRegistry.depositDataIndexes(await vault.getAddress())).to.eq(1) - - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), ZERO_BYTES32) - expect(await depositDataRegistry.depositDataIndexes(await vault.getAddress())).to.eq(0) - await snapshotGasCost(receipt) - }) - }) - - describe('multiple validators', () => { - let validators: Buffer[] - let indexes: number[] - let approvalParams: IKeeperValidators.ApprovalParamsStruct - let multiProof: ValidatorsMultiProof - let signatures: Buffer - - beforeEach(async () => { - multiProof = getValidatorsMultiProof(validatorsData.tree, validatorsData.validators, [ - ...Array(validatorsData.validators.length).keys(), - ]) - validators = validatorsData.validators - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const sortedVals = multiProof.leaves.map((v) => v[0]) - const vaultAddr = await vault.getAddress() - await depositDataRegistry.connect(admin).setDepositDataRoot(vaultAddr, validatorsData.root) - indexes = validators.map((v) => sortedVals.indexOf(v)) - const balance = - validatorDeposit * BigInt(validators.length) + (await ethers.provider.getBalance(vaultAddr)) - await setBalance(vaultAddr, balance) - signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.concat(validators), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - approvalParams = { - validatorsRegistryRoot, - validators: Buffer.concat(validators), - signatures, - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails for invalid vault', async () => { - await expect( - depositDataRegistry.registerValidators( - other.address, - approvalParams, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - - it('fails with invalid validators count', async () => { - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - validators: Buffer.from(''), - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.from(''), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - }) - - it('fails with invalid proof', async () => { - const invalidMultiProof = getValidatorsMultiProof( - validatorsData.tree, - validators.slice(1), - [...Array(validatorsData.validators.length).keys()].slice(1) - ) - - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - indexes, - invalidMultiProof.proofFlags, - invalidMultiProof.proof - ) - ).to.be.revertedWithCustomError(depositDataRegistry, 'MerkleProofInvalidMultiproof') - }) - - it('fails with invalid indexes', async () => { - const vaultAddr = await vault.getAddress() - await expect( - depositDataRegistry.registerValidators( - vaultAddr, - approvalParams, - [], - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidValidators') - - await expect( - depositDataRegistry.registerValidators( - vaultAddr, - approvalParams, - indexes.map((i) => i + 1), - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithPanic(PANIC_CODES.OUT_OF_BOUND_INDEX) - - await expect( - depositDataRegistry.registerValidators( - vaultAddr, - approvalParams, - indexes.sort(() => 0.5 - Math.random()), - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidProof') - }) - - it('succeeds', async () => { - const startIndex = uintSerializer.deserialize( - ethers.getBytes(await validatorsRegistry.get_deposit_count()) - ) - const vaultAddress = await vault.getAddress() - const receipt = await depositDataRegistry.registerValidators( - vaultAddress, - approvalParams, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - for (let i = 0; i < validators.length; i++) { - const validator = validators[i] - const publicKey = toHexString(validator.subarray(0, 48)) - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - toHexString(Buffer.from(uintSerializer.serialize(startIndex + i))) - ) - } - expect(await depositDataRegistry.depositDataIndexes(vaultAddress)).to.eq(validators.length) - await snapshotGasCost(receipt) - }) - }) - - describe('migrate', () => { - beforeEach('add vault', async () => { - await vaultsRegistry.connect(dao).addVault(other.address) - }) - - it('fails for non-vault', async () => { - await expect( - depositDataRegistry.connect(admin).migrate(validatorsData.root, 0, manager.address) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidVault') - }) - }) -}) diff --git a/test/DepositDataRegistry.t.sol b/test/DepositDataRegistry.t.sol new file mode 100644 index 00000000..15326e21 --- /dev/null +++ b/test/DepositDataRegistry.t.sol @@ -0,0 +1,768 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from '../lib/forge-std/src/Test.sol'; +import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IDepositDataRegistry} from '../contracts/interfaces/IDepositDataRegistry.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; +import {IVaultVersion} from '../contracts/interfaces/IVaultVersion.sol'; +import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; +import {IVaultsRegistry} from '../contracts/interfaces/IVaultsRegistry.sol'; + +interface IVaultValidatorsV1 { + function validatorsRoot() external view returns (bytes32); + function validatorIndex() external view returns (uint256); + function keysManager() external view returns (address); +} + +contract DepositDataRegistryTest is Test, EthHelpers { + ForkContracts private contracts; + IDepositDataRegistry private depositDataRegistry; + address private validVault; + address private invalidVault; + address private lowVersionVault; + address private admin; + address private nonAdmin; + address private newDepositDataManager; + uint256 private exitingAssets; + + function setUp() public { + contracts = _activateEthereumFork(); + + // Get existing deposit data registry + depositDataRegistry = IDepositDataRegistry(_depositDataRegistry); + + // Create a valid vault (version >= 2) + admin = makeAddr('admin'); + validVault = _getOrCreateVault( + VaultType.EthVault, + admin, + abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'metadataIpfsHash' + }) + ), + false + ); + exitingAssets = + IEthVault(validVault).totalExitingAssets() + + IEthVault(validVault).convertToAssets(IEthVault(validVault).queuedShares()) + + address(validVault).balance; + + invalidVault = makeAddr('invalidVault'); + nonAdmin = makeAddr('nonAdmin'); + newDepositDataManager = makeAddr('newDepositDataManager'); + + // Create or mock a vault with version < 2 + // For this test, we'll simulate a vault with version 1 + lowVersionVault = makeAddr('lowVersionVault'); + vm.mockCall( + lowVersionVault, + abi.encodeWithSelector(IVaultVersion.version.selector), + abi.encode(uint8(1)) + ); + + // Mock that lowVersionVault is registered in the vaults registry + vm.mockCall( + address(contracts.vaultsRegistry), + abi.encodeWithSelector(IVaultsRegistry.vaults.selector, lowVersionVault), + abi.encode(true) + ); + } + + function test_setDepositDataManager_failsForInvalidVault() public { + // Attempt to set deposit data manager for an invalid vault + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataManager(invalidVault, newDepositDataManager); + } + + function test_setDepositDataManager_failsForInvalidVaultVersion() public { + // Attempt to set deposit data manager for a vault with version < 2 + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataManager(lowVersionVault, newDepositDataManager); + } + + function test_setDepositDataManager_failsForNonAdmin() public { + // Attempt to set deposit data manager by a non-admin + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + depositDataRegistry.setDepositDataManager(validVault, newDepositDataManager); + } + + function test_setDepositDataManager_succeeds() public { + // Verify current deposit data manager before change + address initialManager = depositDataRegistry.getDepositDataManager(validVault); + + // Set new deposit data manager by the admin + vm.prank(admin); + + // Expect the DepositDataManagerUpdated event + vm.expectEmit(true, true, false, false); + emit IDepositDataRegistry.DepositDataManagerUpdated(validVault, newDepositDataManager); + + // Execute the function + _startSnapshotGas('DepositDataRegistryTest_test_setDepositDataManager_succeeds'); + depositDataRegistry.setDepositDataManager(validVault, newDepositDataManager); + _stopSnapshotGas(); + + // Verify deposit data manager was updated + address updatedManager = depositDataRegistry.getDepositDataManager(validVault); + assertEq(updatedManager, newDepositDataManager, 'Deposit data manager not updated correctly'); + assertNotEq(updatedManager, initialManager, 'Deposit data manager should have changed'); + } + + function test_setDepositDataRoot_failsForInvalidVault() public { + // Attempt to set deposit data root for an invalid vault + bytes32 newRoot = bytes32(uint256(1)); + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataRoot(invalidVault, newRoot); + } + + function test_setDepositDataRoot_failsForInvalidVaultVersion() public { + // Attempt to set deposit data root for a vault with version < 2 + bytes32 newRoot = bytes32(uint256(1)); + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataRoot(lowVersionVault, newRoot); + } + + function test_setDepositDataRoot_failsForNonDepositDataManager() public { + // Attempt to set deposit data root by a non-deposit data manager + bytes32 newRoot = bytes32(uint256(1)); + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + depositDataRegistry.setDepositDataRoot(validVault, newRoot); + } + + function test_setDepositDataRoot_failsForSameValue() public { + // First set initial deposit data root + bytes32 initialRoot = bytes32(uint256(1)); + + // Set the deposit data manager to admin for this test + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + + // Set initial deposit data root + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, initialRoot); + + // Attempt to set the same deposit data root + vm.prank(admin); + vm.expectRevert(Errors.ValueNotChanged.selector); + depositDataRegistry.setDepositDataRoot(validVault, initialRoot); + } + + function test_setDepositDataRoot_succeeds() public { + // Set up initial values + bytes32 newRoot = bytes32(uint256(1)); + + // Set the deposit data manager to admin for this test + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + + // Set deposit data root by the deposit data manager + vm.prank(admin); + + // Expect the DepositDataRootUpdated event + vm.expectEmit(true, false, false, false); + emit IDepositDataRegistry.DepositDataRootUpdated(validVault, newRoot); + + // Execute the function + _startSnapshotGas('DepositDataRegistryTest_test_setDepositDataRoot_succeeds'); + depositDataRegistry.setDepositDataRoot(validVault, newRoot); + _stopSnapshotGas(); + + // Verify deposit data root was updated + bytes32 updatedRoot = depositDataRegistry.depositDataRoots(validVault); + assertEq(updatedRoot, newRoot, 'Deposit data root not updated correctly'); + + // Verify deposit data index was reset to 0 + uint256 updatedIndex = depositDataRegistry.depositDataIndexes(validVault); + assertEq(updatedIndex, 0, 'Deposit data index not reset to 0'); + } + + function test_updateVaultState_succeeds() public { + // Prepare the vault for testing + _collateralizeEthVault(validVault); + + // Generate harvest params with some reward + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + validVault, + int160(1 ether), // totalReward - simulating 1 ETH of rewards + uint160(0) // unlockedMevReward - no MEV rewards for this test + ); + + // Record the initial state of the vault + uint256 initialTotalAssets = IEthVault(validVault).totalAssets(); + + // Execute the updateVaultState function + _startSnapshotGas('DepositDataRegistryTest_test_updateVaultState_succeeds'); + depositDataRegistry.updateVaultState(validVault, harvestParams); + _stopSnapshotGas(); + + // Verify that the vault state was updated + uint256 updatedTotalAssets = IEthVault(validVault).totalAssets(); + + // The total assets should have increased by the reward amount + assertGt( + updatedTotalAssets, + initialTotalAssets, + 'Vault total assets should have increased after state update' + ); + + // We can also verify that the vault is no longer requiring a state update + bool stateUpdateRequired = IEthVault(validVault).isStateUpdateRequired(); + assertFalse( + stateUpdateRequired, + 'Vault should not require state update after calling updateVaultState' + ); + } + + function test_registerValidator_failsForInvalidVault() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + _stopOracleImpersonate(address(contracts.keeper)); + + bytes32[] memory proof = new bytes32[](0); + + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidator(invalidVault, keeperParams, proof); + } + function test_registerValidator_failsForInvalidVaultVersion() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + lowVersionVault, + 'ipfsHash', + deposits, + true + ); + _stopOracleImpersonate(address(contracts.keeper)); + + bytes32[] memory proof = new bytes32[](0); + + // Attempt to register validator for a vault with version < 2 + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidator(lowVersionVault, keeperParams, proof); + } + + function test_registerValidator_failsWithInvalidProof() public { + vm.deal(validVault, exitingAssets + 32 ether); + + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + + // Create a deposit data root that doesn't match the validator + bytes32 depositDataRoot = keccak256('incorrect_root'); + + // Create an invalid proof that doesn't prove the validator is in the tree + bytes32[] memory invalidProof = new bytes32[](1); + invalidProof[0] = bytes32(uint256(123)); // Some random value + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Attempt to register with invalid proof + vm.expectRevert(Errors.InvalidProof.selector); + depositDataRegistry.registerValidator(validVault, keeperParams, invalidProof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidator_succeedsWith0x01Validator() public { + vm.deal(validVault, exitingAssets + 32 ether); + + uint256 validatorIndex = 0; + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + + // Create root + bytes32 depositDataRoot = keccak256( + bytes.concat(keccak256(abi.encode(keeperParams.validators, validatorIndex))) + ); + bytes32[] memory proof = new bytes32[](0); + + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + _startSnapshotGas('DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator'); + depositDataRegistry.registerValidator(validVault, keeperParams, proof); + _stopSnapshotGas(); + + _stopOracleImpersonate(address(contracts.keeper)); + + // Verify the validator index was incremented + assertEq( + depositDataRegistry.depositDataIndexes(validVault), + 1, + 'Validator index should be incremented' + ); + } + + function test_registerValidator_succeedsWith0x02Validator() public { + vm.deal(validVault, exitingAssets + 67 ether); + + uint256 validatorIndex = 0; + uint256[] memory deposits = new uint256[](1); + deposits[0] = 67 ether / 1 gwei; // 67 ETH + + _startOracleImpersonate(address(contracts.keeper)); + // Create a 0x02 validator (isV1Validator = false) + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + false // 0x02 validator + ); + + // Create root for the validator + bytes32 depositDataRoot = keccak256( + bytes.concat(keccak256(abi.encode(keeperParams.validators, validatorIndex))) + ); + + // Empty proof for a single validator + bytes32[] memory proof = new bytes32[](0); + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Register validator + _startSnapshotGas('DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator'); + depositDataRegistry.registerValidator(validVault, keeperParams, proof); + _stopSnapshotGas(); + + _stopOracleImpersonate(address(contracts.keeper)); + + // Verify the validator index was incremented + assertEq( + depositDataRegistry.depositDataIndexes(validVault), + 1, + 'Validator index should be incremented' + ); + } + + function test_registerValidators_failsForInvalidVault() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + + // Prepare proof params for multi-proof + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); + + // Attempt to register validators for an invalid vault + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidators(invalidVault, keeperParams, indexes, proofFlags, proof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_failsForInvalidVaultVersion() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + lowVersionVault, + 'ipfsHash', + deposits, + true + ); + + // Prepare proof params for multi-proof + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); + + // Attempt to register validators for a vault with version < 2 + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidators( + lowVersionVault, + keeperParams, + indexes, + proofFlags, + proof + ); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_failsWithNoIndexes() public { + vm.deal(validVault, exitingAssets + 64 ether); + + // Create validator approval params + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + + uint256[] memory indexes = new uint256[](0); + + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); + + // Create a deposit data root + bytes32 depositDataRoot = keccak256('root'); + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Attempt to register with invalid validators length + vm.expectRevert(Errors.InvalidValidators.selector); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_failWithInvalidProof() public { + vm.deal(validVault, exitingAssets + 64 ether); + + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + + // Prepare valid proof params + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + + bool[] memory proofFlags = new bool[](2); + proofFlags[0] = true; + proofFlags[1] = true; + + // Create an invalid proof + bytes32[] memory invalidProof = new bytes32[](1); + invalidProof[0] = bytes32(uint256(123)); // Some random value + + // Create a deposit data root that doesn't match the validators + bytes32 depositDataRoot = keccak256('incorrect_root'); + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Attempt to register with invalid proof + vm.expectRevert(MerkleProof.MerkleProofInvalidMultiproof.selector); + depositDataRegistry.registerValidators( + validVault, + keeperParams, + indexes, + proofFlags, + invalidProof + ); + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_successWith0x01Validators() public { + vm.deal(validVault, exitingAssets + 64 ether); + + // Create validator approval params for 2 validators + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + true + ); + + // Setup for multi-proof verification + uint256 validatorIndex = 0; + + // Extract each validator's data (each 176 bytes long for 0x01 validator) + bytes memory validator1 = _extractBytes(keeperParams.validators, 0, 176); + bytes memory validator2 = _extractBytes(keeperParams.validators, 176, 176); + + // Create a Merkle tree with the correct format for validator registration + bytes32[] memory leaves = new bytes32[](2); + leaves[0] = keccak256(bytes.concat(keccak256(abi.encode(validator1, validatorIndex)))); + leaves[1] = keccak256(bytes.concat(keccak256(abi.encode(validator2, validatorIndex + 1)))); + + // Sort the leaves before calculating the Merkle root + if (leaves[0] > leaves[1]) { + (leaves[0], leaves[1]) = (leaves[1], leaves[0]); + } + + // Calculate the Merkle root (for simplicity with only 2 leaves, it's just the hash of both leaves) + bytes32 depositDataRoot = keccak256(abi.encodePacked(leaves[0], leaves[1])); + + // Setup multi-proof parameters + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + + // For a tree with just 2 leaves and we're verifying both, we don't need a complex proof + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + bytes32[] memory proof = new bytes32[](0); + + // Set up the root in the registry + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Register validators + _startSnapshotGas('DepositDataRegistryTest_test_registerValidators_successWith0x01Validators'); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); + _stopSnapshotGas(); + + // Verify the validator index was incremented by 2 + assertEq( + depositDataRegistry.depositDataIndexes(validVault), + 2, + 'Validator index should be incremented by 2' + ); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_successWith0x02Validators() public { + // Fund the vault with enough ETH for two validators with 45 ETH each + vm.deal(validVault, exitingAssets + 90 ether); + + // Create validator approval params for 2 validators with 45 ETH each + uint256[] memory deposits = new uint256[](2); + deposits[0] = 45 ether / 1 gwei; // 45 ETH for first validator + deposits[1] = 45 ether / 1 gwei; // 45 ETH for second validator + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + 'ipfsHash', + deposits, + false // 0x02 validators + ); + + // Setup for multi-proof verification + uint256 validatorIndex = 0; + + // Extract each validator's data (each 184 bytes long for 0x02 validator) + bytes memory validator1 = _extractBytes(keeperParams.validators, 0, 184); + bytes memory validator2 = _extractBytes(keeperParams.validators, 184, 184); + + // Create a Merkle tree with the correct format for validator registration + bytes32[] memory leaves = new bytes32[](2); + leaves[0] = keccak256(bytes.concat(keccak256(abi.encode(validator1, validatorIndex)))); + leaves[1] = keccak256(bytes.concat(keccak256(abi.encode(validator2, validatorIndex + 1)))); + + // Sort the leaves before calculating the Merkle root + if (leaves[0] > leaves[1]) { + (leaves[0], leaves[1]) = (leaves[1], leaves[0]); + } + + // Calculate the Merkle root (for simplicity with only 2 leaves, it's just the hash of both leaves) + bytes32 depositDataRoot = keccak256(abi.encodePacked(leaves[0], leaves[1])); + + // Setup multi-proof parameters + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + + // For a tree with just 2 leaves and we're verifying both, we don't need a complex proof + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + bytes32[] memory proof = new bytes32[](0); + + // Set up the root in the registry + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Register validators + _startSnapshotGas('DepositDataRegistryTest_test_registerValidators_successWith0x02Validators'); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); + _stopSnapshotGas(); + + // Verify the validator index was incremented by 2 + assertEq( + depositDataRegistry.depositDataIndexes(validVault), + 2, + 'Validator index should be incremented by 2' + ); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_migrate_failsForInvalidVault() public { + // Attempt to migrate for an invalid vault + vm.expectRevert(Errors.InvalidVault.selector); + vm.prank(invalidVault); + depositDataRegistry.migrate(bytes32(0), 0, admin); + } + + function test_migrate_failsForInvalidVaultVersion() public { + // Attempt to migrate for a vault with version < 2 + vm.expectRevert(Errors.InvalidVault.selector); + vm.prank(lowVersionVault); + depositDataRegistry.migrate(bytes32(0), 0, admin); + } + + function test_migrate_failsWhenAlreadyMigrated() public { + address foxVault = _getForkVault(VaultType.EthFoxVault); + + _upgradeVault(VaultType.EthFoxVault, foxVault); + if (contracts.keeper.isHarvestRequired(foxVault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(foxVault, 0, 0); + IVaultState(foxVault).updateState(harvestParams); + } + + // Attempt to migrate when the vault has already been migrated + vm.expectRevert(Errors.AccessDenied.selector); + vm.prank(foxVault); + depositDataRegistry.migrate(bytes32(0), 0, admin); + } + + function test_migrate_succeeds() public { + address foxVault = _getForkVault(VaultType.EthFoxVault); + + address depositDataManagerBefore = IVaultValidatorsV1(foxVault).keysManager(); + bytes32 depositDataRootBefore = IVaultValidatorsV1(foxVault).validatorsRoot(); + uint256 depositDataIndexBefore = IVaultValidatorsV1(foxVault).validatorIndex(); + + _upgradeVault(VaultType.EthFoxVault, foxVault); + if (contracts.keeper.isHarvestRequired(foxVault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(foxVault, 0, 0); + IVaultState(foxVault).updateState(harvestParams); + } + + // Check the vault has been upgraded + assertEq( + IVaultValidators(foxVault).validatorsManager(), + address(depositDataRegistry), + 'Validators manager should be set to the deposit data registry after upgrade' + ); + assertEq(IVaultVersion(foxVault).version(), 2, 'Vault should have been upgraded to version 2'); + assertEq( + depositDataRegistry.getDepositDataManager(foxVault), + depositDataManagerBefore, + 'Deposit data manager should be the same after upgrade' + ); + assertEq( + depositDataRegistry.depositDataIndexes(foxVault), + depositDataIndexBefore, + 'Deposit data index should be the same after upgrade' + ); + assertEq( + depositDataRegistry.depositDataRoots(foxVault), + depositDataRootBefore, + 'Deposit data root should be the same after upgrade' + ); + } +} diff --git a/test/EthBlocklistErc20Vault.spec.ts b/test/EthBlocklistErc20Vault.spec.ts deleted file mode 100644 index 6415835f..00000000 --- a/test/EthBlocklistErc20Vault.spec.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthBlocklistErc20Vault, - IKeeperRewards, - Keeper, - DepositDataRegistry, - OsTokenVaultController, -} from '../typechain-types' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ZERO_ADDRESS } from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import keccak256 from 'keccak256' -import { extractDepositShares } from './shared/utils' - -describe('EthBlocklistErc20Vault', () => { - const name = 'EthBlocklistVault' - const symbol = 'eBLV' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Signer, other: Wallet, blocklistManager: Wallet - let vault: EthBlocklistErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, admin, other, blocklistManager] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthBlocklistErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthBlocklistErc20Vault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('transfer', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - await vault.connect(sender).deposit(sender.address, referrer, { value: amount }) - }) - - it('cannot transfer to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot transfer from blocked user', async () => { - await vault.connect(other).deposit(other.address, referrer, { value: amount }) - await vault.connect(blocklistManager).updateBlocklist(sender.address, true) - await expect( - vault.connect(other).transfer(sender.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can transfer', async () => { - const receipt = await vault.connect(sender).transfer(other.address, amount) - expect(await vault.balanceOf(sender.address)).to.eq(0) - expect(await vault.balanceOf(other.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, other.address, amount) - await snapshotGasCost(receipt) - }) - }) - - describe('deposit', () => { - const assets = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be called by blocked sender', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(other).deposit(other.address, referrer, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot update state and call by blocked sender', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const vaultReward = getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault - .connect(other) - .updateStateAndDeposit(other.address, referrer, harvestParams, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).deposit(other.address, referrer, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by not blocked user', async () => { - const receipt = await vault - .connect(sender) - .deposit(sender.address, referrer, { value: assets }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, assets, shares, referrer) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback cannot be called by blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await vault.connect(blocklistManager).updateBlocklist(await depositorMock.getAddress(), true) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by not blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(sender).deposit(sender.address, referrer, { value: assets }) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from blocked user', async () => { - await vault.connect(admin).updateBlocklist(sender.address, true) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not blocked user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/EthBlocklistErc20Vault.t.sol b/test/EthBlocklistErc20Vault.t.sol new file mode 100644 index 00000000..907c8d32 --- /dev/null +++ b/test/EthBlocklistErc20Vault.t.sol @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; +import {EthBlocklistErc20Vault} from '../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthBlocklistErc20VaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthBlocklistErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + blocklistManager = makeAddr('blocklistManager'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthBlocklistErc20Vault, admin, initParams, false); + vault = EthBlocklistErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('EthBlocklistErc20Vault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_transfer() public { + uint256 amount = 1 ether; + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas('EthBlocklistErc20VaultTest_test_transfer'); + vault.transfer(other, amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(sender), 0); + assertEq(vault.balanceOf(other), amount); + } + + function test_cannotTransferToBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Try to transfer to blocked user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferFromBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit ETH for both users + _depositEth(amount, sender, sender); + _depositEth(amount, other, other); + + // Block sender + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to transfer from blocked user to other + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + IEthErc20Vault(vault).deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthErc20Vault(vault).deposit{value: amount}(other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas('EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser'); + _depositEth(amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(receiver), amount); + } + + function test_cannotDepositUsingReceiveAsBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_canDepositUsingReceiveAsNotBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas('EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser'); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(sender), amount); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('EthBlocklistErc20VaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.EthBlocklistErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); + + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), 0); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(blocklistVault.totalExitingAssets(), 0); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.totalSupply(), _securityDeposit); + assertEq(blocklistVault.symbol(), 'SW-ETH-1'); + assertEq(blocklistVault.name(), 'SW ETH Vault'); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault( + VaultType.EthBlocklistErc20Vault, + admin, + initParams, + true + ); + EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); + + _depositToVault(address(blocklistVault), 95 ether, sender, sender); + _registerEthValidator(address(blocklistVault), 32 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); + uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 senderBalanceBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); + assertEq(blocklistVault.version(), 4); + + _startSnapshotGas('EthBlocklistErc20VaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthBlocklistErc20Vault, address(blocklistVault)); + _stopSnapshotGas(); + + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq(blocklistVault.totalSupply(), totalSharesBefore); + assertEq(blocklistVault.symbol(), 'SW-ETH-1'); + assertEq(blocklistVault.name(), 'SW ETH Vault'); + } + + function _depositEth(uint256 amount, address from, address to) internal { + vm.prank(from); + IEthErc20Vault(vault).deposit{value: amount}(to, address(0)); + } +} diff --git a/test/EthBlocklistVault.spec.ts b/test/EthBlocklistVault.spec.ts deleted file mode 100644 index 57b018fb..00000000 --- a/test/EthBlocklistVault.spec.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthBlocklistVault, - IKeeperRewards, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../typechain-types' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ZERO_ADDRESS } from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import keccak256 from 'keccak256' -import { extractDepositShares } from './shared/utils' - -describe('EthBlocklistVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Signer, other: Wallet, blocklistManager: Wallet - let vault: EthBlocklistVault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, admin, other, blocklistManager] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthBlocklistVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthBlocklistVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const assets = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be called by blocked sender', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(other).deposit(other.address, referrer, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot update state and call by blocked sender', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const vaultReward = getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault - .connect(other) - .updateStateAndDeposit(other.address, referrer, harvestParams, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).deposit(other.address, referrer, { value: assets }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by not blocked user', async () => { - const receipt = await vault - .connect(sender) - .deposit(sender.address, referrer, { value: assets }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, assets, shares, referrer) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback cannot be called by blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await vault.connect(blocklistManager).updateBlocklist(await depositorMock.getAddress(), true) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by not blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(sender).deposit(sender.address, referrer, { value: assets }) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from blocked user', async () => { - await vault.connect(admin).updateBlocklist(sender.address, true) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not blocked user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/EthBlocklistVault.t.sol b/test/EthBlocklistVault.t.sol new file mode 100644 index 00000000..c8364af4 --- /dev/null +++ b/test/EthBlocklistVault.t.sol @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {EthBlocklistVault} from '../contracts/vaults/ethereum/EthBlocklistVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthBlocklistVaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthBlocklistVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + blocklistManager = makeAddr('blocklistManager'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthBlocklistVault, admin, initParams, false); + vault = EthBlocklistVault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('EthBlocklistVault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas('EthBlocklistVaultTest_test_canDepositAsNonBlockedUser'); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.getShares(receiver), amount); + } + + function test_cannotDepositUsingReceiveAsBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_cannotUpdateStateAndDepositFromBlockedSender() public { + _collateralizeVault( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault) + ); + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_canDepositUsingReceiveAsNotBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas('EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser'); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.getShares(sender), amount); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('EthBlocklistVaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.EthBlocklistVault, admin, initParams, true); + _stopSnapshotGas(); + EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); + + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), 0); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(blocklistVault.totalExitingAssets(), 0); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthBlocklistVault, admin, initParams, true); + EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); + + _depositToVault(address(blocklistVault), 95 ether, sender, sender); + _registerEthValidator(address(blocklistVault), 32 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); + uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 senderSharesBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); + assertEq(blocklistVault.version(), 4); + + _startSnapshotGas('EthBlocklistVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthBlocklistVault, address(blocklistVault)); + _stopSnapshotGas(); + + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderSharesBefore); + } +} diff --git a/test/EthErc20Vault.spec.ts b/test/EthErc20Vault.spec.ts deleted file mode 100644 index eedf9095..00000000 --- a/test/EthErc20Vault.spec.ts +++ /dev/null @@ -1,346 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - DepositDataRegistry, - EthErc20Vault, - IKeeperRewards, - Keeper, - OsToken, - OsTokenConfig, - OsTokenVaultController, -} from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { MAX_UINT256, ZERO_ADDRESS } from './shared/constants' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - setAvgRewardPerSecond, - updateRewards, -} from './shared/rewards' -import keccak256 from 'keccak256' -import { extractExitPositionTicket, setBalance } from './shared/utils' -import { MAINNET_FORK } from '../helpers/constants' -import { registerEthValidator } from './shared/validators' - -describe('EthErc20Vault', () => { - const capacity = ethers.parseEther('1000') - const name = 'SW ETH Vault' - const symbol = 'SW-ETH-1' - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const referrer = '0x' + '1'.repeat(40) - let sender: Wallet, receiver: Wallet, admin: Signer, dao: Wallet, other: Wallet - let vault: EthErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - depositDataRegistry: DepositDataRegistry, - osToken: OsToken - - beforeEach('deploy fixtures', async () => { - ;[dao, sender, receiver, admin, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthErc20Vault(admin, { - capacity, - name, - symbol, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - osTokenConfig = fixture.osTokenConfig - depositDataRegistry = fixture.depositDataRegistry - osToken = fixture.osToken - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq('0x' + keccak256('EthErc20Vault').toString('hex')) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - it('deposit emits transfer event', async () => { - const amount = ethers.parseEther('100') - let expectedShares = await vault.convertToShares(amount) - if (MAINNET_FORK.enabled) { - expectedShares += 1n // rounding error - } - - const receipt = await vault - .connect(sender) - .deposit(receiver.address, referrer, { value: amount }) - expect(await vault.balanceOf(receiver.address)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, expectedShares, referrer) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(ZERO_ADDRESS, receiver.address, expectedShares) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback function emits transfer event', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - - const amount = ethers.parseEther('100') - let expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - if (MAINNET_FORK.enabled) { - expectedShares += 1n // rounding error - } - expect(await vault.balanceOf(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(ZERO_ADDRESS, depositorMockAddress, expectedShares) - await snapshotGasCost(receipt) - }) - - it('enter exit queue emits transfer event', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const queuedSharesBefore = await vault.queuedShares() - const totalAssetsBefore = await vault.totalAssets() - const totalSharesBefore = await vault.totalShares() - - const amount = ethers.parseEther('100') - let shares = await vault.convertToShares(amount) - await vault.connect(sender).deposit(sender.address, referrer, { value: amount }) - if (MAINNET_FORK.enabled) { - shares += 1n // rounding error - } - expect(await vault.balanceOf(sender.address)).to.be.eq(shares) - - const receipt = await vault.connect(sender).enterExitQueue(shares, receiver.address) - const positionTicket = await extractExitPositionTicket(receipt) - await expect(receipt) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(sender.address, receiver.address, positionTicket, shares) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, await vault.getAddress(), shares) - expect(await vault.queuedShares()).to.be.eq(queuedSharesBefore + shares) - expect(await vault.totalAssets()).to.be.eq(totalAssetsBefore + amount) - expect(await vault.totalSupply()).to.be.eq(totalSharesBefore + shares) - expect(await vault.balanceOf(sender.address)).to.be.eq(0) - - await snapshotGasCost(receipt) - }) - - it('update exit queue emits transfer event', async () => { - const validatorDeposit = ethers.parseEther('32') - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: validatorDeposit }) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, { - vault: await vault.getAddress(), - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - }) - - // exit validator - let shares = await vault.convertToShares(validatorDeposit) - await vault.connect(sender).enterExitQueue(shares, sender.address) - await setBalance(await vault.getAddress(), validatorDeposit) - - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - if (MAINNET_FORK.enabled) { - shares -= 1n // rounding error - } - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(await vault.getAddress(), ZERO_ADDRESS, shares) - - await snapshotGasCost(receipt) - }) - - it('cannot transfer vault shares when unharvested and osToken minted', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const assets = ethers.parseEther('1') - const shares = await vault.convertToShares(assets) - const osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: assets }) - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - - await updateRewards(keeper, [ - getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), ethers.parseEther('0')), - ]) - await updateRewards(keeper, [ - getHarvestParams(await vault.getAddress(), ethers.parseEther('1.2'), ethers.parseEther('0')), - ]) - await expect( - vault.connect(sender).transfer(receiver.address, shares) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('cannot transfer vault shares when LTV is violated', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const assets = ethers.parseEther('2') - const shares = await vault.convertToShares(assets) - const osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: assets }) - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - await expect( - vault.connect(sender).transfer(receiver.address, shares) - ).to.be.revertedWithCustomError(vault, 'LowLtv') - await vault.connect(sender).approve(receiver.address, shares) - await expect( - vault.connect(receiver).transferFrom(sender.address, receiver.address, shares) - ).to.be.revertedWithCustomError(vault, 'LowLtv') - }) - - it('can transfer vault shares when LTV is not violated', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const assets = ethers.parseEther('2') - const osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - const transferShares = await vault.convertToShares(ethers.parseEther('0.1')) - - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: assets }) - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - await expect(vault.connect(sender).transfer(receiver.address, transferShares)).to.emit( - vault, - 'Transfer' - ) - await vault.connect(sender).approve(receiver.address, transferShares) - await expect( - vault.connect(receiver).transferFrom(sender.address, receiver.address, transferShares) - ).to.emit(vault, 'Transfer') - }) - - it('can deposit and mint osToken in one transaction', async () => { - const assets = ethers.parseEther('1') - let shares = await vault.convertToShares(assets) - - await setAvgRewardPerSecond(dao, vault, keeper, 0) - expect(await vault.osTokenPositions(sender.address)).to.eq(0n) - expect(await vault.getShares(sender.address)).to.eq(0n) - - // max shares - const config = await osTokenConfig.getConfig(await vault.getAddress()) - let osTokenAssets = (assets * config.ltvPercent) / ethers.parseEther('1') - let osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - let receipt = await vault - .connect(sender) - .depositAndMintOsToken(receiver.address, MAX_UINT256, ZERO_ADDRESS, { value: assets }) - - if (MAINNET_FORK.enabled) { - shares += 1n // rounding error - osTokenAssets -= 1n // rounding error - } - - expect(await osToken.balanceOf(receiver.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(sender.address)).to.eq(osTokenShares) - expect(await vault.getShares(sender.address)).to.eq(shares) - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, assets, shares, ZERO_ADDRESS) - await expect(receipt).to.emit(vault, 'Transfer').withArgs(ZERO_ADDRESS, sender.address, shares) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(sender.address, receiver.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - - // mint osToken with half shares - osTokenAssets = assets / 2n - osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - receipt = await vault - .connect(receiver) - .depositAndMintOsToken(other.address, osTokenShares, ZERO_ADDRESS, { value: assets }) - - if (MAINNET_FORK.enabled) { - osTokenAssets -= 1n // rounding error - } - - expect(await osToken.balanceOf(other.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(receiver.address)).to.eq(osTokenShares) - expect(await vault.getShares(receiver.address)).to.eq(shares) - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(receiver.address, receiver.address, assets, shares, ZERO_ADDRESS) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(ZERO_ADDRESS, receiver.address, shares) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(receiver.address, other.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - it('can update state, deposit, and mint osToken in one transaction', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - const vaultAddr = await vault.getAddress() - const assets = ethers.parseEther('1') - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - await updateRewards(keeper, [vaultReward], 0) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - - expect(await vault.osTokenPositions(sender.address)).to.eq(0n) - expect(await vault.getShares(sender.address)).to.eq(0n) - - const config = await osTokenConfig.getConfig(await vault.getAddress()) - let osTokenAssets = (assets * config.ltvPercent) / ethers.parseEther('1') - const osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - const receipt = await vault - .connect(sender) - .updateStateAndDepositAndMintOsToken( - receiver.address, - MAX_UINT256, - ZERO_ADDRESS, - harvestParams, - { - value: assets, - } - ) - - let shares = await vault.convertToShares(assets) - if (MAINNET_FORK.enabled) { - shares += 1n // rounding error - osTokenAssets -= 1n // rounding error - } - - expect(await osToken.balanceOf(receiver.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(sender.address)).to.eq(osTokenShares) - expect(await vault.getShares(sender.address)).to.eq(shares) - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, assets, shares, ZERO_ADDRESS) - await expect(receipt).to.emit(vault, 'Transfer').withArgs(ZERO_ADDRESS, sender.address, shares) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(sender.address, receiver.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) -}) diff --git a/test/EthErc20Vault.t.sol b/test/EthErc20Vault.t.sol new file mode 100644 index 00000000..a0c402d5 --- /dev/null +++ b/test/EthErc20Vault.t.sol @@ -0,0 +1,476 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthErc20VaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('EthErc20VaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.EthErc20Vault, admin, initParams, false); + _stopSnapshotGas(); + EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + + assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); + assertEq(erc20Vault.version(), 5); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.queuedShares(), 0); + assertEq(erc20Vault.totalShares(), _securityDeposit); + assertEq(erc20Vault.totalAssets(), _securityDeposit); + assertEq(erc20Vault.totalExitingAssets(), 0); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.totalSupply(), _securityDeposit); + assertEq(erc20Vault.symbol(), 'SW-ETH-1'); + assertEq(erc20Vault.name(), 'SW ETH Vault'); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthErc20Vault, admin, initParams, false); + EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + + // Deposit enough for validator (32 ETH minimum) + _depositToVault(address(erc20Vault), 40 ether, sender, sender); + + // Add funds directly to the vault to cover the validator + vm.deal(address(erc20Vault), address(erc20Vault).balance + 32 ether); + + _registerEthValidator(address(erc20Vault), 32 ether, true); + + vm.prank(sender); + erc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = erc20Vault.totalShares(); + uint256 totalAssetsBefore = erc20Vault.totalAssets(); + uint256 totalExitingAssetsBefore = erc20Vault.totalExitingAssets(); + uint256 queuedSharesBefore = erc20Vault.queuedShares(); + uint256 senderBalanceBefore = erc20Vault.getShares(sender); + + assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); + assertEq(erc20Vault.version(), 4); + + _startSnapshotGas('EthErc20VaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthErc20Vault, address(erc20Vault)); + _stopSnapshotGas(); + + assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); + assertEq(erc20Vault.version(), 5); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.queuedShares(), queuedSharesBefore); + assertEq(erc20Vault.totalShares(), totalSharesBefore); + assertEq(erc20Vault.totalAssets(), totalAssetsBefore); + assertEq(erc20Vault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.getShares(sender), senderBalanceBefore); + assertEq(erc20Vault.totalSupply(), totalSharesBefore); + assertEq(erc20Vault.symbol(), 'SW-ETH-1'); + assertEq(erc20Vault.name(), 'SW ETH Vault'); + } + + function test_deposit_emitsTransfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // When depositing, the vault will mint shares to the receiver + // So we should expect a Transfer event from address(0) to the receiver + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Call deposit directly + _startSnapshotGas('EthErc20VaultTest_test_deposit_emitsTransfer'); + vm.prank(sender); + vault.deposit{value: amount}(sender, referrer); + _stopSnapshotGas(); + } + + function test_enterExitQueue_emitsTransfer() public { + _collateralizeEthVault(address(vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositEth(amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(sender, address(vault), shares); + + // Enter exit queue + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas('EthErc20VaultTest_test_enterExitQueue_emitsTransfer'); + uint256 positionTicket = vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Claim exited assets + vm.prank(sender); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_redeem_emitsEvent() public { + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createVault(VaultType.EthErc20Vault, admin, initParams, false); + EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositToVault(_vault, amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, _vault); + emit IERC20.Transfer(sender, address(0), shares); + + // Redeem + vm.prank(sender); + _startSnapshotGas('EthErc20VaultTest_test_redeem_emitsEvent'); + uint256 positionTicket = erc20Vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + assertEq(positionTicket, type(uint256).max); + } + + function test_cannotTransferFromSharesWithLowLtv() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + uint256 depositAmount = 10 ether; + + // Deposit ETH + _depositEth(depositAmount, sender, sender); + + // First mint the maximum amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, type(uint256).max, referrer); + + // Approve other to transfer a significant amount + vm.prank(sender); + vault.approve(other, depositAmount / 4); + + // Try to transferFrom a significant amount + vm.prank(other); + _startSnapshotGas('EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv'); + vm.expectRevert(Errors.LowLtv.selector); + vault.transferFrom(sender, other, depositAmount / 4); // 25% of collateral + _stopSnapshotGas(); + } + + function test_canTransferFromSharesWithHighLtv() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + uint256 depositAmount = 10 ether; + uint256 depositShares = vault.convertToShares(depositAmount); + + // Deposit ETH + _depositEth(depositAmount, sender, sender); + + // Mint a very small amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, depositShares / 100, referrer); // Just 1% of deposit + + // Approve other to transfer shares + vm.prank(sender); + vault.approve(other, depositShares / 2); + + // Should be able to transferFrom most shares + vm.prank(other); + _startSnapshotGas('EthErc20VaultTest_test_canTransferFromSharesWithHighLtv'); + vault.transferFrom(sender, other, depositShares / 2); + _stopSnapshotGas(); + + // Verify the transfer succeeded + assertApproxEqAbs(vault.balanceOf(sender), depositShares - depositShares / 2, 1); + assertApproxEqAbs(vault.balanceOf(other), depositShares / 2, 1); + } + + function test_depositAndMintOsToken() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + uint256 depositAmount = 10 ether; + uint256 osTokenShares = vault.convertToShares(depositAmount) / 2; // Use half for osToken + + // Call depositAndMintOsToken + vm.prank(sender); + _startSnapshotGas('EthErc20VaultTest_test_depositAndMintOsToken'); + uint256 mintedAssets = vault.depositAndMintOsToken{value: depositAmount}( + sender, + osTokenShares, + referrer + ); + _stopSnapshotGas(); + + // Check results + assertGt(mintedAssets, 0, 'Should have minted some osToken assets'); + assertEq( + vault.osTokenPositions(sender), + osTokenShares, + 'Should have minted expected osToken shares' + ); + assertEq( + vault.balanceOf(sender), + vault.convertToShares(depositAmount), + 'Should have received tokens for the deposit' + ); + } + + function test_updateStateAndDepositAndMintOsToken() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Create harvest params + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + uint256 depositAmount = 5 ether; + uint256 osTokenShares = vault.convertToShares(depositAmount) / 2; // Use half for osToken + + // Call updateStateAndDepositAndMintOsToken + vm.prank(sender); + _startSnapshotGas('EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken'); + uint256 mintedAssets = vault.updateStateAndDepositAndMintOsToken{value: depositAmount}( + sender, + osTokenShares, + referrer, + harvestParams + ); + _stopSnapshotGas(); + + // Check results + assertGt(mintedAssets, 0, 'Should have minted some osToken assets'); + assertEq( + vault.osTokenPositions(sender), + osTokenShares, + 'Should have minted expected osToken shares' + ); + assertEq( + vault.balanceOf(sender), + vault.convertToShares(depositAmount), + 'Should have received tokens for the deposit' + ); + } + + function test_withdrawValidator_validatorsManager() public { + // 1. Set validators manager + address validatorsManager = makeAddr('validatorsManager'); + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 2. First deposit enough ETH to register a validator (32 ETH minimum) + _depositEth(35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas('EthErc20VaultTest_test_withdrawValidator_validatorsManager'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_withdrawValidator_osTokenRedeemer() public { + // 1. Set osToken redeemer + address osTokenRedeemer = makeAddr('osTokenRedeemer'); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // 2. First deposit enough ETH to register a validator (32 ETH minimum) + _depositEth(35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(osTokenRedeemer); + _startSnapshotGas('EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_withdrawValidator_unknown() public { + // 1. Set unknown address + address unknown = makeAddr('unknown'); + + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // 2. First deposit enough ETH to register a validator (32 ETH minimum) + _depositEth(35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(unknown); + _startSnapshotGas('EthErc20VaultTest_test_withdrawValidator_unknown'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_depositViaReceiveFallback_emitsTransfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // When depositing via the receive fallback, the vault should emit a Transfer event + // from address(0) to the sender + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Use low-level call to trigger the receive function + _startSnapshotGas('EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer'); + vm.prank(sender); + (bool success, ) = address(vault).call{value: amount}(''); + _stopSnapshotGas(); + + require(success, 'ETH transfer failed'); + + // Verify sender received the correct number of tokens + assertEq(vault.balanceOf(sender), shares, 'Sender should have received tokens'); + } + + function test_updateExitQueue_emitsTransfer() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // We need to deposit enough ETH to cover the validator registration (32 ETH) + uint256 amount = 40 ether; + + // Deposit ETH + _depositEth(amount, sender, sender); + + // Enter exit queue with 10 ETH + uint256 exitAmount = 10 ether; + uint256 exitShares = vault.convertToShares(exitAmount); + + vm.prank(sender); + vault.enterExitQueue(exitShares, sender); + + // Set some rewards to trigger state update and exit queue processing + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(1 ether), + 0 + ); + + // Update state which should process the exit queue + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(vault), address(0), exitShares); + _startSnapshotGas('EthErc20VaultTest_test_updateExitQueue_emitsTransfer'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify the exit queue was processed correctly + // The queue might not be fully processed in one update, so we'll check that progress was made + assertLt(vault.queuedShares(), exitShares, 'Exit queue should be at least partially processed'); + } + + // Helper function to deposit ETH to the vault + function _depositEth(uint256 amount, address from, address to) internal { + vm.prank(from); + IEthErc20Vault(vault).deposit{value: amount}(to, referrer); + } +} diff --git a/test/EthFoxVault.spec.ts b/test/EthFoxVault.spec.ts deleted file mode 100644 index 9c2dbf90..00000000 --- a/test/EthFoxVault.spec.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { ethers } from 'hardhat' -import keccak256 from 'keccak256' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { Keeper, IKeeperRewards, EthFoxVault, DepositDataRegistry } from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ZERO_ADDRESS } from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import { extractDepositShares, extractExitPositionTicket } from './shared/utils' - -describe('EthFoxVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, blocklistManager: Wallet, admin: Signer, other: Wallet - let vault: EthFoxVault, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createFoxVault: ThenArg>['createEthFoxVault'] - - before('create fixture loader', async () => { - ;[sender, blocklistManager, admin, other] = (await (ethers as any).getSigners()).slice(1, 5) - }) - - beforeEach('deploy fixtures', async () => { - ;({ - createEthFoxVault: createFoxVault, - keeper, - validatorsRegistry, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createFoxVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthFoxVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(2) - }) - - describe('set blocklist manager', () => { - it('cannot be called by not admin', async () => { - await expect( - vault.connect(other).setBlocklistManager(blocklistManager.address) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('admin can update blocklist manager', async () => { - const tx = await vault.connect(admin).setBlocklistManager(blocklistManager.address) - await expect(tx) - .to.emit(vault, 'BlocklistManagerUpdated') - .withArgs(await admin.getAddress(), blocklistManager.address) - expect(await vault.blocklistManager()).to.be.eq(blocklistManager.address) - await snapshotGasCost(tx) - }) - }) - - describe('blocklist', () => { - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be updated by not blocklist manager', async () => { - await expect( - vault.connect(other).updateBlocklist(sender.address, true) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot be updated twice', async () => { - await vault.connect(blocklistManager).updateBlocklist(sender.address, true) - await expect( - vault.connect(blocklistManager).updateBlocklist(sender.address, true) - ).to.not.emit(vault, 'BlocklistUpdated') - }) - - it('can be updated by blocklist manager', async () => { - // add to blocklist - let tx = await vault.connect(blocklistManager).updateBlocklist(sender.address, true) - await expect(tx) - .to.emit(vault, 'BlocklistUpdated') - .withArgs(blocklistManager.address, sender.address, true) - expect(await vault.blockedAccounts(sender.address)).to.be.eq(true) - await snapshotGasCost(tx) - - // remove from blocklist - tx = await vault.connect(blocklistManager).updateBlocklist(sender.address, false) - await expect(tx) - .to.emit(vault, 'BlocklistUpdated') - .withArgs(blocklistManager.address, sender.address, false) - expect(await vault.blockedAccounts(sender.address)).to.be.eq(false) - await snapshotGasCost(tx) - }) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).updateBlocklist(sender.address, true) - }) - - it('cannot be called by blocked sender', async () => { - await expect( - vault.connect(sender).deposit(sender.address, referrer, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot update state and call', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const vaultReward = getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await expect( - vault - .connect(sender) - .updateStateAndDeposit(sender.address, referrer, harvestParams, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await expect( - vault.connect(other).deposit(sender.address, referrer, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by not blocked user', async () => { - const receipt = await vault.connect(other).deposit(other.address, referrer, { value: amount }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(other.address, other.address, amount, shares, referrer) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback cannot be called by blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - await vault.connect(admin).updateBlocklist(await depositorMock.getAddress(), true) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by not blocked sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - }) - - describe('ejecting user', () => { - const senderAssets = parseEther('1') - let senderShares: bigint - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - const tx = await vault - .connect(sender) - .deposit(sender.address, referrer, { value: senderAssets }) - senderShares = await extractDepositShares(tx) - }) - - it('fails for not blocklist manager', async () => { - await expect(vault.connect(other).ejectUser(sender.address)).to.revertedWithCustomError( - vault, - 'AccessDenied' - ) - }) - - it('does not fail for user with no vault shares', async () => { - expect(await vault.getShares(other.address)).to.eq(0) - - const tx = await vault.connect(blocklistManager).ejectUser(other.address) - await expect(tx) - .to.emit(vault, 'BlocklistUpdated') - .withArgs(blocklistManager.address, other.address, true) - expect(await vault.blockedAccounts(other.address)).to.eq(true) - await expect(tx).to.not.emit(vault, 'ExitQueueEntered') - await snapshotGasCost(tx) - }) - - it('blocklist manager can eject all of the user assets for collateralized vault', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - const tx = await vault.connect(blocklistManager).ejectUser(sender.address) - const positionTicket = await extractExitPositionTicket(tx) - await expect(tx) - .to.emit(vault, 'BlocklistUpdated') - .withArgs(blocklistManager.address, sender.address, true) - expect(await vault.blockedAccounts(sender.address)).to.eq(true) - await expect(tx) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(sender.address, sender.address, positionTicket, senderShares) - await expect(tx).to.emit(vault, 'UserEjected').withArgs(sender.address, senderShares) - expect(await vault.getShares(sender.address)).to.eq(0) - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/EthFoxVault.t.sol b/test/EthFoxVault.t.sol new file mode 100644 index 00000000..d1250dad --- /dev/null +++ b/test/EthFoxVault.t.sol @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IEthFoxVault} from '../contracts/interfaces/IEthFoxVault.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {EthFoxVault} from '../contracts/vaults/ethereum/custom/EthFoxVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthFoxVaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthFoxVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + uint256 exitingAssets; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + blocklistManager = makeAddr('blocklistManager'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // Get or create the EthFoxVault + bytes memory initParams = abi.encode( + IEthFoxVault.EthFoxVaultInitParams({ + admin: admin, + ownMevEscrow: address(0), // Using shared MEV escrow + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthFoxVault, admin, initParams, false); + vault = EthFoxVault(payable(_vault)); + exitingAssets = vault.convertToAssets(vault.queuedShares()) + address(vault).balance; + } + + function test_deployFails() public { + // Deploy the vault directly + vm.deal(admin, 1 ether); + vm.prank(admin); + address impl = _getOrCreateVaultImpl(VaultType.EthFoxVault); + address _vault = address(new ERC1967Proxy(impl, '')); + + bytes memory initParams = abi.encode( + IEthFoxVault.EthFoxVaultInitParams({ + admin: admin, + ownMevEscrow: address(0), // Using shared MEV escrow + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + vm.expectRevert(Errors.UpgradeFailed.selector); + EthFoxVault(payable(_vault)).initialize(initParams); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('EthFoxVault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 2); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Deposit as non-blocked user + _startSnapshotGas('EthFoxVaultTest_test_canDepositAsNonBlockedUser'); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), expectedShares, 1); + } + + function test_cannotDepositUsingReceiveAsBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_canDepositUsingReceiveAsNotBlockedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Deposit as non-blocked user + _startSnapshotGas('EthFoxVaultTest_test_canDepositUsingReceiveAsNotBlockedUser'); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(sender), expectedShares, 1); + } + + function test_cannotUpdateStateAndDepositFromBlockedSender() public { + _collateralizeVault( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault) + ); + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_ejectUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + uint256 queueSharesBefore = vault.queuedShares(); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Verify user is not yet in blocklist + assertFalse(vault.blockedAccounts(sender)); + + // Eject user + _startSnapshotGas('EthFoxVaultTest_test_ejectUser'); + vm.prank(blocklistManager); + vault.ejectUser(sender); + _stopSnapshotGas(); + + // Verify user is now in blocklist + assertTrue(vault.blockedAccounts(sender)); + + // User's shares should be in exit queue + assertEq(vault.getShares(sender), 0); + assertApproxEqAbs(vault.queuedShares(), queueSharesBefore + shares, 1); + } + + function test_ejectUserWithNoShares() public { + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + uint256 queueSharesBefore = vault.queuedShares(); + + // Eject user with no shares + _startSnapshotGas('EthFoxVaultTest_test_ejectUserWithNoShares'); + vm.prank(blocklistManager); + vault.ejectUser(sender); + _stopSnapshotGas(); + + // Verify user is in blocklist + assertTrue(vault.blockedAccounts(sender)); + + // No shares should be in exit queue + assertEq(vault.queuedShares(), queueSharesBefore); + } + + function test_ejectUserFailsFromNonBlocklistManager() public { + uint256 amount = 1 ether; + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Try to eject user by non-blocklist manager + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.ejectUser(sender); + } + + function test_withdrawValidator_validatorsManager() public { + // 1. Set validators manager + address validatorsManager = makeAddr('validatorsManager'); + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 2. First deposit and register a validator + _depositToVault(address(vault), 35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas('EthFoxVaultTest_test_withdrawValidator_validatorsManager'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_withdrawValidator_unknown() public { + // 1. Set unknown address + address unknown = makeAddr('unknown'); + + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // 2. First deposit and register a validator + _depositToVault(address(vault), 35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(unknown); + _startSnapshotGas('EthFoxVaultTest_test_withdrawValidator_unknown'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } +} diff --git a/test/EthGenesisVault.spec.ts b/test/EthGenesisVault.spec.ts deleted file mode 100644 index 1ae4638a..00000000 --- a/test/EthGenesisVault.spec.ts +++ /dev/null @@ -1,582 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { - EthGenesisVault, - Keeper, - PoolEscrowMock, - LegacyRewardTokenMock, - DepositDataRegistry, -} from '../typechain-types' -import { createDepositorMock, ethVaultFixture, getOraclesSignatures } from './shared/fixtures' -import { expect } from './shared/expect' -import keccak256 from 'keccak256' -import { - ONE_DAY, - ORACLES, - SECURITY_DEPOSIT, - VALIDATORS_DEADLINE, - ZERO_ADDRESS, - ZERO_BYTES32, -} from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { - createEthValidatorsData, - exitSignatureIpfsHashes, - getEthValidatorsSigningData, - getValidatorsMultiProof, - registerEthValidator, -} from './shared/validators' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import { - extractCheckpointAssets, - extractDepositShares, - extractExitPositionTicket, - getBlockTimestamp, - increaseTime, - setBalance, -} from './shared/utils' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { MAINNET_FORK } from '../helpers/constants' -import { ThenArg } from '../helpers/types' - -describe('EthGenesisVault', () => { - const capacity = ethers.parseEther('1000000') - const feePercent = 500 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const deadline = VALIDATORS_DEADLINE - let admin: Signer, other: Wallet - let vault: EthGenesisVault, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - let poolEscrow: PoolEscrowMock - let rewardEthToken: LegacyRewardTokenMock - - let createGenesisVault: ThenArg>['createEthGenesisVault'] - - async function acceptPoolEscrowOwnership() { - if (MAINNET_FORK.enabled) return - await vault.connect(admin).acceptPoolEscrowOwnership() - } - - async function collatEthVault() { - if (MAINNET_FORK.enabled) return - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - } - - beforeEach('deploy fixtures', async () => { - ;[admin, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - depositDataRegistry = fixture.depositDataRegistry - ;[vault, rewardEthToken, poolEscrow] = await fixture.createEthGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - createGenesisVault = fixture.createEthGenesisVault - }) - - it('initializes correctly', async () => { - await expect(vault.connect(admin).initialize(ZERO_BYTES32)).to.revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - expect(await vault.capacity()).to.be.eq(capacity) - - // VaultAdmin - const adminAddr = await admin.getAddress() - - // VaultVersion - expect(await vault.version()).to.be.eq(4) - expect(await vault.vaultId()).to.be.eq(`0x${keccak256('EthGenesisVault').toString('hex')}`) - - // VaultFee - if (!MAINNET_FORK.enabled) { - expect(await vault.admin()).to.be.eq(adminAddr) - expect(await vault.feeRecipient()).to.be.eq(adminAddr) - } - expect(await vault.feePercent()).to.be.eq(feePercent) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - describe('migrate', () => { - it('fails from not rewardEthToken', async () => { - await expect( - vault.connect(admin).migrate(await admin.getAddress(), ethers.parseEther('1')) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails when pool escrow ownership is not accepted', async () => { - const [vault, rewardEthToken] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - const assets = ethers.parseEther('10') - await expect( - rewardEthToken.connect(other).migrate(other.address, assets, 0) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails with zero receiver', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - const assets = ethers.parseEther('1') - if (MAINNET_FORK.enabled) { - await expect( - rewardEthToken.connect(other).migrate(ZERO_ADDRESS, assets, assets) - ).to.be.revertedWith('RewardEthToken: invalid receiver') - } else { - await expect( - rewardEthToken.connect(other).migrate(ZERO_ADDRESS, assets, assets) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - } - }) - - it('fails with zero assets', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - if (MAINNET_FORK.enabled) { - await expect(rewardEthToken.connect(other).migrate(other.address, 0, 0)).to.be.revertedWith( - 'RewardEthToken: zero assets' - ) - } else { - await expect( - rewardEthToken.connect(other).migrate(other.address, 0, 0) - ).to.be.revertedWithCustomError(vault, 'InvalidAssets') - } - }) - - it('fails when not collateralized', async () => { - const [vault, rewardEthToken] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - await vault.connect(admin).acceptPoolEscrowOwnership() - const assets = ethers.parseEther('1') - await expect( - rewardEthToken.connect(other).migrate(other.address, assets, assets) - ).to.be.revertedWithCustomError(vault, 'NotCollateralized') - }) - - it('fails when not harvested', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - const reward = ethers.parseEther('5') - const unlockedMevReward = 0n - const vaultAddr = await vault.getAddress() - const vaultReward = getHarvestParams(vaultAddr, reward, unlockedMevReward) - await updateRewards(keeper, [vaultReward]) - await updateRewards(keeper, [ - getHarvestParams(vaultAddr, reward + ethers.parseEther('5'), unlockedMevReward), - ]) - - let holder: Signer - if (MAINNET_FORK.enabled) { - holder = await ethers.getImpersonatedSigner(MAINNET_FORK.v2PoolHolder) - } else { - holder = other - } - - const assets = ethers.parseEther('1') - await expect( - rewardEthToken.connect(holder).migrate(await holder.getAddress(), assets, assets) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('migrates from rewardEthToken', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - const assets = ethers.parseEther('10') - const expectedShares = await vault.convertToShares(assets) - - let holder: Signer - if (MAINNET_FORK.enabled) { - holder = await ethers.getImpersonatedSigner(MAINNET_FORK.v2PoolHolder) - } else { - holder = other - } - const holderAddr = await holder.getAddress() - - const receipt = await rewardEthToken.connect(holder).migrate(holderAddr, assets, 0) - expect(await vault.getShares(holderAddr)).to.eq(expectedShares) - - await expect(receipt).to.emit(vault, 'Migrated').withArgs(holderAddr, assets, expectedShares) - await expect(receipt).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(receipt) - }) - }) - - it('pulls assets on claim exited assets', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - - const assets = ethers.parseEther('10') - let tx = await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: assets }) - const shares = await extractDepositShares(tx) - - const vaultAddr = await vault.getAddress() - const vaultBalance = await ethers.provider.getBalance(vaultAddr) - const poolEscrowAddr = await poolEscrow.getAddress() - const poolEscrowBalance = await ethers.provider.getBalance(poolEscrowAddr) - const vaultTotalBalance = - vaultBalance + poolEscrowBalance + (await vault.convertToAssets(await vault.queuedShares())) - - await setBalance(vaultAddr, 0n) - const response = await vault.connect(other).enterExitQueue(shares, other.address) - const positionTicket = await extractExitPositionTicket(response) - const timestamp = await getBlockTimestamp(response) - - await setBalance(poolEscrowAddr, vaultTotalBalance) - - await increaseTime(ONE_DAY) - const reward = 0n - const unlockedMevReward = 0n - const harvestParams = getHarvestParams(vaultAddr, reward, unlockedMevReward) - const tree = await updateRewards(keeper, [harvestParams]) - const proof = getRewardsRootProof(tree, harvestParams) - await vault.updateState({ - rewardsRoot: tree.root, - proof, - reward: harvestParams.reward, - unlockedMevReward: harvestParams.unlockedMevReward, - }) - const exitQueueIndex = await vault.getExitQueueIndex(positionTicket) - - tx = await vault.connect(other).claimExitedAssets(positionTicket, timestamp, exitQueueIndex) - await expect(tx) - .to.emit(poolEscrow, 'Withdrawn') - .withArgs(vaultAddr, vaultAddr, vaultTotalBalance) - await expect(tx) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(other.address, positionTicket, 0, assets) - expect(await ethers.provider.getBalance(await poolEscrow.getAddress())).to.eq(0) - await snapshotGasCost(tx) - }) - - it('pulls withdrawals on single validator registration', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - const validatorDeposit = ethers.parseEther('32') - const vaultAddr = await vault.getAddress() - const vaultBalance = await ethers.provider.getBalance(vaultAddr) - const poolEscrowAddr = await poolEscrow.getAddress() - const poolEscrowBalance = await ethers.provider.getBalance(poolEscrowAddr) - const vaultTotalBalance = - validatorDeposit + - vaultBalance + - poolEscrowBalance + - (await vault.convertToAssets(await vault.queuedShares())) - - await setBalance(vaultAddr, 0n) - await setBalance(poolEscrowAddr, vaultTotalBalance) - expect(await vault.withdrawableAssets()).to.be.greaterThanOrEqual(validatorDeposit) - const tx = await registerEthValidator( - vault, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await expect(tx) - .to.emit(poolEscrow, 'Withdrawn') - .withArgs(vaultAddr, vaultAddr, vaultTotalBalance) - await snapshotGasCost(tx) - }) - - it('pulls withdrawals on multiple validators registration', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - const validatorsData = await createEthValidatorsData(vault) - const validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const vaultAddr = await vault.getAddress() - // reset validator index - await depositDataRegistry.connect(admin).setDepositDataRoot(vaultAddr, ZERO_BYTES32) - await depositDataRegistry.connect(admin).setDepositDataRoot(vaultAddr, validatorsData.root) - const proof = getValidatorsMultiProof(validatorsData.tree, validatorsData.validators, [ - ...Array(validatorsData.validators.length).keys(), - ]) - const validators = validatorsData.validators - const assets = ethers.parseEther('32') * BigInt(validators.length) - - const sortedVals = proof.leaves.map((v) => v[0]) - const indexes = validators.map((v) => sortedVals.indexOf(v)) - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: assets }) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - - const signingData = await getEthValidatorsSigningData( - Buffer.concat(validators), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ) - const approveParams = { - validatorsRegistryRoot, - validators: `0x${Buffer.concat(validators).toString('hex')}`, - signatures: getOraclesSignatures(signingData, ORACLES.length), - exitSignaturesIpfsHash, - deadline, - } - - const vaultBalance = await ethers.provider.getBalance(vaultAddr) - const poolEscrowAddr = await poolEscrow.getAddress() - const poolEscrowBalance = await ethers.provider.getBalance(poolEscrowAddr) - const vaultTotalBalance = - vaultBalance + poolEscrowBalance + (await vault.convertToAssets(await vault.queuedShares())) - - await setBalance(vaultAddr, 0n) - await setBalance(poolEscrowAddr, vaultTotalBalance) - - const tx = await depositDataRegistry - .connect(admin) - .registerValidators(vaultAddr, approveParams, indexes, proof.proofFlags, proof.proof) - await expect(tx) - .to.emit(poolEscrow, 'Withdrawn') - .withArgs(vaultAddr, vaultAddr, vaultTotalBalance) - await snapshotGasCost(tx) - }) - - it('can deposit through receive fallback function', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddr = await depositorMock.getAddress() - const amount = ethers.parseEther('100') - let expectedShares = await vault.convertToShares(amount) - - const receipt = await depositorMock.connect(other).depositToVault({ value: amount }) - if (MAINNET_FORK.enabled) { - expectedShares += 1n // rounding error - } - expect(await vault.getShares(await depositorMock.getAddress())).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddr, depositorMockAddr, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - describe('update state', () => { - let totalVaultAssets: bigint - let totalLegacyAssets: bigint - - beforeEach(async () => { - if (MAINNET_FORK.enabled) { - totalVaultAssets = await vault.totalAssets() - totalLegacyAssets = await rewardEthToken.totalAssets() - } else { - totalVaultAssets = ethers.parseEther('10') - totalLegacyAssets = ethers.parseEther('5') - await vault.deposit(other.address, ZERO_ADDRESS, { - value: totalVaultAssets - SECURITY_DEPOSIT, - }) - await rewardEthToken.connect(other).setTotalStaked(totalLegacyAssets) - } - }) - - it('splits reward between rewardEthToken and vault', async () => { - await acceptPoolEscrowOwnership() - const reward = ethers.parseEther('30') - const unlockedMevReward = 0n - const expectedVaultDelta = - (reward * totalVaultAssets) / (totalLegacyAssets + totalVaultAssets) - const expectedLegacyDelta = reward - expectedVaultDelta - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - const exitQueueAssets = await extractCheckpointAssets(receipt) - - if (MAINNET_FORK.enabled) { - // rounding error - totalLegacyAssets -= 1n - totalVaultAssets += 1n - } - - expect(await rewardEthToken.totalAssets()).to.eq(totalLegacyAssets + expectedLegacyDelta) - expect(await vault.totalAssets()).to.eq( - totalVaultAssets + expectedVaultDelta - exitQueueAssets - ) - await snapshotGasCost(receipt) - }) - - it('skips updating legacy with zero total assets', async () => { - if (MAINNET_FORK.enabled) return - await acceptPoolEscrowOwnership() - await rewardEthToken.setTotalStaked(0n) - await rewardEthToken.setTotalRewards(0n) - await rewardEthToken.setTotalPenalty(0n) - - const reward = ethers.parseEther('5') - const unlockedMevReward = 0n - - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - - const totalLegacyAssetsBefore = await rewardEthToken.totalAssets() - const totalVaultAssetsBefore = await vault.totalAssets() - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - expect(await rewardEthToken.totalAssets()).to.eq(totalLegacyAssetsBefore) - expect(await vault.totalAssets()).to.eq(totalVaultAssetsBefore + reward) - await snapshotGasCost(receipt) - }) - - it('fails when pool escrow ownership not accepted', async () => { - const [vault] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - const totalRewards = ethers.parseEther('30') - const vaultReward = getHarvestParams(await vault.getAddress(), totalRewards, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ).to.be.revertedWithCustomError(vault, 'InvalidInitialHarvest') - }) - - it('fails with negative first update', async () => { - const [vault] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - await vault.connect(admin).acceptPoolEscrowOwnership() - const totalPenalty = ethers.parseEther('-5') - const vaultReward = getHarvestParams(await vault.getAddress(), totalPenalty, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ).to.revertedWithCustomError(vault, 'InvalidInitialHarvest') - }) - - it('splits penalty between rewardEthToken and vault', async () => { - await acceptPoolEscrowOwnership() - await collatEthVault() - const reward = ethers.parseEther('-5') - const unlockedMevReward = 0n - const expectedVaultDelta = - (reward * totalVaultAssets) / (totalLegacyAssets + totalVaultAssets) - const expectedLegacyDelta = reward - expectedVaultDelta - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - const exitQueueAssets = await extractCheckpointAssets(receipt) - - expect((await rewardEthToken.totalAssets()) - (await rewardEthToken.totalPenalty())).to.eq( - totalLegacyAssets + expectedLegacyDelta + 1n // rounding error - ) - expect(await vault.totalAssets()).to.eq( - totalVaultAssets + expectedVaultDelta - exitQueueAssets - 1n // rounding error - ) - await snapshotGasCost(receipt) - }) - - it('deducts rewards on first state update', async () => { - const [vault, rewardEthToken] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - await vault.connect(admin).acceptPoolEscrowOwnership() - await vault.deposit(other.address, ZERO_ADDRESS, { - value: totalVaultAssets - SECURITY_DEPOSIT, - }) - await rewardEthToken.connect(other).setTotalStaked(totalLegacyAssets) - - const totalRewards = ethers.parseEther('25') - const legacyRewards = ethers.parseEther('5') - await rewardEthToken.connect(other).setTotalRewards(legacyRewards) - expect(await rewardEthToken.totalAssets()).to.eq(totalLegacyAssets + legacyRewards) - expect(await rewardEthToken.totalRewards()).to.eq(legacyRewards) - expect(await vault.totalAssets()).to.eq(totalVaultAssets) - - const expectedVaultDelta = - ((totalRewards - legacyRewards) * totalVaultAssets) / - (totalLegacyAssets + legacyRewards + totalVaultAssets) - const expectedLegacyDelta = totalRewards - legacyRewards - expectedVaultDelta - const vaultReward = getHarvestParams(await vault.getAddress(), totalRewards, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - if (MAINNET_FORK.enabled) { - // rounding error - totalLegacyAssets -= 1n - totalVaultAssets += 1n - } - - expect(await rewardEthToken.totalAssets()).to.eq( - totalLegacyAssets + legacyRewards + expectedLegacyDelta - ) - expect(await vault.totalAssets()).to.eq(totalVaultAssets + expectedVaultDelta) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/EthGenesisVault.t.sol b/test/EthGenesisVault.t.sol new file mode 100644 index 00000000..923eb186 --- /dev/null +++ b/test/EthGenesisVault.t.sol @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IEthGenesisVault} from '../contracts/interfaces/IEthGenesisVault.sol'; +import {IEthPoolEscrow} from '../contracts/interfaces/IEthPoolEscrow.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {EthGenesisVault} from '../contracts/vaults/ethereum/EthGenesisVault.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthGenesisVaultTest is Test, EthHelpers { + ForkContracts public contracts; + address public admin; + address public user; + address public poolEscrow; + address public rewardEthToken; + bytes public initParams; + + function setUp() public { + // Activate Ethereum fork and get contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + + // Fund accounts with ETH for testing + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Get pool escrow and reward token addresses from the helper + poolEscrow = _poolEscrow; + rewardEthToken = _rewardEthToken; + + initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + } + + function test_deployFails() public { + // Deploy the vault directly + vm.deal(admin, 1 ether); + vm.prank(admin); + address impl = _getOrCreateVaultImpl(VaultType.EthGenesisVault); + address _vault = address(new ERC1967Proxy(impl, '')); + + vm.expectRevert(Errors.UpgradeFailed.selector); + IEthGenesisVault(_vault).initialize(initParams); + } + + function test_upgradesCorrectly() public { + // Get or create a vault + address vaultAddr = _getForkVault(VaultType.EthGenesisVault); + EthGenesisVault existingVault = EthGenesisVault(payable(vaultAddr)); + + vm.deal( + vaultAddr, + existingVault.totalExitingAssets() + + existingVault.convertToAssets(existingVault.queuedShares()) + + vaultAddr.balance + ); + _depositToVault(address(existingVault), 40 ether, user, user); + _registerEthValidator(address(existingVault), 32 ether, true); + + vm.prank(user); + existingVault.enterExitQueue(10 ether, user); + + // Record initial state + uint256 initialTotalAssets = existingVault.totalAssets(); + uint256 initialTotalShares = existingVault.totalShares(); + uint256 totalExitingAssetsBefore = existingVault.totalExitingAssets(); + uint256 queuedSharesBefore = existingVault.queuedShares(); + uint256 senderBalanceBefore = existingVault.getShares(user); + uint256 initialCapacity = existingVault.capacity(); + uint256 initialFeePercent = existingVault.feePercent(); + address validatorsManager = existingVault.validatorsManager(); + address feeRecipient = existingVault.feeRecipient(); + address adminBefore = existingVault.admin(); + + assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); + assertEq(existingVault.version(), 4); + + _startSnapshotGas('EthGenesisVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthGenesisVault, address(existingVault)); + _stopSnapshotGas(); + + assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); + assertEq(existingVault.version(), 5); + assertEq(existingVault.admin(), adminBefore); + assertEq(existingVault.capacity(), initialCapacity); + assertEq(existingVault.feePercent(), initialFeePercent); + assertEq(existingVault.feeRecipient(), feeRecipient); + assertEq(existingVault.validatorsManager(), validatorsManager); + assertEq(existingVault.queuedShares(), queuedSharesBefore); + assertEq(existingVault.totalShares(), initialTotalShares); + assertEq(existingVault.totalAssets(), initialTotalAssets); + assertEq(existingVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(existingVault.validatorsManagerNonce(), 0); + assertEq(existingVault.getShares(user), senderBalanceBefore); + } + + function test_cannotInitializeTwice() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Try to initialize it again + vm.prank(admin); + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize(initParams); + } + + function test_migrate_failsWithInvalidCaller() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Try to migrate with invalid caller (not rewardEthToken) + vm.prank(user); + vm.expectRevert(Errors.AccessDenied.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithInvalidPoolEscrowOwner() public { + // Get or create a vault with a different pool escrow ownership + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be different from the vault + vm.mockCall( + poolEscrow, + abi.encodeWithSelector(IEthPoolEscrow.owner.selector), + abi.encode(address(0x123)) + ); + + // Try to migrate + vm.prank(rewardEthToken); + vm.expectRevert(Errors.AccessDenied.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithNotHarvested() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be the vault + vm.mockCall( + poolEscrow, + abi.encodeWithSelector(IEthPoolEscrow.owner.selector), + abi.encode(address(vault)) + ); + + // Ensure vault needs harvesting + _setEthVaultReward(address(vault), 1 ether, 0); + _setEthVaultReward(address(vault), 2 ether, 0); + + vm.prank(rewardEthToken); + vm.expectRevert(Errors.NotHarvested.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithInvalidReceiver() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be the vault + vm.mockCall( + poolEscrow, + abi.encodeWithSelector(IEthPoolEscrow.owner.selector), + abi.encode(address(vault)) + ); + + vm.prank(rewardEthToken); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.migrate(address(0), 1 ether); + } + + function test_migrate_failsWithInvalidAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be the vault + vm.mockCall( + poolEscrow, + abi.encodeWithSelector(IEthPoolEscrow.owner.selector), + abi.encode(address(vault)) + ); + + vm.prank(rewardEthToken); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.migrate(user, 0); + } + + function test_migrate_works() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Ensure vault is harvested + _collateralizeEthVault(address(vault)); + + // Mock the pool escrow owner to be the vault + vm.mockCall( + poolEscrow, + abi.encodeWithSelector(IEthPoolEscrow.owner.selector), + abi.encode(address(vault)) + ); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + + // Set up migration + uint256 migrateAmount = 10 ether; + uint256 osTokenShares = vault.osTokenPositions(user); + assertEq(osTokenShares, 0, 'OsToken position should be empty'); + + // Perform migration + _startSnapshotGas('EthGenesisVaultTest_test_migrate_works'); + vm.prank(rewardEthToken); + uint256 shares = vault.migrate(user, migrateAmount); + _stopSnapshotGas(); + + // Verify results + assertGt(shares, 0, 'Should have minted shares'); + assertEq(vault.getShares(user), shares, 'User should have received shares'); + assertEq( + vault.totalAssets(), + initialTotalAssets + migrateAmount, + 'Total assets should increase' + ); + assertEq(vault.totalShares(), initialTotalShares + shares, 'Total shares should increase'); + + // Verify OsToken position + osTokenShares = vault.osTokenPositions(user); + assertGt(osTokenShares, 0, 'OsToken position should be created'); + } + + function test_pullWithdrawals_claimEscrowAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Add some ETH to the pool escrow + uint256 escrowAmount = 40 ether; + vm.deal(poolEscrow, poolEscrow.balance + escrowAmount); + vm.deal( + address(vault), + address(vault).balance + + vault.convertToAssets(vault.queuedShares()) + + vault.totalExitingAssets() + ); + + // Record initial balances + uint256 vaultInitialBalance = address(vault).balance; + + // Register a validator to trigger _pullWithdrawals + _startSnapshotGas('GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets'); + _registerEthValidator(address(vault), 32 ether, false); + _stopSnapshotGas(); + + // Verify results + uint256 vaultFinalBalance = address(vault).balance; + uint256 escrowFinalBalance = poolEscrow.balance; + + assertGt( + vaultFinalBalance, + vaultInitialBalance, + 'Vault balance should increase from claiming escrow assets' + ); + + assertEq(escrowFinalBalance, 0, 'Pool escrow balance should be emptied'); + } + + function test_fallback_acceptsEtherFromPoolEscrow() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + uint256 initialBalance = address(vault).balance; + uint256 totalShares = vault.totalShares(); + uint256 amount = 3 ether; + + // Send ETH from pool escrow + vm.deal(poolEscrow, poolEscrow.balance + amount); + vm.prank(poolEscrow); + _startSnapshotGas('EthGenesisVaultTest_test_fallback_acceptsEtherFromPoolEscrow'); + (bool success, ) = address(vault).call{value: amount}(''); + _stopSnapshotGas(); + + assertTrue(success, 'ETH transfer should succeed'); + assertEq( + vault.totalShares(), + totalShares, + 'Total shares should not change after deposit from pool escrow' + ); + assertEq( + address(vault).balance, + initialBalance + amount, + 'Vault balance should increase by transfer amount' + ); + } + + function test_fallback_acceptsEtherFromUser() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + uint256 initialShares = vault.getShares(user); + uint256 amount = 2 ether; + + // Send ETH from user (should create shares) + _startSnapshotGas('EthGenesisVaultTest_test_fallback_acceptsEtherFromUser'); + vm.prank(user); + (bool success, ) = address(vault).call{value: amount}(''); + _stopSnapshotGas(); + + assertTrue(success, 'ETH transfer should succeed'); + assertGt(vault.getShares(user), initialShares, 'User shares should increase after deposit'); + } + + function test_claimsPoolEscrowAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + uint256 vaultAmount = vault.totalExitingAssets() + + vault.convertToAssets(vault.queuedShares()) + + vaultAddr.balance; + + uint256 depositAmount = 3 ether; + uint256 shares = vault.convertToShares(depositAmount); + _depositToVault(vaultAddr, depositAmount, user, user); + + vm.deal(vaultAddr, 0); + vm.deal(poolEscrow, vaultAmount + depositAmount); + + // Enter exit queue + vm.prank(user); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas('EthGenesisVaultTest_test_claimsPoolEscrowAssets'); + uint256 positionTicket = vault.enterExitQueue(shares, user); + _stopSnapshotGas(); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Claim exited assets + vm.prank(user); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + } +} diff --git a/test/EthOsTokenVaultEscrow.t.sol b/test/EthOsTokenVaultEscrow.t.sol new file mode 100644 index 00000000..0a179e8d --- /dev/null +++ b/test/EthOsTokenVaultEscrow.t.sol @@ -0,0 +1,1441 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; +import {IOsTokenVaultEscrow} from '../contracts/interfaces/IOsTokenVaultEscrow.sol'; +import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +interface IStrategiesRegistry { + function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; + function setStrategy(address strategy, bool enabled) external; + + function owner() external view returns (address); +} + +contract EthOsTokenVaultEscrowTest is Test, EthHelpers { + IStrategiesRegistry private constant _strategiesRegistry = + IStrategiesRegistry(0x90b82E4b3aa385B4A02B7EBc1892a4BeD6B5c465); + + ForkContracts public contracts; + IEthVault public vault; + + address public user; + address public admin; + address public liquidator; + + function setUp() public { + // Activate Ethereum fork and get contracts + contracts = _activateEthereumFork(); + + // Setup addresses + user = makeAddr('user'); + admin = makeAddr('admin'); + liquidator = makeAddr('liquidator'); + + // Fund accounts + vm.deal(user, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(liquidator, 100 ether); + + // Register user + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(user)), user); + + // Create a vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = IEthVault(_vault); + + // Ensure the vault has enough ETH to process exit requests + vm.deal( + address(vault), + address(vault).balance + + vault.totalExitingAssets() + + vault.convertToAssets(vault.queuedShares()) + ); + } + + function test_register_success() public { + // Arrange: First, collateralize the vault and deposit ETH + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // Calculate osToken shares based on the vault's LTV ratio + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + // Mint osToken shares to the user + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + uint256 cumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); + + // Expect the PositionCreated event + vm.expectEmit(true, false, true, true); + emit IOsTokenVaultEscrow.PositionCreated( + address(vault), + 0, + user, + osTokenShares, + cumulativeFeePerShare + ); + + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Act & Assert: Verify the position was registered correctly + (address registeredOwner, uint256 exitedAssets, uint256 registeredShares) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + assertEq(registeredOwner, user, 'Incorrect owner registered'); + assertEq(exitedAssets, 0, 'Initial exited assets should be zero'); + assertEq(registeredShares, osTokenShares, 'Incorrect osToken shares registered'); + } + + function test_register_directCall() public { + // Arrange: Set up authenticator to allow calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + // We need to mock the authenticator to test direct calls + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256('canRegister(address,address,uint256,uint256)')), + address(this), + user, + 123, + 100 + ), + abi.encode(true) + ); + + // Act: Call register directly + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_directCall'); + + // Expect the PositionCreated event + vm.expectEmit(true, true, true, true); + emit IOsTokenVaultEscrow.PositionCreated( + address(this), + 123, + user, + 100, + 1e18 // default cumulativeFeePerShare + ); + + contracts.osTokenVaultEscrow.register(user, 123, 100, 1e18); + _stopSnapshotGas(); + + // Assert: Verify position was created + (address owner, uint256 exitedAssets, uint256 shares) = contracts + .osTokenVaultEscrow + .getPosition(address(this), 123); + + assertEq(owner, user, 'Incorrect owner'); + assertEq(exitedAssets, 0, 'Initial exited assets should be zero'); + assertEq(shares, 100, 'Incorrect shares amount'); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_accessDenied() public { + // Arrange: Set up authenticator to deny calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256('canRegister(address,address,uint256,uint256)')), + address(this), + user, + 123, + 100 + ), + abi.encode(false) + ); + + // Act & Assert: Expect revert on unauthorized call + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_accessDenied'); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.osTokenVaultEscrow.register(user, 123, 100, 1e18); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_zeroAddress() public { + // Arrange: Set up authenticator to allow calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256('canRegister(address,address,uint256,uint256)')), + address(this), + address(0), + 123, + 100 + ), + abi.encode(true) + ); + + // Act & Assert: Expect revert on zero address + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_zeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + contracts.osTokenVaultEscrow.register(address(0), 123, 100, 1e18); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_invalidShares() public { + // Arrange: Set up authenticator to allow calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256('canRegister(address,address,uint256,uint256)')), + address(this), + user, + 123, + 0 + ), + abi.encode(true) + ); + + // Act & Assert: Expect revert on zero shares + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_invalidShares'); + vm.expectRevert(Errors.InvalidShares.selector); + contracts.osTokenVaultEscrow.register(user, 123, 0, 1e18); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_fullFlow() public { + // This test demonstrates the full flow from deposit to registering with the escrow + + // 1. Collateralize the vault and make a deposit + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // 2. Calculate and mint osToken shares + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // 3. Transfer position to escrow (which calls register internally) + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_fullFlow'); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + + // 4. Verify the position in escrow + (address owner, uint256 exitedAssets, uint256 shares) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + assertEq(owner, user, 'Incorrect owner'); + assertEq(exitedAssets, 0, 'Initial exited assets should be zero'); + assertEq(shares, osTokenShares, 'Incorrect shares amount'); + + // 5. Verify user's osToken position is now zero + uint256 userOsTokenPosition = vault.osTokenPositions(user); + assertEq(userOsTokenPosition, 0, 'User should have no remaining osTokens'); + } + + function test_processExitedAssets_success() public { + // Arrange: First, collateralize the vault and deposit ETH + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // Calculate osToken shares based on the vault's LTV ratio + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + // Mint osToken shares to the user + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // Transfer position to escrow (which calls register internally) + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Update vault state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Move time forward to allow claiming exited assets + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exitQueueIndex + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Expect the ExitedAssetsProcessed event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.ExitedAssetsProcessed( + address(vault), + address(this), // msg.sender in the test context + exitPositionTicket, + 0 // We don't check exact value as it depends on conversion calculations + ); + + // Act: Process exited assets + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_success'); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + _stopSnapshotGas(); + + // Assert: Verify the position's exited assets were updated + (address owner, uint256 exitedAssets, uint256 shares) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + assertEq(owner, user, 'Owner should still be the same'); + assertGt(exitedAssets, 0, 'Exited assets should be greater than zero'); + assertGt(shares, osTokenShares, 'Shares should have accrued fees'); + } + + function test_processExitedAssets_invalidPosition() public { + // Arrange: Use a non-existent position + uint256 nonExistentTicket = 9999; + + // Act & Assert: Expect revert on invalid position + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_invalidPosition'); + vm.expectRevert(Errors.InvalidPosition.selector); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + nonExistentTicket, + vm.getBlockTimestamp(), + 0 + ); + _stopSnapshotGas(); + } + + function test_processExitedAssets_exitRequestNotProcessed() public { + // Arrange: Collateralize vault, deposit ETH, and set up position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Act & Assert: Try to process before updateState and expect failure + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_exitRequestNotProcessed'); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + _stopSnapshotGas(); + } + + function test_processExitedAssets_claimExitedAssets() public { + // disable fee shares accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); + + // Arrange: Set up all the way to processing + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue and advance time + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exitQueueIndex + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Expect the ExitedAssetsProcessed event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.ExitedAssetsProcessed( + address(vault), + address(this), // msg.sender in the test context + exitPositionTicket, + 0 // We don't check exact value as it depends on conversion calculations + ); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Get position details + (, uint256 exitedAssets, ) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + + // Record user balance before claiming + uint256 userBalanceBefore = user.balance; + + // Act: Claim the exited assets + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_claimExitedAssets'); + vm.prank(user); + uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares + ); + _stopSnapshotGas(); + + // Assert: Verify assets were received and position was deleted + uint256 userBalanceAfter = user.balance; + assertEq( + userBalanceAfter - userBalanceBefore, + claimedAssets, + 'User should receive the claimed assets' + ); + assertEq(claimedAssets, exitedAssets, 'Claimed assets should equal exited assets'); + + // Verify position is deleted after full claim + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + assertEq(ownerAfter, address(0), 'Position should be deleted after full claim'); + assertEq(exitedAssetsAfter, 0, 'Exited assets should be zero after full claim'); + assertEq(sharesAfter, 0, 'Shares should be zero after full claim'); + } + + function test_processExitedAssets_partialClaim() public { + // disable fee shares accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); + + // Arrange: Set up all the way to processing + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue and advance time + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exitQueueIndex + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Expect the ExitedAssetsProcessed event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.ExitedAssetsProcessed( + address(vault), + address(this), // msg.sender in the test context + exitPositionTicket, + 0 // We don't check exact value as it depends on conversion calculations + ); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Get position details + (address owner, uint256 exitedAssets, uint256 shares) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + // Record user balance before claiming + uint256 userBalanceBefore = user.balance; + + // Act: Claim half of the exited assets + uint256 halfShares = osTokenShares / 2; + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_partialClaim'); + vm.prank(user); + uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + halfShares + ); + _stopSnapshotGas(); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Assert: Verify assets were received and position was updated + uint256 userBalanceAfter = user.balance; + assertEq( + userBalanceAfter - userBalanceBefore, + claimedAssets, + 'User should receive the claimed assets' + ); + + // Expected claimed assets should be proportional to shares claimed + uint256 expectedClaimedAssets = (exitedAssets * halfShares) / osTokenShares; + assertApproxEqAbs( + claimedAssets, + expectedClaimedAssets, + 1, + 'Claimed assets should be proportional to shares' + ); + + // Verify position is updated after partial claim + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket_); + + assertEq(ownerAfter, owner, 'Owner should remain unchanged after partial claim'); + assertEq( + exitedAssetsAfter, + exitedAssets - claimedAssets, + 'Exited assets should be reduced by claimed amount' + ); + assertEq(sharesAfter, shares - halfShares, 'Shares should be reduced by claimed amount'); + } + + function test_claimExitedAssets_notOwner() public { + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Try to claim as a different user + address otherUser = makeAddr('otherUser'); + _mintOsToken(otherUser, osTokenShares); // Give them the required osToken shares + + vm.startPrank(otherUser); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_notOwner'); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares + ); + _stopSnapshotGas(); + vm.stopPrank(); + } + + function test_claimExitedAssets_insufficientShares() public { + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Mint extra shares to the user so they have enough to try claiming + _mintOsToken(user, osTokenShares * 2); + + // Try to claim more shares than available + vm.prank(user); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_insufficientShares'); + vm.expectRevert(Errors.InvalidShares.selector); + contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares * 2 // More than available + ); + _stopSnapshotGas(); + } + + function test_claimExitedAssets_nonExistentPosition() public { + // Try to claim from a non-existent position ticket + uint256 nonExistentTicket = 9999; + + _mintOsToken(user, 1 ether); // Give them some osToken shares + + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_nonExistentPosition'); + vm.expectRevert(); // Will revert with a custom error + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), nonExistentTicket, 1 ether); + _stopSnapshotGas(); + } + + function test_claimExitedAssets_noProcessedAssets() public { + // Setup a position without processing exited assets + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Skip processing exit queue + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Try to claim without processed assets + vm.prank(user); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_noProcessedAssets'); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares + ); + _stopSnapshotGas(); + } + + function test_claimExitedAssets_withFeeAccrual() public { + // Set up a realistic APR for fee accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(868240800); // ~3% APR + + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 initialCumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Fast forward time to accrue fees + vm.warp(timestamp + _exitingAssetsClaimDelay + 30 days); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Check if fees accrued + uint256 newCumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); + assertGt(newCumulativeFeePerShare, initialCumulativeFeePerShare, 'Fees should have accrued'); + + // Get position details before claiming + (, uint256 exitedAssets, uint256 positionShares) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + + // Shares should have increased due to fee accrual + assertGt(positionShares, osTokenShares, 'Position shares should have increased due to fees'); + + // Record user balance before claiming + uint256 userBalanceBefore = user.balance; + + // Claim assets + vm.prank(user); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_withFeeAccrual'); + uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares + ); + _stopSnapshotGas(); + + // Verify assets were received + uint256 userBalanceAfter = user.balance; + assertEq( + userBalanceAfter - userBalanceBefore, + claimedAssets, + 'User should receive the correct amount of assets' + ); + assertLt(claimedAssets, exitedAssets, 'Fee assets should not be included in the claim'); + } + + function test_claimExitedAssets_minimalAmount() public { + // disable fee shares accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); + + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Get position details + (, uint256 exitedAssets, uint256 shares) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + + // Try to claim minimal shares (1 wei) + uint256 minimalShares = 1; + uint256 userBalanceBefore = user.balance; + + vm.prank(user); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_minimalAmount'); + uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + minimalShares + ); + _stopSnapshotGas(); + + // Verify appropriate tiny amount was claimed + uint256 userBalanceAfter = user.balance; + assertEq( + userBalanceAfter - userBalanceBefore, + claimedAssets, + 'User should receive the claimed assets' + ); + + // Expected claimed assets for tiny share amount + uint256 expectedClaimedAssets = (exitedAssets * minimalShares) / shares; + assertEq( + claimedAssets, + expectedClaimedAssets, + 'Claimed assets should be proportional to shares' + ); + } + + // Helper function to setup a position in escrow + function _setupEscrowPosition() + internal + returns (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) + { + // Collateralize vault and deposit + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // Calculate and mint osToken shares + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // Transfer position to escrow + timestamp = vm.getBlockTimestamp(); + vm.prank(user); + exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + return (exitPositionTicket, osTokenShares, timestamp); + } + + // Helper function to make a position unhealthy for liquidation + function _makePositionUnhealthy( + address _vault, + uint256 exitPositionTicket, + uint256 timestamp, + uint256 exitQueueIndex + ) internal { + // Process exited assets first + contracts.osTokenVaultEscrow.processExitedAssets( + _vault, + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Artificially manipulate the position to make it unhealthy + // We'll simulate a price drop by increasing the value of the osToken shares relative to exited assets + // This is done by setting a high average reward per second in the vault controller + vm.prank(address(contracts.keeper)); + contracts.osTokenVaultController.setAvgRewardPerSecond(4341204000); // 15 % + + // Advance time to allow the high APR to take effect + vm.warp(vm.getBlockTimestamp() + 365 days); + + // Force an update of the osToken state to reflect the new values + contracts.osTokenVaultController.updateState(); + + vm.prank(address(contracts.keeper)); + contracts.osTokenVaultController.setAvgRewardPerSecond(0); + } + + function test_liquidateOsToken_success() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, osTokenShares); + + // Get position details before liquidation + (address ownerBefore, uint256 exitedAssetsBefore, uint256 sharesBefore) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Record liquidator balance before + uint256 liquidatorBalanceBefore = liquidator.balance; + + // Expected bonus based on the liquidation bonus from the contract + uint256 liqBonusPercent = contracts.osTokenVaultEscrow.liqBonusPercent(); + uint256 liquidationAssets = (exitedAssetsBefore * 1e18) / liqBonusPercent; + uint256 liquidationShares = contracts.osTokenVaultController.convertToShares(liquidationAssets); + + // Expect liquidation event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.OsTokenLiquidated( + liquidator, + address(vault), + exitPositionTicket_, + liquidator, + liquidationShares, + exitedAssetsBefore + ); + + // Liquidate the position + vm.prank(liquidator); + _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_success'); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), + exitPositionTicket_, + liquidationShares, + liquidator + ); + _stopSnapshotGas(); + + // Get position details after liquidation + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket_); + + // Verify liquidator received assets + uint256 liquidatorBalanceAfter = liquidator.balance; + assertApproxEqAbs( + liquidatorBalanceAfter - liquidatorBalanceBefore, + exitedAssetsBefore, + 2, + 'Liquidator did not receive correct amount of assets' + ); + + // Verify position was updated + assertEq(ownerAfter, ownerBefore, 'Owner should not change'); + assertApproxEqAbs(exitedAssetsAfter, 0, 2, 'Exited assets not correctly reduced'); + assertLt(sharesAfter, sharesBefore, 'Shares not correctly reduced'); + } + + function test_liquidateOsToken_invalidHealthFactor() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Process exited assets without making the position unhealthy + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, osTokenShares); + + // Get liquidation amount + (, , uint256 sharesBefore) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + uint256 liquidationShares = sharesBefore / 2; + + // Try to liquidate a healthy position + vm.prank(liquidator); + _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_invalidHealthFactor'); + vm.expectRevert(Errors.InvalidHealthFactor.selector); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), + exitPositionTicket, + liquidationShares, + liquidator + ); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_invalidPosition() public { + // Setup a non-existent position + uint256 nonExistentTicket = 9999; + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, 1 ether); + + // Try to liquidate a non-existent position + vm.prank(liquidator); + _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_invalidPosition'); + vm.expectRevert(Errors.InvalidPosition.selector); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), + nonExistentTicket, + 1 ether, + liquidator + ); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_zeroAddress() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, osTokenShares); + + // Try to liquidate to zero address + vm.prank(liquidator); + _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_zeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), + exitPositionTicket, + osTokenShares, + address(0) + ); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_invalidReceivedAssets() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint too many osToken shares to liquidator (much more than the position value) + uint256 excessiveShares = osTokenShares * 100; + _mintOsToken(liquidator, excessiveShares); + + // Try to liquidate with excessive shares + vm.prank(liquidator); + _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_invalidReceivedAssets'); + vm.expectRevert(Errors.InvalidReceivedAssets.selector); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), + exitPositionTicket, + excessiveShares, + liquidator + ); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_partialLiquidation() public { + // Setup a position in escrow + (uint256 exitPositionTicket, , uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Get position details before liquidation + (address ownerBefore, uint256 exitedAssetsBefore, uint256 sharesBefore) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + // Only liquidate half of the position + uint256 liqBonusPercent = contracts.osTokenVaultEscrow.liqBonusPercent(); + uint256 halfExitedAssets = exitedAssetsBefore / 2; + uint256 halfLiquidationAssets = (halfExitedAssets * 1e18) / liqBonusPercent; + uint256 halfLiquidationShares = contracts.osTokenVaultController.convertToShares( + halfLiquidationAssets + ); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, halfLiquidationShares); + + // Record liquidator balance before + uint256 liquidatorBalanceBefore = liquidator.balance; + + // Liquidate half the position + vm.prank(liquidator); + _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_partialLiquidation'); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), + exitPositionTicket, + halfLiquidationShares, + liquidator + ); + _stopSnapshotGas(); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Get position details after liquidation + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket_); + + // Verify partial liquidation results + assertEq(ownerAfter, ownerBefore, 'Owner should not change'); + assertApproxEqAbs( + exitedAssetsAfter, + exitedAssetsBefore - halfExitedAssets, + 10, + 'Exited assets should be reduced by approximately half' + ); + assertLt(sharesAfter, sharesBefore, 'Shares should be reduced'); + + // Verify liquidator received assets + uint256 liquidatorBalanceAfter = liquidator.balance; + assertApproxEqAbs( + liquidatorBalanceAfter - liquidatorBalanceBefore, + halfExitedAssets, + 10, + 'Liquidator should receive approximately half of the exited assets' + ); + } + + function test_redeemOsToken_success() public { + vm.prank(address(contracts.keeper)); + contracts.osTokenVaultController.setAvgRewardPerSecond(0); + + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Get position details before redemption + (address ownerBefore, uint256 exitedAssetsBefore, ) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + uint256 expectedAssets = contracts.osTokenVaultController.convertToAssets(osTokenShares); + + // Mint osToken shares to the redeemer + address redeemer = makeAddr('redeemer'); + _mintOsToken(redeemer, osTokenShares); + + // set redeemer + vm.prank(Ownable(address(contracts.keeper)).owner()); + contracts.osTokenConfig.setRedeemer(redeemer); + + // Record redeemer balance before + address receiver = makeAddr('receiver'); + uint256 receiverBalanceBefore = receiver.balance; + + // Expect OsTokenRedeemed event + vm.expectEmit(true, true, true, true); + emit IOsTokenVaultEscrow.OsTokenRedeemed( + redeemer, + address(vault), + exitPositionTicket, + receiver, + osTokenShares, + expectedAssets + ); + + // Redeem the position + vm.prank(redeemer); + _startSnapshotGas('OsTokenLiquidationTest_test_redeemOsToken_success'); + contracts.osTokenVaultEscrow.redeemOsToken( + address(vault), + exitPositionTicket, + osTokenShares, + receiver + ); + _stopSnapshotGas(); + + // Verify receiver received assets + uint256 receiverBalanceAfter = receiver.balance; + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + expectedAssets, + 'Receiver should receive all exited assets' + ); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Get position details after redemption + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket_); + + // Verify position was updated + assertEq(ownerAfter, ownerBefore, 'Owner should not change'); + assertEq( + exitedAssetsAfter, + exitedAssetsBefore - expectedAssets, + 'Exited assets should be zero' + ); + assertEq(sharesAfter, 0, 'Shares should be zero'); + } + + function test_redeemOsToken_notRedeemer() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + exitQueueIndex + ); + + // Mock the osTokenConfig.redeemer call to return an official redeemer address + address officialRedeemer = makeAddr('officialRedeemer'); + vm.mockCall( + address(contracts.osTokenConfig), + abi.encodeWithSelector(bytes4(keccak256('redeemer()'))), + abi.encode(officialRedeemer) + ); + + // Try to redeem from an unauthorized address + address unauthorizedCaller = makeAddr('unauthorizedCaller'); + _mintOsToken(unauthorizedCaller, osTokenShares); + + vm.prank(unauthorizedCaller); + _startSnapshotGas('OsTokenLiquidationTest_test_redeemOsToken_notRedeemer'); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.osTokenVaultEscrow.redeemOsToken( + address(vault), + exitPositionTicket, + osTokenShares, + unauthorizedCaller + ); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_updateLiqConfig_success() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Define new values - using conservative values + uint64 newLiqThresholdPercent = 5e17; // 50% + uint256 newLiqBonusPercent = 1.1e18; // 110% + + // Expect LiqConfigUpdated event + vm.expectEmit(true, true, false, false); + emit IOsTokenVaultEscrow.LiqConfigUpdated(newLiqThresholdPercent, newLiqBonusPercent); + + // Call updateLiqConfig as owner + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_success'); + contracts.osTokenVaultEscrow.updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent); + _stopSnapshotGas(); + + // Verify state was updated + assertEq( + contracts.osTokenVaultEscrow.liqThresholdPercent(), + newLiqThresholdPercent, + 'liqThresholdPercent not updated correctly' + ); + assertEq( + contracts.osTokenVaultEscrow.liqBonusPercent(), + newLiqBonusPercent, + 'liqBonusPercent not updated correctly' + ); + } + + function test_updateLiqConfig_onlyOwner() public { + // Define values + uint64 newLiqThresholdPercent = 5e17; // 50% + uint256 newLiqBonusPercent = 1.1e18; // 110% + + // Get a non-owner address + address nonOwner = makeAddr('nonOwner'); + + // Call updateLiqConfig as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_onlyOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + contracts.osTokenVaultEscrow.updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent); + _stopSnapshotGas(); + } + + function test_updateLiqConfig_invalidThreshold() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Test with threshold = 0 + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_zero'); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(0, 1.1e18); + _stopSnapshotGas(); + + // Test with threshold = 1e18 (100%) + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_max'); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(1e18, 1.1e18); + _stopSnapshotGas(); + } + + function test_updateLiqConfig_invalidBonus() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Test with bonus < _maxPercent (1e18) + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_low'); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(5e17, 0.9e18); + _stopSnapshotGas(); + + // Test with bonus too high (threshold * bonus > _maxPercent) + // If threshold = 90% (0.9e18) and bonus = 112% (1.12e18), + // then 0.9e18 * 1.12e18 / 1e18 = 1.008e18 > 1e18 + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_high'); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(9e17, 1.12e18); + _stopSnapshotGas(); + } + + function test_setAuthenticator_success() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Get current authenticator + address currentAuthenticator = contracts.osTokenVaultEscrow.authenticator(); + + // Create a new authenticator address + address newAuthenticator = makeAddr('newAuthenticator'); + + // Ensure it's different from the current one + if (newAuthenticator == currentAuthenticator) { + newAuthenticator = makeAddr('newAuthenticator2'); + } + + // Expect AuthenticatorUpdated event + vm.expectEmit(true, false, false, false); + emit IOsTokenVaultEscrow.AuthenticatorUpdated(newAuthenticator); + + // Call setAuthenticator as owner + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_setAuthenticator_success'); + contracts.osTokenVaultEscrow.setAuthenticator(newAuthenticator); + _stopSnapshotGas(); + + // Verify state was updated + assertEq( + contracts.osTokenVaultEscrow.authenticator(), + newAuthenticator, + 'Authenticator not updated correctly' + ); + } + + function test_setAuthenticator_onlyOwner() public { + // Create a new authenticator address + address newAuthenticator = makeAddr('newAuthenticator'); + + // Get a non-owner address + address nonOwner = makeAddr('nonOwner'); + + // Call setAuthenticator as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_setAuthenticator_onlyOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + contracts.osTokenVaultEscrow.setAuthenticator(newAuthenticator); + _stopSnapshotGas(); + } + + function test_setAuthenticator_valueNotChanged() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Get current authenticator + address currentAuthenticator = contracts.osTokenVaultEscrow.authenticator(); + + // Call setAuthenticator with the same authenticator, should revert + vm.prank(escrowOwner); + _startSnapshotGas('EthOsTokenVaultEscrowTest_test_setAuthenticator_valueNotChanged'); + vm.expectRevert(Errors.ValueNotChanged.selector); + contracts.osTokenVaultEscrow.setAuthenticator(currentAuthenticator); + _stopSnapshotGas(); + } +} diff --git a/test/EthPrivErc20Vault.spec.ts b/test/EthPrivErc20Vault.spec.ts deleted file mode 100644 index b354c838..00000000 --- a/test/EthPrivErc20Vault.spec.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthPrivErc20Vault, - IKeeperRewards, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ZERO_ADDRESS } from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { collateralizeEthVault, getRewardsRootProof, updateRewards } from './shared/rewards' -import keccak256 from 'keccak256' - -describe('EthPrivErc20Vault', () => { - const capacity = ethers.parseEther('1000') - const name = 'SW ETH Vault' - const symbol = 'SW-ETH-1' - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Signer, other: Wallet - let vault: EthPrivErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - depositDataRegistry: DepositDataRegistry - - let createPrivateVault: ThenArg>['createEthPrivErc20Vault'] - - beforeEach('deploy fixtures', async () => { - ;[sender, admin, other] = await (ethers as any).getSigners() - ;({ - createEthPrivErc20Vault: createPrivateVault, - keeper, - validatorsRegistry, - osTokenVaultController, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createPrivateVault(admin, { - capacity, - name, - symbol, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthPrivErc20Vault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(await admin.getAddress()) - await vault.connect(admin).updateWhitelist(await admin.getAddress(), true) - await vault.connect(admin).updateWhitelist(sender.address, true) - }) - - it('cannot be called by not whitelisted sender', async () => { - await expect( - vault.connect(other).deposit(other.address, referrer, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot update state and call', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const vaultReward = ethers.parseEther('1') - const tree = await updateRewards(keeper, [ - { reward: vaultReward, unlockedMevReward: 0n, vault: await vault.getAddress() }, - ]) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: 0n, - reward: vaultReward, - }), - } - await expect( - vault - .connect(other) - .updateStateAndDeposit(other.address, referrer, harvestParams, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to not whitelisted user', async () => { - await expect( - vault.connect(other).deposit(other.address, referrer, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by whitelisted user', async () => { - const receipt = await vault - .connect(sender) - .deposit(sender.address, referrer, { value: amount }) - expect(await vault.balanceOf(sender.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, amount, amount, referrer) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback cannot be called by not whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = ethers.parseEther('100') - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - await vault.connect(admin).updateWhitelist(await depositorMock.getAddress(), true) - - const amount = ethers.parseEther('100') - const expectedShares = ethers.parseEther('100') - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.balanceOf(await depositorMock.getAddress())).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs( - await depositorMock.getAddress(), - await depositorMock.getAddress(), - amount, - expectedShares, - ZERO_ADDRESS - ) - await snapshotGasCost(receipt) - }) - }) - - describe('transfer', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(await admin.getAddress()) - await vault.connect(admin).updateWhitelist(sender.address, true) - await vault.connect(sender).deposit(sender.address, referrer, { value: amount }) - }) - - it('cannot transfer to not whitelisted user', async () => { - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot transfer from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(other.address, true) - await vault.connect(sender).transfer(other.address, amount) - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(other).transfer(sender.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can transfer to whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(other.address, true) - const receipt = await vault.connect(sender).transfer(other.address, amount) - expect(await vault.balanceOf(sender.address)).to.eq(0) - expect(await vault.balanceOf(other.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, other.address, amount) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(await admin.getAddress()) - await vault.connect(admin).updateWhitelist(sender.address, true) - await vault.connect(admin).updateWhitelist(await admin.getAddress(), true) - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(sender).deposit(sender.address, referrer, { value: assets }) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from whitelisted user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/EthPrivErc20Vault.t.sol b/test/EthPrivErc20Vault.t.sol new file mode 100644 index 00000000..de082269 --- /dev/null +++ b/test/EthPrivErc20Vault.t.sol @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; +import {EthPrivErc20Vault} from '../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; + +contract EthPrivErc20VaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthPrivErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + whitelister = makeAddr('whitelister'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthPrivErc20Vault, admin, initParams, false); + vault = EthPrivErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('EthPrivErc20Vault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_transfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(other, true); + vm.stopPrank(); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas('EthPrivErc20VaultTest_test_transfer'); + vault.transfer(other, shares); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(sender), 0, 1); + assertEq(vault.balanceOf(other), shares); + } + + function test_cannotTransferToNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not other + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Try to transfer to non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist other but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(other, true); + + // First whitelist sender temporarily to deposit + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to transfer from non-whitelisted user to whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit as non-whitelisted user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user to whitelisted receiver + _startSnapshotGas('EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser'); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(receiver), expectedShares, 1); + } + + function test_cannotDepositUsingReceiveAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit using receive() function as non-whitelisted user + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + (bool success, ) = address(vault).call{value: amount}(''); + require(success, 'Transfer failed'); + } + + function test_canDepositUsingReceiveAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // When depositing via the receive fallback, the vault should emit a Transfer event + // from address(0) to the sender + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Use low-level call to trigger the receive function + _startSnapshotGas('EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser'); + vm.prank(sender); + (bool success, ) = address(vault).call{value: amount}(''); + _stopSnapshotGas(); + + require(success, 'ETH transfer failed'); + + // Verify sender received the correct number of tokens + assertEq(vault.balanceOf(sender), shares, 'Sender should have received tokens'); + } + + function test_cannotUpdateStateAndDepositAsNotWhitelistedUser() public { + _collateralizeEthVault(address(vault)); + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to update state and deposit as non-whitelisted user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_cannotMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and temporarily whitelist sender to deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken as non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_cannotDepositAndMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit and mint osToken as non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.depositAndMintOsToken{value: amount}(other, osTokenShares, referrer); + } + + function test_canDepositAndMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vm.stopPrank(); + + // Deposit and mint osToken as whitelisted user + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(amount / 2); + vm.prank(sender); + _startSnapshotGas('EthPrivErc20VaultTest_test_canDepositAndMintOsTokenAsWhitelistedUser'); + vault.depositAndMintOsToken{value: amount}(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check balances and osToken position + assertApproxEqAbs(vault.balanceOf(sender), shares, 1); + assertEq(vault.osTokenPositions(sender), osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('EthPrivErc20VaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.EthPrivErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); + + assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); + assertEq(privErc20Vault.version(), 5); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.queuedShares(), 0); + assertEq(privErc20Vault.totalShares(), _securityDeposit); + assertEq(privErc20Vault.totalAssets(), _securityDeposit); + assertEq(privErc20Vault.totalExitingAssets(), 0); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.totalSupply(), _securityDeposit); + assertEq(privErc20Vault.symbol(), 'SW-ETH-1'); + assertEq(privErc20Vault.name(), 'SW ETH Vault'); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthPrivErc20Vault, admin, initParams, true); + EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); + + // whitelist sender + vm.prank(privErc20Vault.whitelister()); + privErc20Vault.updateWhitelist(sender, true); + + _depositToVault(address(privErc20Vault), 95 ether, sender, sender); + _registerEthValidator(address(privErc20Vault), 32 ether, true); + + vm.prank(sender); + privErc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privErc20Vault.totalShares(); + uint256 totalAssetsBefore = privErc20Vault.totalAssets(); + uint256 totalExitingAssetsBefore = privErc20Vault.totalExitingAssets(); + uint256 queuedSharesBefore = privErc20Vault.queuedShares(); + uint256 senderBalanceBefore = privErc20Vault.getShares(sender); + + assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); + assertEq(privErc20Vault.version(), 4); + + _startSnapshotGas('EthPrivErc20VaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthPrivErc20Vault, address(privErc20Vault)); + _stopSnapshotGas(); + + assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); + assertEq(privErc20Vault.version(), 5); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.queuedShares(), queuedSharesBefore); + assertEq(privErc20Vault.totalShares(), totalSharesBefore); + assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); + assertEq(privErc20Vault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); + assertEq(privErc20Vault.totalSupply(), totalSharesBefore); + assertEq(privErc20Vault.symbol(), 'SW-ETH-1'); + assertEq(privErc20Vault.name(), 'SW ETH Vault'); + } +} diff --git a/test/EthPrivVault.spec.ts b/test/EthPrivVault.spec.ts deleted file mode 100644 index b634dd80..00000000 --- a/test/EthPrivVault.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthPrivVault, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../typechain-types' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ZERO_ADDRESS } from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { collateralizeEthVault } from './shared/rewards' -import keccak256 from 'keccak256' - -describe('EthPrivVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Signer, other: Wallet - let vault: EthPrivVault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, admin, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthPrivVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('EthPrivVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - admin = await ethers.getImpersonatedSigner(await vault.admin()) - await vault.connect(admin).setWhitelister(await admin.getAddress()) - await vault.connect(admin).updateWhitelist(await admin.getAddress(), true) - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(admin).updateWhitelist(sender.address, true) - await vault.connect(sender).deposit(sender.address, referrer, { value: assets }) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not whitelisted user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/EthPrivVault.t.sol b/test/EthPrivVault.t.sol new file mode 100644 index 00000000..ee901bf1 --- /dev/null +++ b/test/EthPrivVault.t.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {EthPrivVault} from '../contracts/vaults/ethereum/EthPrivVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthPrivVaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthPrivVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + whitelister = makeAddr('whitelister'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.EthPrivVault, admin, initParams, false); + vault = EthPrivVault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('EthPrivVault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_cannotDepositFromNotWhitelistedSender() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist receiver but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(receiver, true); + + // Try to deposit from non-whitelisted user + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user + _startSnapshotGas('EthPrivVaultTest_test_canDepositAsWhitelistedUser'); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_cannotDepositUsingReceiveAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and don't whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit using receive function as non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_canDepositUsingReceiveAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit using receive function as whitelisted user + _startSnapshotGas('EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser'); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(sender), shares, 1); + } + + function test_cannotMintOsTokenFromNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist user for initial deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken from non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_whitelistUpdateDoesNotAffectExistingFunds() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + uint256 initialBalance = vault.getShares(sender); + assertApproxEqAbs(initialBalance, shares, 1); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Verify share balance remains the same + assertEq( + vault.getShares(sender), + initialBalance, + 'Balance should not change when whitelisting is removed' + ); + + // Verify cannot make new deposits but still has existing shares + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(sender, referrer); + vm.stopPrank(); + } + + function test_cannotUpdateStateAndDepositFromNotWhitelistedUser() public { + _collateralizeEthVault(address(vault)); + + // Set whitelister and don't whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to update state and deposit from non-whitelisted user + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_canUpdateStateAndDepositAsWhitelistedUser() public { + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Update state and deposit as whitelisted user + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + vm.prank(sender); + _startSnapshotGas('EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser'); + vault.updateStateAndDeposit{value: amount}(receiver, referrer, harvestParams); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('EthPrivVaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.EthPrivVault, admin, initParams, true); + _stopSnapshotGas(); + EthPrivVault privVault = EthPrivVault(payable(_vault)); + + assertEq(privVault.vaultId(), keccak256('EthPrivVault')); + assertEq(privVault.version(), 5); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), admin); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.queuedShares(), 0); + assertEq(privVault.totalShares(), _securityDeposit); + assertEq(privVault.totalAssets(), _securityDeposit); + assertEq(privVault.totalExitingAssets(), 0); + assertEq(privVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthPrivVault, admin, initParams, true); + EthPrivVault privVault = EthPrivVault(payable(_vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + privVault.setWhitelister(whitelister); + + vm.prank(whitelister); + privVault.updateWhitelist(sender, true); + + // Make a deposit + _depositToVault(address(privVault), 95 ether, sender, sender); + _registerEthValidator(address(privVault), 32 ether, true); + + vm.prank(sender); + privVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privVault.totalShares(); + uint256 totalAssetsBefore = privVault.totalAssets(); + uint256 totalExitingAssetsBefore = privVault.totalExitingAssets(); + uint256 queuedSharesBefore = privVault.queuedShares(); + uint256 senderSharesBefore = privVault.getShares(sender); + bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); + + assertEq(privVault.vaultId(), keccak256('EthPrivVault')); + assertEq(privVault.version(), 4); + + _startSnapshotGas('EthPrivVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthPrivVault, address(privVault)); + _stopSnapshotGas(); + + assertEq(privVault.vaultId(), keccak256('EthPrivVault')); + assertEq(privVault.version(), 5); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), whitelister); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.queuedShares(), queuedSharesBefore); + assertEq(privVault.totalShares(), totalSharesBefore); + assertEq(privVault.totalAssets(), totalAssetsBefore); + assertEq(privVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(privVault.getShares(sender), senderSharesBefore); + assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); + } + + function test_setWhitelister() public { + address newWhitelister = makeAddr('newWhitelister'); + + // Non-admin cannot set whitelister + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setWhitelister(newWhitelister); + + // Admin can set whitelister + vm.prank(admin); + _startSnapshotGas('EthPrivVaultTest_test_setWhitelister'); + vault.setWhitelister(newWhitelister); + _stopSnapshotGas(); + + assertEq(vault.whitelister(), newWhitelister, 'Whitelister not set correctly'); + } + + function test_updateWhitelist() public { + // Set whitelister + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Non-whitelister cannot update whitelist + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateWhitelist(sender, true); + + // Whitelister can update whitelist + vm.prank(whitelister); + _startSnapshotGas('EthPrivVaultTest_test_updateWhitelist'); + vault.updateWhitelist(sender, true); + _stopSnapshotGas(); + + assertTrue(vault.whitelistedAccounts(sender), 'Account not whitelisted correctly'); + + // Whitelister can remove from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + assertFalse(vault.whitelistedAccounts(sender), 'Account not removed from whitelist correctly'); + } + + function test_depositAndMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist users + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit and mint osToken as whitelisted user + vm.prank(sender); + _startSnapshotGas('EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser'); + uint256 osTokenAssets = vault.depositAndMintOsToken{value: amount}( + sender, + type(uint256).max, + referrer + ); + _stopSnapshotGas(); + + // Check osToken position and vault shares + uint128 osTokenShares = vault.osTokenPositions(sender); + assertGt(osTokenShares, 0); + assertGt(osTokenAssets, 0); + assertApproxEqAbs(vault.getShares(sender), shares, 1); + } + + function test_cannotDepositAndMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister without whitelisting sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(receiver, true); + + // Try to deposit and mint osToken as non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.depositAndMintOsToken{value: amount}(receiver, type(uint256).max, referrer); + } +} diff --git a/test/EthRewardSplitter.t.sol b/test/EthRewardSplitter.t.sol index 12fa614e..2e8cad48 100644 --- a/test/EthRewardSplitter.t.sol +++ b/test/EthRewardSplitter.t.sol @@ -1,696 +1,498 @@ // SPDX-License-Identifier: BUSL-1.1 - pragma solidity ^0.8.22; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; -import {IEthVaultFactory} from '../contracts/interfaces/IEthVaultFactory.sol'; +import {Test} from 'forge-std/Test.sol'; +import {EthRewardSplitter} from '../contracts/misc/EthRewardSplitter.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {EthErc20Vault, IEthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IVaultAdmin} from '../contracts/interfaces/IVaultAdmin.sol'; -import {IVaultFee} from '../contracts/interfaces/IVaultFee.sol'; -import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; import {RewardSplitterFactory} from '../contracts/misc/RewardSplitterFactory.sol'; -import {IRewardSplitterFactory} from '../contracts/interfaces/IRewardSplitterFactory.sol'; -import {EthRewardSplitter} from '../contracts/misc/EthRewardSplitter.sol'; -import {RewardSplitter} from '../contracts/misc/RewardSplitter.sol'; import {IRewardSplitter} from '../contracts/interfaces/IRewardSplitter.sol'; +import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; +import {IVaultFee} from '../contracts/interfaces/IVaultFee.sol'; import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {IVaultEthStaking} from '../contracts/interfaces/IVaultEthStaking.sol'; -import {Vm} from '../lib/forge-std/src/Vm.sol'; -import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; -import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; -import {Test} from '../lib/forge-std/src/Test.sol'; import {Errors} from '../contracts/libraries/Errors.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {RewardsTest} from './Rewards.t.sol'; -import {ConstantsTest} from './Constants.t.sol'; -import {MainnetForkTest} from './MainnetFork.t.sol'; - -abstract contract EthRewardSplitterTest is Test, ConstantsTest, RewardsTest, MainnetForkTest { - address public constant user1 = address(0x1); - address public constant user2 = address(0x2); - - address public vault; - address public vaultAdmin; - address public rewardSplitter; - address public rewardSplitterFactory; - uint256 avgRewardPerSecond = 1585489600; - - function setUp() public virtual override(ConstantsTest, MainnetForkTest, RewardsTest) { - MainnetForkTest.setUp(); - ConstantsTest.setUp(); - RewardsTest.setUp(); - - vm.prank(VaultsRegistry(vaultsRegistry).owner()); - VaultsRegistry(vaultsRegistry).addFactory(v2VaultFactory); - - // create V2 vault - IEthVault.EthVaultInitParams memory params = IEthVault.EthVaultInitParams({ - capacity: type(uint256).max, - feePercent: 1000, - metadataIpfsHash: '' - }); - vault = IEthVaultFactory(v2VaultFactory).createVault{value: 1 gwei}(abi.encode(params), false); - - // collateralize vault (imitate validator creation) - _collateralizeVault(vault); - - // set vault admin - vaultAdmin = IVaultAdmin(vault).admin(); - - // create reward splitter and connect to vault - vm.startPrank(vaultAdmin); - address rewardSplitterImpl = address(new EthRewardSplitter()); - rewardSplitterFactory = address(new RewardSplitterFactory(rewardSplitterImpl)); - rewardSplitter = IRewardSplitterFactory(rewardSplitterFactory).createRewardSplitter(vault); - IVaultFee(vault).setFeeRecipient(rewardSplitter); - vm.stopPrank(); - } -} - -contract EthRewardSplitterSetClaimOnBehalfTest is EthRewardSplitterTest { - function test_failsByNotVaultAdmin() public { - vm.prank(user1); - vm.expectRevert(Errors.AccessDenied.selector); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); - } - function test_normal() public { - // enable claim on behalf - vm.prank(vaultAdmin); - vm.expectEmit(rewardSplitter); - emit IRewardSplitter.ClaimOnBehalfUpdated(vaultAdmin, true); +contract EthRewardSplitterTest is Test, EthHelpers { + ForkContracts public contracts; + EthErc20Vault public vault; + EthRewardSplitter public rewardSplitter; + RewardSplitterFactory public splitterFactory; + + address public admin; + address public shareholder1; + address public shareholder2; + address public depositor; + + uint128 public constant SHARE1 = 7000; // 70% + uint128 public constant SHARE2 = 3000; // 30% + uint256 public constant DEPOSIT_AMOUNT = 100 ether; + + function setUp() public { + // Get fork contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + shareholder1 = makeAddr('shareholder1'); + shareholder2 = makeAddr('shareholder2'); + depositor = makeAddr('depositor'); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(depositor, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + name: 'Test Vault', + symbol: 'TVLT', + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(vaultAddr)); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); + // Deploy RewardSplitter implementation + EthRewardSplitter impl = new EthRewardSplitter(); - assertTrue(IRewardSplitter(rewardSplitter).isClaimOnBehalfEnabled()); - - // disable claim on behalf - vm.prank(vaultAdmin); - vm.expectEmit(rewardSplitter); - emit IRewardSplitter.ClaimOnBehalfUpdated(vaultAdmin, false); + // Deploy RewardSplitterFactory + splitterFactory = new RewardSplitterFactory(address(impl)); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(false); + // Create RewardSplitter for the vault + vm.prank(admin); + address splitterAddr = splitterFactory.createRewardSplitter(address(vault)); + rewardSplitter = EthRewardSplitter(payable(splitterAddr)); - assertFalse(IRewardSplitter(rewardSplitter).isClaimOnBehalfEnabled()); - } -} + // Set RewardSplitter as fee recipient + vm.prank(admin); + vault.setFeeRecipient(address(rewardSplitter)); -contract EthRewardSplitterIncreaseSharesTest is EthRewardSplitterTest { - function test_failsWithZeroShares() public { - vm.prank(vaultAdmin); - vm.expectRevert(IRewardSplitter.InvalidAmount.selector); - IRewardSplitter(rewardSplitter).increaseShares(user1, 0); - } + // Configure shares in RewardSplitter + vm.startPrank(admin); + rewardSplitter.increaseShares(shareholder1, SHARE1); + rewardSplitter.increaseShares(shareholder2, SHARE2); + vm.stopPrank(); - function test_failsWithZeroAccount() public { - vm.prank(vaultAdmin); - vm.expectRevert(IRewardSplitter.InvalidAccount.selector); - IRewardSplitter(rewardSplitter).increaseShares(ZERO_ADDRESS, 1); + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); } - function test_failsByNotVaultAdmin() public { - vm.prank(user1); - vm.expectRevert(Errors.AccessDenied.selector); - IRewardSplitter(rewardSplitter).increaseShares(user1, 1); + function test_initialization() public view { + assertEq(rewardSplitter.vault(), address(vault), 'Vault address not set correctly'); + assertEq(rewardSplitter.totalShares(), SHARE1 + SHARE2, 'Total shares not set correctly'); + assertEq( + rewardSplitter.sharesOf(shareholder1), + SHARE1, + 'Shareholder1 shares not set correctly' + ); + assertEq( + rewardSplitter.sharesOf(shareholder2), + SHARE2, + 'Shareholder2 shares not set correctly' + ); } - function test_failsWhenVaultNotHarvested() public { - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, 1); + function test_generateAndDistributeRewards() public { + // Generate rewards by depositing and simulating profit + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - uint256 unlockedMevReward = 0; - skip(REWARDS_DELAY + 1); - _setVaultRewards(vault, 1 ether, unlockedMevReward, avgRewardPerSecond); - - skip(REWARDS_DELAY + 1); - _setVaultRewards(vault, 2 ether, unlockedMevReward, avgRewardPerSecond); - - vm.prank(vaultAdmin); - vm.expectRevert(IRewardSplitter.NotHarvested.selector); - IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, 1); - } + // Get initial vault shares of reward splitter + uint256 initialShares = vault.getShares(address(rewardSplitter)); - function test_doesNotAffectOthersRewards() public { - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, 100); - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); - uint256 totalReward = 1 ether; - uint256 fee = 0.1 ether; - uint256 unlockedMevReward = 0; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); - IVaultState(vault).updateState(harvestParams); - uint256 feeShares = IVaultState(vault).convertToShares(fee); - - assertEq(IVaultFee(vault).feeRecipient(), rewardSplitter); - assertEq(IVaultState(vault).getShares(rewardSplitter), feeShares); - - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, 100); - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), feeShares); - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(vaultAdmin), 0); - } + // Simulate rewards/profit + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), // 1 ETH reward + 0 + ); - function test_vaultAdminCanIncreaseShares() public { - uint128 shares = 100; - - vm.prank(vaultAdmin); - vm.expectEmit(rewardSplitter); - emit IRewardSplitter.SharesIncreased(user1, shares); - - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); - - assertEq(IRewardSplitter(rewardSplitter).sharesOf(user1), shares); - assertEq(IRewardSplitter(rewardSplitter).totalShares(), shares); - } -} + // Update vault state to distribute rewards + vault.updateState(harvestParams); -contract EthRewardSplitterDecreaseSharesTest is EthRewardSplitterTest { - uint128 public constant shares = 100; + // Verify RewardSplitter has received vault shares as rewards + uint256 newShares = vault.getShares(address(rewardSplitter)); + assertGt(newShares, initialShares, 'RewardSplitter should have received vault shares'); - function setUp() public override { - super.setUp(); - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); - } + // Sync rewards in the splitter + rewardSplitter.syncRewards(); - function test_failsWithZeroShares() public { - vm.prank(vaultAdmin); - vm.expectRevert(IRewardSplitter.InvalidAmount.selector); - IRewardSplitter(rewardSplitter).decreaseShares(user1, 0); - } + // Check available rewards + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + assertGt(rewards1, 0, 'Shareholder1 should have rewards'); + assertGt(rewards2, 0, 'Shareholder2 should have rewards'); - function test_failsWithZeroAccount() public { - vm.prank(vaultAdmin); - vm.expectRevert(IRewardSplitter.InvalidAccount.selector); - IRewardSplitter(rewardSplitter).decreaseShares(ZERO_ADDRESS, 1); - } + // Record initial ETH balances + uint256 shareholder1BalanceBefore = shareholder1.balance; - function test_failsByNotVaultAdmin() public { - vm.prank(user1); - vm.expectRevert(Errors.AccessDenied.selector); - IRewardSplitter(rewardSplitter).decreaseShares(user1, 1); - } + // Shareholder1 enters exit queue with their vault shares + vm.prank(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); - function test_failsWithAmountLargerThanBalance() public { - vm.prank(vaultAdmin); - expectRevertWithPanic(PanicCode.ARITHMETIC_UNDER_OR_OVERFLOW); - IRewardSplitter(rewardSplitter).decreaseShares(user1, shares + 1); - } + // Process the exit queue + harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + vault.updateState(harvestParams); - function test_failsWhenVaultNotHarvested() public { - uint256 unlockedMevReward = 0; - skip(REWARDS_DELAY + 1); - _setVaultRewards(vault, 1 ether, unlockedMevReward, avgRewardPerSecond); - - skip(REWARDS_DELAY + 1); - _setVaultRewards(vault, 2 ether, unlockedMevReward, avgRewardPerSecond); + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - vm.prank(vaultAdmin); - vm.expectRevert(IRewardSplitter.NotHarvested.selector); - IRewardSplitter(rewardSplitter).decreaseShares(user1, 1); - } + // Shareholder1 claims exited assets + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - function test_doesNotAffectRewards() public { - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(vaultAdmin, shares); - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); - uint256 totalReward = 1 ether; - uint256 fee = 0.1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 - ); - IVaultState(vault).updateState(harvestParams); - uint256 feeShares = IVaultState(vault).convertToShares(fee); - - assertEq(IVaultFee(vault).feeRecipient(), rewardSplitter); - assertEq(IVaultState(vault).getShares(rewardSplitter), feeShares); - - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).decreaseShares(vaultAdmin, 1); - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), feeShares / 2); - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(vaultAdmin), feeShares / 2); - } + vm.prank(shareholder1); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - function test_vaultAdminCanDecreaseShares() public { - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).decreaseShares(user1, 1); - - uint128 newShares = shares - 1; - assertEq(IRewardSplitter(rewardSplitter).sharesOf(user1), newShares); - assertEq(IRewardSplitter(rewardSplitter).totalShares(), newShares); - } -} + // Verify shareholder1 received ETH rewards + assertGt( + shareholder1.balance - shareholder1BalanceBefore, + 0, + 'Shareholder1 should receive ETH rewards' + ); -contract EthRewardSplitterSyncRewardsTest is Test, EthRewardSplitterTest { - uint128 public constant shares = 100; + // Shareholder2 directly claims tokens without going through exit queue + vm.prank(shareholder2); + address receiver = shareholder2; + rewardSplitter.claimVaultTokens(rewards2, receiver); - function setUp() public override { - super.setUp(); - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + // Verify shareholder2 received vault tokens + assertGt(vault.getShares(receiver), 0, 'Shareholder2 should receive vault tokens directly'); } - function test_NoOpWhenUpToDate() public { - uint256 totalReward = 1 ether; - uint256 unlockedMevReward = 0; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); - IVaultState(vault).updateState(harvestParams); - - bool canSyncRewards; - canSyncRewards = IRewardSplitter(rewardSplitter).canSyncRewards(); - assertTrue(canSyncRewards); - IRewardSplitter(rewardSplitter).syncRewards(); - - canSyncRewards = IRewardSplitter(rewardSplitter).canSyncRewards(); - assertFalse(canSyncRewards); - - vm.recordLogs(); - IRewardSplitter(rewardSplitter).syncRewards(); - - // check that RewardsSynced event was not emitted - Vm.Log[] memory logs = vm.getRecordedLogs(); - assertEq(logs.length, 0); - } + function test_maxWithdrawal() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - function test_noOpWithZeroTotalShares() public { - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).decreaseShares(user1, shares); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), + 0 + ); - uint256 totalReward = 1 ether; - uint256 unlockedMevReward = 0; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); - IVaultState(vault).updateState(harvestParams); + vault.updateState(harvestParams); + rewardSplitter.syncRewards(); - bool canSyncRewards = IRewardSplitter(rewardSplitter).canSyncRewards(); - assertFalse(canSyncRewards); + // Get total rewards available + uint256 totalRewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(totalRewards, 0, 'Should have rewards to withdraw'); - vm.recordLogs(); - IRewardSplitter(rewardSplitter).syncRewards(); + // Withdraw using max value (should withdraw all available rewards) + vm.prank(shareholder1); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); + rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); - // check that RewardsSynced event was not emitted - Vm.Log[] memory logs = vm.getRecordedLogs(); - assertEq(logs.length, 0); + // Check rewards were fully claimed + assertEq(rewardSplitter.rewardsOf(shareholder1), 0, 'All rewards should be withdrawn'); } - function test_anyoneCanSyncRewards() public { - vm.prank(vaultAdmin); - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); - uint256 totalReward = 1 ether; - uint256 fee = 0.1 ether; - uint256 unlockedMevReward = 0; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), unlockedMevReward, 0); - IVaultState(vault).updateState(harvestParams); - uint256 feeShares = IVaultState(vault).convertToShares(fee); - - assertTrue(IRewardSplitter(rewardSplitter).canSyncRewards()); - - vm.expectEmit(rewardSplitter); - emit IRewardSplitter.RewardsSynced(feeShares, feeShares * 1 ether / shares); - IRewardSplitter(rewardSplitter).syncRewards(); - } -} + function test_notHarvestedInSyncRewards() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); -contract EthRewardSplitterClaimVaultTokensTest is EthRewardSplitterTest { - uint128 public constant shares = 100; - uint256 rewards; - address erc20Vault; - address erc20VaultAdmin; - - function setUp() public override { - super.setUp(); - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); - - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), 0, 0); - IVaultState(vault).updateState(harvestParams); - - IRewardSplitter(rewardSplitter).syncRewards(); - rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); - - IEthErc20Vault.EthErc20VaultInitParams memory params = IEthErc20Vault.EthErc20VaultInitParams({ - capacity: type(uint256).max, - feePercent: 1000, - metadataIpfsHash: '', - name: 'SW ETH Vault', - symbol: 'SW-ETH-1' - }); - erc20Vault = IEthVaultFactory(erc20VaultFactory).createVault{value: SECURITY_DEPOSIT}(abi.encode(params), true); - - // collateralize vault (imitate validator creation) - _collateralizeVault(erc20Vault); - - // Remember erc20 vault admin - erc20VaultAdmin = IVaultAdmin(erc20Vault).admin(); - } + // Force vault to need harvesting without actually harvesting + // First set a reward to make it need harvesting + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + // Mock the isStateUpdateRequired to return true + vm.mockCall( + address(vault), + abi.encodeWithSelector(IVaultState.isStateUpdateRequired.selector), + abi.encode(true) + ); - function test_revertsForNotErc20Vault() public { - vm.expectRevert(); - IRewardSplitter(rewardSplitter).claimVaultTokens(rewards, user1); + // Attempt to sync rewards when vault needs harvesting + vm.expectRevert(IRewardSplitter.NotHarvested.selector); + rewardSplitter.syncRewards(); } - function test_canClaimForErc20Vault() public { - // create reward splitter and connect to erc20 vault - vm.startPrank(erc20VaultAdmin); - rewardSplitter = IRewardSplitterFactory(rewardSplitterFactory).createRewardSplitter(erc20Vault); - IVaultFee(erc20Vault).setFeeRecipient(rewardSplitter); - vm.stopPrank(); + function test_exitRequestNotProcessedInClaimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + rewardSplitter.setClaimOnBehalf(true); - // increase shares - vm.prank(erc20VaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - // harvest vault rewards - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - erc20Vault, SafeCast.toInt256(totalReward), 0, 0 + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), + 0 ); - IVaultState(erc20Vault).updateState(harvestParams); - // sync rewards to splitter - IRewardSplitter(rewardSplitter).syncRewards(); - rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + vault.updateState(harvestParams); + rewardSplitter.syncRewards(); - // claim vault tokens - vm.prank(user1); - vm.expectEmit(rewardSplitter); - emit IRewardSplitter.RewardsWithdrawn(user1, rewards); - IRewardSplitter(rewardSplitter).claimVaultTokens(rewards, user1); + // Enter exit queue on behalf of shareholder1 + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(admin); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - // check no rewards left - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); - - // second claim should fail - vm.prank(user1); - expectRevertWithPanic(PanicCode.ARITHMETIC_UNDER_OR_OVERFLOW); - IRewardSplitter(rewardSplitter).claimVaultTokens(rewards, user1); - } -} + // Try to claim without waiting for the delay period + // (Exit request is not yet processed) + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); -contract EthRewardSplitterEnterExitQueueTest is EthRewardSplitterTest { - uint128 public constant shares = 100; - uint256 rewards; - - function setUp() public override { - super.setUp(); - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); - - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, SafeCast.toInt256(totalReward), 0, 0); - IVaultState(vault).updateState(harvestParams); - - IRewardSplitter(rewardSplitter).syncRewards(); - rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); + vm.prank(admin); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); } - function test_enterExitQueueWithMulticall() public { - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user1, ZERO_ADDRESS); - - // harvest vault rewards - uint256 totalReward = 2 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 - ); - - // harvest vault rewards one more time - totalReward = 3 ether; - skip(REWARDS_DELAY + 1); - harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 - ); - - // Prepare updateVaultState call - bytes memory updateStateCall = abi.encodeWithSignature( - "updateVaultState((bytes32,int160,uint160,bytes32[]))", - harvestParams - ); + function test_accessDeniedInEnterExitQueueOnBehalf() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - // Call enterExitQueue prepended with updateStateCall - vm.prank(user1); - bytes[] memory enterExitQueueCalls = new bytes[](2); - enterExitQueueCalls[0] = updateStateCall; - enterExitQueueCalls[1] = abi.encodeWithSignature( - "enterExitQueue(uint256,address)", type(uint256).max, user1 + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), + 0 ); - IRewardSplitter(rewardSplitter).multicall(enterExitQueueCalls); - // check updateState call succeeded - assertFalse(IVaultState(vault).isStateUpdateRequired()); + vault.updateState(harvestParams); + rewardSplitter.syncRewards(); - // check splitter rewards are synced - assertFalse(IRewardSplitter(rewardSplitter).canSyncRewards()); + // Claim on behalf is disabled by default + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - // check all user rewards are withdrawn - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); + // Should fail with AccessDenied since claim-on-behalf is disabled + vm.prank(admin); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); } -} - -contract EthRewardSplitterEnterExitQueueOnBehalfTest is EthRewardSplitterTest { - uint128 public constant shares = 100; - uint256 rewards; - function setUp() public override { - super.setUp(); + function test_claimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); + rewardSplitter.setClaimOnBehalf(true); - // add shareholder - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - // deposit vault - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user2, ZERO_ADDRESS); - - // set vault rewards - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), + 0 ); - IVaultState(vault).updateState(harvestParams); - - // set shareholder rewards - IRewardSplitter(rewardSplitter).syncRewards(); - rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); - - // enable claim on behalf - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); - } - function test_failsIfClaimOnBehalfDisabled() public { - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(false); + vault.updateState(harvestParams); - vm.expectRevert(Errors.AccessDenied.selector); - IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); - } + // Sync rewards + rewardSplitter.syncRewards(); - function test_withdrawFixedRewards() public { - // check onBehalf and rewards, do not check positionTicket - vm.expectEmit(true, false, true, false); - emit IRewardSplitter.ExitQueueEnteredOnBehalf(user1, 0, rewards); + // Check available rewards + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(rewards, 0, 'Shareholder should have rewards'); - // enter exit queue on behalf - IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); + // Someone else enters exit queue on behalf of shareholder1 + vm.prank(admin); + uint256 timestamp = vm.getBlockTimestamp(); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - // check splitter rewards are synced - assertFalse(IRewardSplitter(rewardSplitter).canSyncRewards()); + // Verify position is tracked correctly + assertEq( + rewardSplitter.exitPositions(positionTicket), + shareholder1, + 'Exit position should be tracked' + ); - // check all user rewards are withdrawn - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); - } + // Process the exit queue + harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Someone else claims on behalf of shareholder1 + uint256 shareholder1BalanceBefore = shareholder1.balance; + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + + // Expected reward amount to be claimed + (, , uint256 exitedAssets) = vault.calculateExitedAssets( + address(rewardSplitter), + positionTicket, + timestamp, + uint256(exitQueueIndex) + ); + + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); - function test_withdrawAllRewards() public { - // set vault rewards - uint256 totalReward = 2 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 + // Verify shareholder1 received rewards + assertGt( + shareholder1.balance - shareholder1BalanceBefore, + 0, + 'Shareholder should receive claimed rewards' ); - IVaultState(vault).updateState(harvestParams); + } - // check onBehalf, do not check positionTicket and rewards - vm.expectEmit(true, false, false, false); - emit IRewardSplitter.ExitQueueEnteredOnBehalf(user1, 0, 0); + function test_syncRewards() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - // enter exit queue on behalf - IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(type(uint256).max, user1); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), + 0 + ); - // check splitter rewards are synced - assertFalse(IRewardSplitter(rewardSplitter).canSyncRewards()); + vault.updateState(harvestParams); - // check all user rewards are withdrawn - assertEq(IRewardSplitter(rewardSplitter).rewardsOf(user1), 0); - } -} + // Initial state before sync + uint256 initialTotalRewards = rewardSplitter.totalRewards(); + // Should be able to sync rewards + assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards'); -contract EthRewardSplitterClaimExitedAssetsOnBehalfTest is EthRewardSplitterTest { - uint128 public constant shares = 100; - uint256 rewards; - uint256 positionTicket; - uint256 timestamp; + // Sync rewards with event check + vm.expectEmit(false, false, false, false); // We don't know exact values + emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values + rewardSplitter.syncRewards(); - function setUp() public override { - super.setUp(); + // Verify rewards were synced + uint256 newTotalRewards = rewardSplitter.totalRewards(); + assertGt(newTotalRewards, initialTotalRewards, 'Total rewards should increase after sync'); - // add shareholder - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + // Verify each shareholder has rewards + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); - // deposit vault - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user2, ZERO_ADDRESS); + assertGt(rewards1, 0, 'Shareholder1 should have rewards after sync'); + assertGt(rewards2, 0, 'Shareholder2 should have rewards after sync'); - // set vault rewards - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 + // Verify proportional distribution + assertApproxEqRel( + rewards1, + (newTotalRewards * SHARE1) / (SHARE1 + SHARE2), + 0.0001e18, // 0.01% tolerance + 'Shareholder1 rewards should be proportional to shares' ); - IVaultState(vault).updateState(harvestParams); - - // set shareholder rewards - IRewardSplitter(rewardSplitter).syncRewards(); - rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); - - // enable claim on behalf - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); - - // enter exit queue on behalf - positionTicket = IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); - timestamp = block.timestamp; - } - function test_failsIfInvalidPosition() public { - positionTicket++; - int256 exitQueueIndex = IEthVault(vault).getExitQueueIndex(positionTicket); - - vm.expectRevert(Errors.InvalidPosition.selector); - - // claim exited assets on behalf - IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( - positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + assertApproxEqRel( + rewards2, + (newTotalRewards * SHARE2) / (SHARE1 + SHARE2), + 0.0001e18, // 0.01% tolerance + 'Shareholder2 rewards should be proportional to shares' ); } - function test_basic() public { - skip(exitingAssetsClaimDelay + 1); - - uint256 balanceBeforeClaim = user1.balance; - - // check onBehalf, positionTicket, do not check amount - vm.expectEmit(true, true, false, false); - emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(user1, positionTicket, 0); + function test_manageShares() public { + // Test increase shares with event + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesIncreased(shareholder1, 1000); + rewardSplitter.increaseShares(shareholder1, 1000); - // claim exited assets on behalf - int256 exitQueueIndex = IEthVault(vault).getExitQueueIndex(positionTicket); - IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( - positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) + assertEq( + rewardSplitter.sharesOf(shareholder1), + SHARE1 + 1000, + 'Shares should increase by 1000' ); - // Take 1 ether vault reward, apply 10% vault fee - uint256 exitedAssets = 0.1 ether; + // Test decrease shares with event + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesDecreased(shareholder1, 1000); + rewardSplitter.decreaseShares(shareholder1, 1000); - // check user balance change, leave 1 wei for rounding error - assertApproxEqAbs(user1.balance - balanceBeforeClaim, exitedAssets, 1 wei); - - // check repeating call fails - vm.expectRevert(Errors.InvalidPosition.selector); - IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( - positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) - ); + assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1, 'Shares should decrease by 1000'); } -} + function test_updateVaultState() public { + // Generate rewards with a callback from reward splitter + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), + 0 + ); -contract EthRewardSplitterClaimExitedAssetsOnBehalfMultipleUsersTest is EthRewardSplitterTest { - uint128 public constant shares = 100; - uint256 rewards; - uint256 timestamp; + // Update vault state through reward splitter + rewardSplitter.updateVaultState(harvestParams); - function setUp() public override { - super.setUp(); + // Verify rewards can be sync'd + assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards after update'); - // add shareholder - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); + // Sync and verify rewards + rewardSplitter.syncRewards(); + uint256 totalRewards = rewardSplitter.totalRewards(); + assertGt(totalRewards, 0, 'Total rewards should be greater than zero'); + } - // assign 10% of shares to user1 and 90% to user2 - IRewardSplitter(rewardSplitter).increaseShares(user2, 9 * shares); + function test_receiveEth() public { + // Send ETH directly to RewardSplitter + uint256 amount = 1 ether; + uint256 initialBalance = address(rewardSplitter).balance; - // deposit vault - IVaultEthStaking(vault).deposit{value: 10 ether - SECURITY_DEPOSIT}(user2, ZERO_ADDRESS); + // Send ETH + (bool success, ) = address(rewardSplitter).call{value: amount}(''); + assertTrue(success, 'ETH transfer should succeed'); - // set vault rewards - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 + // Verify balance increased + assertEq( + address(rewardSplitter).balance, + initialBalance + amount, + 'RewardSplitter balance should increase' ); - IVaultState(vault).updateState(harvestParams); - - // enable claim on behalf - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); } - function test_multipleShareholder() public { - uint256 splitterBalanceBeforeClaim = rewardSplitter.balance; - - // Take 1 ether vault reward, apply 10% vault fee - // got 0.1 ether - // 10% to user1, 90% to user2 - uint256 exitedAssets1 = 0.01 ether; - uint256 exitedAssets2 = 0.09 ether; - - // Each exit-claim combination adds up rounding error 1 wei - uint256 maxError1 = 1 wei; - uint256 maxError2 = 2 wei; + function test_accessControl() public { + // Non-admin tries to increase shares + vm.prank(shareholder1); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.increaseShares(shareholder1, 1000); - _claimExitedAssetsOnBehalf(user1, exitedAssets1, maxError1); - _claimExitedAssetsOnBehalf(user2, exitedAssets2, maxError2); + // Non-admin tries to decrease shares + vm.prank(shareholder1); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.decreaseShares(shareholder1, 1000); - // check unclaimed rewards on splitter balance - assertEq(rewardSplitter.balance - splitterBalanceBeforeClaim, 0); + // Non-admin tries to set claim on behalf + vm.prank(shareholder1); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.setClaimOnBehalf(true); } - function _claimExitedAssetsOnBehalf( - address user, uint256 exitedAssets, uint256 maxError - ) internal { - // set balances before claim - uint256 userBalanceBeforeClaim = user.balance; + function test_invalidAccountInDecreaseShares() public { + // Try to decrease shares for the zero address + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAccount.selector); + rewardSplitter.decreaseShares(address(0), 1000); - // enter exit queue on behalf - uint256 positionTicket = IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf( - type(uint256).max, user - ); - timestamp = block.timestamp; + // Also test non-zero but invalid account (one that has no shares) + address randomAccount = makeAddr('randomAccount'); + vm.prank(admin); + vm.expectRevert(); // This will revert when trying to decrease below zero, but the error type may vary + rewardSplitter.decreaseShares(randomAccount, 1000); + } - skip(exitingAssetsClaimDelay + 1); + function test_invalidParameters() public { + // Try to increase shares with invalid amount + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAmount.selector); + rewardSplitter.increaseShares(shareholder1, 0); - // check onBehalf, positionTicket, do not check amount - vm.expectEmit(true, true, false, false); - emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(user, positionTicket, 0); + // Try to increase shares with invalid account + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAccount.selector); + rewardSplitter.increaseShares(address(0), 1000); - // claim exited assets on behalf - int256 exitQueueIndex = IEthVault(vault).getExitQueueIndex(positionTicket); - IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( - positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) - ); - - // check user balance change, allow rounding error - assertApproxEqAbs(user.balance - userBalanceBeforeClaim, exitedAssets, maxError); + // Try to decrease shares with invalid amount + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAmount.selector); + rewardSplitter.decreaseShares(shareholder1, 0); } } diff --git a/test/EthValidatorsChecker.t.sol b/test/EthValidatorsChecker.t.sol new file mode 100644 index 00000000..5cac4900 --- /dev/null +++ b/test/EthValidatorsChecker.t.sol @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {EthValidatorsChecker} from '../contracts/validators/EthValidatorsChecker.sol'; +import {IValidatorsChecker} from '../contracts/interfaces/IValidatorsChecker.sol'; +import {IDepositDataRegistry} from '../contracts/interfaces/IDepositDataRegistry.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +interface IVaultValidatorsV1 { + function validatorsRoot() external view returns (bytes32); + function validatorIndex() external view returns (uint256); + function keysManager() external view returns (address); + function setValidatorsRoot(bytes32 root) external; +} + +contract EthValidatorsCheckerTest is Test, EthHelpers { + // Test contracts + ForkContracts public contracts; + EthValidatorsChecker public validatorsChecker; + address public vault; + address public emptyVault; + address public admin; + address public user; + bytes32 public validRegistryRoot; + + function setUp() public { + // Setup fork and contracts + contracts = _activateEthereumFork(); + + // Deploy a fresh EthValidatorsChecker + validatorsChecker = new EthValidatorsChecker( + address(contracts.validatorsRegistry), + address(contracts.keeper), + address(contracts.vaultsRegistry), + address(_depositDataRegistry) + ); + + // Setup accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + vm.deal(user, 100 ether); + + // Create and prepare a vault with sufficient funds + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + vault = _createVault(VaultType.EthVault, admin, initParams, false); + _depositToVault(vault, 33 ether, user, vault); // Deposit enough for 1 validator + _collateralizeEthVault(address(vault)); + + // Create another vault without sufficient funds + emptyVault = _createVault(VaultType.EthVault, admin, initParams, false); + + // Get valid registry root + validRegistryRoot = contracts.validatorsRegistry.get_deposit_root(); + } + + // Tests for checkValidatorsManagerSignature + + function testValidatorsManagerSignature_InvalidRegistryRoot() public view { + // Create invalid root + bytes32 invalidRoot = bytes32(uint256(validRegistryRoot) + 1); + + // Test with invalid root + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkValidatorsManagerSignature(vault, invalidRoot, '', ''); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_REGISTRY_ROOT)); + assertEq(blockNumber, block.number); + } + + function testValidatorsManagerSignature_InvalidVault() public { + // Use non-existent vault + address invalidVault = makeAddr('nonVault'); + + // Test with invalid vault + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkValidatorsManagerSignature(invalidVault, validRegistryRoot, '', ''); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VAULT)); + assertEq(blockNumber, block.number); + } + + function testValidatorsManagerSignature_InsufficientAssets() public view { + // Test with empty vault + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkValidatorsManagerSignature(emptyVault, validRegistryRoot, '', ''); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INSUFFICIENT_ASSETS)); + assertEq(blockNumber, block.number); + } + + function testValidatorsManagerSignature_InvalidSignature() public view { + // Get valid registry root + bytes32 validRoot = contracts.validatorsRegistry.get_deposit_root(); + + // Generate validator data + bytes memory validatorData = new bytes(184); // Valid length for one validator + + // Generate invalid signature + bytes memory invalidSignature = '0xdeadbeef'; + + // Check with invalid signature + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkValidatorsManagerSignature(vault, validRoot, validatorData, invalidSignature); + + // Verify expected result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_SIGNATURE)); + assertEq(blockNumber, block.number); + } + + // Tests for checkDepositDataRoot + + function testCheckDepositDataRoot_InvalidRegistryRoot() public view { + // Create invalid root + bytes32 invalidRoot = bytes32(uint256(validRegistryRoot) + 1); + + // Create params with invalid root + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: invalidRoot, + validators: '', + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test with invalid root + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_REGISTRY_ROOT)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidVault() public { + // Use non-existent vault + address invalidVault = makeAddr('nonVault'); + + // Create params with invalid vault + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: invalidVault, + validatorsRegistryRoot: validRegistryRoot, + validators: '', + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test with invalid vault + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VAULT)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InsufficientAssets() public view { + // Create params with empty vault + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: emptyVault, + validatorsRegistryRoot: validRegistryRoot, + validators: '', + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test with empty vault + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INSUFFICIENT_ASSETS)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidValidatorsCount() public view { + // Create valid validator data + bytes memory validators = new bytes(184); // Valid length for one validator + + // Create params with empty proof indexes + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: validRegistryRoot, + validators: validators, + proof: new bytes32[](1), + proofFlags: new bool[](1), + proofIndexes: new uint256[](0) // Empty proof indexes + }); + + // Test with empty proof indexes + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_COUNT)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidValidatorsLength() public view { + // Create params with invalid validator length + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: validRegistryRoot, + validators: '', + proof: new bytes32[](1), + proofFlags: new bool[](1), + proofIndexes: new uint256[](1) + }); + + // Test with invalid validator length + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_LENGTH)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_ValidatorsManager() public { + // Create a vault with a custom validators manager + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address customVault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + _depositToVault(customVault, 33 ether, user, customVault); + _collateralizeEthVault(address(customVault)); + + // Set a custom validators manager + address customManager = makeAddr('customManager'); + vm.prank(admin); + IVaultValidators(customVault).setValidatorsManager(customManager); + + // Create params + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: customVault, + validatorsRegistryRoot: validRegistryRoot, + validators: '', + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_MANAGER)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidProof() public { + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address v1Vault = _createV1EthVault(admin, initParams, false); + _depositToVault(v1Vault, 33 ether, user, user); + + // We need to be very precise with the validator data structure + // V2 validator has length of 184 bytes (48 + 96 + 32 + 8) + uint256 validatorLength = 184; + + // We'll create data for exactly one validator + bytes memory validators = new bytes(validatorLength); + for (uint i = 0; i < validators.length; i++) { + validators[i] = 0x01; // Non-zero values + } + + // Set deposit data root for the vault + bytes32 fakeRoot = keccak256('fake_root'); + vm.prank(IVaultValidatorsV1(v1Vault).keysManager()); + IVaultValidatorsV1(v1Vault).setValidatorsRoot(fakeRoot); + + // Create a valid-looking proof structure + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); // Invalid proof data + + // We need exactly one proof index to match our one validator + uint256[] memory proofIndexes = new uint256[](1); + proofIndexes[0] = 0; // First validator + + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + // Create params with configurations that should reach proof validation + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: v1Vault, + validatorsRegistryRoot: validRegistryRoot, + validators: validators, + proof: proof, + proofFlags: proofFlags, + proofIndexes: proofIndexes + }); + + // Test with invalid proof + vm.expectRevert(abi.encodeWithSignature('MerkleProofInvalidMultiproof()')); + validatorsChecker.checkDepositDataRoot(params); + } + + // Test for V1 vault backward compatibility + function testDepositDataRoot_OldVaultFormat() public { + // Create a vault with previous version (for testing backwards compatibility) + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + // Create a V1 vault or mock one + address v1Vault = _createPrevVersionVault(VaultType.EthVault, admin, initParams, false); + _depositToVault(v1Vault, 33 ether, user, v1Vault); + _collateralizeEthVault(address(v1Vault)); + + // Create basic params for V1 vault + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: v1Vault, + validatorsRegistryRoot: validRegistryRoot, + validators: new bytes(184), // Valid length + proof: new bytes32[](1), + proofFlags: new bool[](1), + proofIndexes: new uint256[](1) + }); + + // Test with V1 vault format + (uint256 blockNumber, ) = validatorsChecker.checkDepositDataRoot(params); + + // We expect specific errors based on behavior with V1 vaults + // The actual expected status will depend on the implementation details + // This test mainly ensures the function doesn't revert unexpectedly + assertEq(blockNumber, block.number); + } + + function test_checkValidatorsManagerSignature_Success() public { + // 1. Get the validators manager + address validatorsManager = makeAddr('validatorsManager'); + uint256 validatorsManagerPrivKey = uint256( + keccak256(abi.encodePacked('validatorsManager_key')) + ); + validatorsManager = vm.addr(validatorsManagerPrivKey); + + // 2. Set the validators manager on the vault + vm.prank(admin); + IVaultValidators(vault).setValidatorsManager(validatorsManager); + + // 3. Create validator data (48 bytes pubkey + 96 bytes signature + 32 bytes root + 8 bytes amount) + bytes memory validatorData = new bytes(184); + for (uint i = 0; i < validatorData.length; i++) { + validatorData[i] = bytes1(uint8(i % 256)); // Fill with incremental data + } + + // 4. Get the domain separator from the contract + // This matches the domain separator calculation in ValidatorsChecker._computeVaultValidatorsDomain + bytes32 domainSeparator = keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256(bytes('VaultValidators')), + keccak256('1'), + block.chainid, + vault + ) + ); + + // 5. Create the message hash that matches the contract's implementation + bytes32 validatorsManagerTypeHash = keccak256( + 'VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)' + ); + bytes32 messageHash = keccak256( + abi.encode(validatorsManagerTypeHash, validRegistryRoot, keccak256(validatorData)) + ); + + // 6. Create the EIP-712 typed data hash exactly as the contract does + bytes32 typedDataHash = keccak256(abi.encodePacked('\x19\x01', domainSeparator, messageHash)); + + // 7. Sign the message with validators manager's private key + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivKey, typedDataHash); + bytes memory signature = abi.encodePacked(r, s, v); + + // 8. Call checkValidatorsManagerSignature + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkValidatorsManagerSignature(vault, validRegistryRoot, validatorData, signature); + + // 9. Verify success result + assertEq( + uint256(status), + uint256(IValidatorsChecker.Status.SUCCEEDED), + 'Signature verification should succeed' + ); + assertEq(blockNumber, block.number); + } + + function test_checkDepositDataRoot_Success() public { + // 1. Set up the vault with the deposit data registry as the validators manager + vm.prank(admin); + IVaultValidators(vault).setValidatorsManager(_depositDataRegistry); + + // 2. Create valid validator data (48 bytes pubkey + 96 bytes signature + 32 bytes root + 8 bytes amount) + bytes memory validator = new bytes(184); + for (uint i = 0; i < validator.length; i++) { + validator[i] = bytes1(uint8(i % 256)); // Fill with incremental data + } + + // 3. Set up the deposit data root + // For a proper test, we need to create a real Merkle root from the validator data + // We'll create a mock Merkle tree with just one validator + + // First, create the leaf node data that will be used in the Merkle tree + // In the actual contract, this is calculated as: + // keccak256(bytes.concat(keccak256(abi.encode(validators[startIndex:endIndex], currentIndex)))) + uint256 validatorIndex = 0; // Current validator index + bytes32 leafNode = keccak256(bytes.concat(keccak256(abi.encode(validator, validatorIndex)))); + + // For a single validator, the Merkle root is the leaf node itself + bytes32 depositDataRoot = leafNode; + + // 4. Set the deposit data root in the registry + vm.prank(IDepositDataRegistry(_depositDataRegistry).getDepositDataManager(vault)); + IDepositDataRegistry(_depositDataRegistry).setDepositDataRoot(vault, depositDataRoot); + + // 5. Mock the deposit data index + vm.mockCall( + _depositDataRegistry, + abi.encodeWithSelector(bytes4(keccak256('depositDataIndexes(address)'))), + abi.encode(validatorIndex) + ); + + // 6. For a single validator Merkle tree, the proof is empty + // But we need to set up the arrays correctly for the function parameters + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + uint256[] memory proofIndexes = new uint256[](1); + proofIndexes[0] = 0; // First (and only) validator + + // 7. Create the parameters for checkDepositDataRoot + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker + .DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: validRegistryRoot, + validators: validator, + proof: proof, + proofFlags: proofFlags, + proofIndexes: proofIndexes + }); + + // 8. Call checkDepositDataRoot + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker + .checkDepositDataRoot(params); + + // 9. Verify success result + assertEq( + uint256(status), + uint256(IValidatorsChecker.Status.SUCCEEDED), + 'Deposit data root verification should succeed' + ); + assertEq(blockNumber, block.number); + } +} diff --git a/test/EthVault.t.sol b/test/EthVault.t.sol new file mode 100644 index 00000000..f57ee489 --- /dev/null +++ b/test/EthVault.t.sol @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract EthVaultTest is Test, EthHelpers { + ForkContracts public contracts; + EthVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + uint256 public exitingAssets; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + referrer = makeAddr('referrer'); + validatorsManager = makeAddr('validatorsManager'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(validatorsManager, 1 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Set validatorsManager for the vault + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + exitingAssets = + vault.totalExitingAssets() + + vault.convertToAssets(vault.queuedShares()) + + vaultAddr.balance; + } + + function test_cannotInitializeTwice() public { + // Try to initialize the vault again, which should fail + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_deploysCorrectly() public { + // Create a new vault to test deployment + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('EthVaultTest_test_deploysCorrectly'); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + _stopSnapshotGas(); + + EthVault newVault = EthVault(payable(vaultAddr)); + + // Verify the vault was deployed correctly + assertEq(newVault.vaultId(), keccak256('EthVault')); + assertEq(newVault.version(), 5); + assertEq(newVault.admin(), admin); + assertEq(newVault.capacity(), 1000 ether); + assertEq(newVault.feePercent(), 1000); + assertEq(newVault.feeRecipient(), admin); + assertEq(newVault.validatorsManager(), _depositDataRegistry); + assertEq(newVault.queuedShares(), 0); + assertEq(newVault.totalShares(), _securityDeposit); + assertEq(newVault.totalAssets(), _securityDeposit); + assertEq(newVault.totalExitingAssets(), 0); + assertEq(newVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // Create a v4 vault (previous version) + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createPrevVersionVault(VaultType.EthVault, admin, initParams, false); + EthVault prevVault = EthVault(payable(vaultAddr)); + + // Deposit some ETH + _depositToVault(address(prevVault), exitingAssets + 32 ether, sender, sender); + + // Register a validator + _registerEthValidator(address(prevVault), 32 ether, true); + + // Enter exit queue with some shares + vm.prank(sender); + prevVault.enterExitQueue(10 ether, sender); + + // Record state before upgrade + uint256 totalSharesBefore = prevVault.totalShares(); + uint256 totalAssetsBefore = prevVault.totalAssets(); + uint256 totalExitingAssetsBefore = prevVault.totalExitingAssets(); + uint256 queuedSharesBefore = prevVault.queuedShares(); + uint256 senderBalanceBefore = prevVault.getShares(sender); + + // Verify current version + assertEq(prevVault.vaultId(), keccak256('EthVault')); + assertEq(prevVault.version(), 4); + + // Upgrade the vault + _startSnapshotGas('EthVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.EthVault, address(prevVault)); + _stopSnapshotGas(); + + // Check that the vault was upgraded correctly + assertEq(prevVault.vaultId(), keccak256('EthVault')); + assertEq(prevVault.version(), 5); + assertEq(prevVault.admin(), admin); + assertEq(prevVault.capacity(), 1000 ether); + assertEq(prevVault.feePercent(), 1000); + assertEq(prevVault.feeRecipient(), admin); + assertEq(prevVault.validatorsManager(), _depositDataRegistry); + + // State should be preserved + assertEq(prevVault.queuedShares(), queuedSharesBefore); + assertEq(prevVault.totalShares(), totalSharesBefore); + assertEq(prevVault.totalAssets(), totalAssetsBefore); + assertEq(prevVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(prevVault.validatorsManagerNonce(), 0); + assertEq(prevVault.getShares(sender), senderBalanceBefore); + } + + function test_exitQueue_works() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Deposit ETH into the vault + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, sender, sender); + + // Get initial state + uint256 senderSharesBefore = vault.getShares(sender); + uint256 queuedSharesBefore = vault.queuedShares(); + + // Amount to exit with + uint256 exitAmount = senderSharesBefore / 2; + + // Enter exit queue + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(sender); + _startSnapshotGas('EthVaultTest_test_exitQueue_works'); + uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); + _stopSnapshotGas(); + + // Check state after entering exit queue + assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, 'Sender shares not reduced'); + assertEq(vault.queuedShares(), queuedSharesBefore + exitAmount, 'Queued shares not increased'); + + // Process exit queue by updating state + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Check that position can be found in exit queue + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Wait for the claiming delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Verify exited assets can be calculated + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault + .calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // Assets should be exited and claimable + assertApproxEqAbs(leftTickets, 0, 1, 'All tickets should be processed'); + assertGt(exitedTickets, 0, 'No tickets exited'); + assertGt(exitedAssets, 0, 'No assets exited'); + + // Claim exited assets + uint256 receiverBalanceBefore = receiver.balance; + + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify receiver got their ETH + uint256 receiverBalanceAfter = receiver.balance; + assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver didn't get ETH"); + assertEq( + receiverBalanceAfter, + receiverBalanceBefore + exitedAssets, + 'Incorrect amount received' + ); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('EthVault'); + assertEq(vault.vaultId(), expectedId, 'Invalid vault ID'); + } + + function test_vaultVersion() public view { + assertEq(vault.version(), 5, 'Invalid vault version'); + } + + function test_withdrawValidator_validatorsManager() public { + // First deposit and register a validator + _depositToVault(address(vault), 40 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // Execute withdrawal as validatorsManager + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(validatorsManager); + _startSnapshotGas('EthVaultTest_test_withdrawValidator_validatorsManager'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_osTokenRedeemer() public { + // Set osToken redeemer + address osTokenRedeemer = makeAddr('osTokenRedeemer'); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + // Fund the redeemer account + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 40 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // Execute withdrawal as osTokenRedeemer + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(osTokenRedeemer); + _startSnapshotGas('EthVaultTest_test_withdrawValidator_osTokenRedeemer'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_unknown() public { + // Create an unknown address + address unknown = makeAddr('unknown'); + + // Fund the unknown account + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 40 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // Execute withdrawal as an unknown address - should fail + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(unknown); + _startSnapshotGas('EthVaultTest_test_withdrawValidator_unknown'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_depositAndMintOsToken() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Set up parameters + uint256 depositAmount = 10 ether; + uint256 shares = vault.convertToShares(depositAmount); + uint256 osTokenSharesToMint = 5 ether; // Half the deposit + + // Perform depositAndMintOsToken + vm.prank(sender); + _startSnapshotGas('EthVaultTest_test_depositAndMintOsToken'); + uint256 mintedAssets = vault.depositAndMintOsToken{value: depositAmount}( + sender, + osTokenSharesToMint, + referrer + ); + _stopSnapshotGas(); + + // Verify sender got vault shares + assertApproxEqAbs(vault.getShares(sender), shares, 1, 'Incorrect amount of vault shares'); + + // Verify osToken position + uint128 osTokenShares = vault.osTokenPositions(sender); + assertEq(osTokenShares, osTokenSharesToMint, 'Incorrect amount of osToken shares'); + assertGt(mintedAssets, 0, 'No osToken assets minted'); + } + + function test_updateStateAndDepositAndMintOsToken() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Set up parameters + uint256 depositAssets = 10 ether; + uint256 osTokenAssetsToMint = 5 ether; // Half the deposit + + uint256 depositShares = vault.convertToShares(depositAssets); + uint256 osTokenSharesToMint = vault.convertToShares(osTokenAssetsToMint); + + // Set up harvest params + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Perform updateStateAndDepositAndMintOsToken + vm.prank(sender); + _startSnapshotGas('EthVaultTest_test_updateStateAndDepositAndMintOsToken'); + uint256 mintedAssets = vault.updateStateAndDepositAndMintOsToken{value: depositAssets}( + sender, + osTokenSharesToMint, + referrer, + harvestParams + ); + _stopSnapshotGas(); + + // Verify sender got vault shares + assertApproxEqAbs(vault.getShares(sender), depositShares, 1, 'Incorrect amount of vault shares'); + + // Verify osToken position + uint128 osTokenShares = vault.osTokenPositions(sender); + assertEq(osTokenShares, osTokenSharesToMint, 'Incorrect amount of osToken shares'); + assertGt(mintedAssets, 0, 'No osToken assets minted'); + } + + function test_fallbackDeposit() public { + // Test direct ETH transfer to vault + uint256 depositAmount = 5 ether; + uint256 depositShares = vault.convertToShares(depositAmount); + uint256 senderBalanceBefore = vault.getShares(sender); + + vm.prank(sender); + _startSnapshotGas('EthVaultTest_test_fallbackDeposit'); + Address.sendValue(payable(address(vault)), depositAmount); + _stopSnapshotGas(); + + // Verify sender got vault shares + assertApproxEqAbs( + vault.getShares(sender), + senderBalanceBefore + depositShares, + 1, + 'Shares not increased' + ); + } +} diff --git a/test/KeeperOracles.t.sol b/test/KeeperOracles.t.sol new file mode 100644 index 00000000..188ac078 --- /dev/null +++ b/test/KeeperOracles.t.sol @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperOracles} from '../contracts/interfaces/IKeeperOracles.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {Keeper} from '../contracts/keeper/Keeper.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract KeeperOraclesTest is Test, EthHelpers { + // Setup contracts and variables + ForkContracts public contracts; + Keeper public keeper; + + address public owner; + address public newOracle; + address public nonOwner; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + keeper = contracts.keeper; + + // Set up test accounts + owner = keeper.owner(); + newOracle = makeAddr('newOracle'); + nonOwner = makeAddr('nonOwner'); + } + + // Test cases for addOracle + function test_addOracle_success() public { + // Remove oracle first if already added + if (keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.removeOracle(newOracle); + } + + // Initial state check + assertFalse(keeper.isOracle(newOracle), 'Oracle should not be added initially'); + uint256 initialTotalOracles = keeper.totalOracles(); + + // Expect OracleAdded event + vm.expectEmit(true, false, false, false); + emit IKeeperOracles.OracleAdded(newOracle); + + // Add the oracle + vm.prank(owner); + _startSnapshotGas('KeeperOraclesTest_test_addOracle_success'); + keeper.addOracle(newOracle); + _stopSnapshotGas(); + + // Verify oracle was added + assertTrue(keeper.isOracle(newOracle), 'Oracle should be added'); + assertEq(keeper.totalOracles(), initialTotalOracles + 1, 'Total oracles should be incremented'); + } + + function test_addOracle_alreadyAdded() public { + // Add oracle first (or ensure it's added) + if (!keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.addOracle(newOracle); + } + + // Try to add again and expect revert + vm.prank(owner); + _startSnapshotGas('KeeperOraclesTest_test_addOracle_alreadyAdded'); + vm.expectRevert(Errors.AlreadyAdded.selector); + keeper.addOracle(newOracle); + _stopSnapshotGas(); + } + + function test_addOracle_maxOraclesExceeded() public { + // Get the current number of oracles + uint256 currentOracles = keeper.totalOracles(); + uint256 maxOracles = 30; // From the contract + + // Skip test if already at max oracles + if (currentOracles >= maxOracles) { + // In a forked environment, we might already have max oracles + // In that case, we can't properly test the max oracles exceeded error + return; + } + + // Add oracles until we reach the maximum + for (uint256 i = 0; i < maxOracles - currentOracles; i++) { + address oracle = makeAddr(string(abi.encodePacked('oracle', i))); + if (!keeper.isOracle(oracle)) { + vm.prank(owner); + keeper.addOracle(oracle); + } + } + + // Verify we've reached the max + assertEq(keeper.totalOracles(), maxOracles, 'Total oracles should equal max oracles'); + + // Try to add one more and expect revert + vm.prank(owner); + _startSnapshotGas('KeeperOraclesTest_test_addOracle_maxOraclesExceeded'); + vm.expectRevert(Errors.MaxOraclesExceeded.selector); + keeper.addOracle(makeAddr('oneMoreOracle')); + _stopSnapshotGas(); + } + + // Test cases for removeOracle + function test_removeOracle_success() public { + // Add oracle first if not already added + if (!keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.addOracle(newOracle); + } + + // Initial state check + assertTrue(keeper.isOracle(newOracle), 'Oracle should be added initially'); + uint256 initialTotalOracles = keeper.totalOracles(); + + // Expect OracleRemoved event + vm.expectEmit(true, false, false, false); + emit IKeeperOracles.OracleRemoved(newOracle); + + // Remove the oracle + vm.prank(owner); + _startSnapshotGas('KeeperOraclesTest_test_removeOracle_success'); + keeper.removeOracle(newOracle); + _stopSnapshotGas(); + + // Verify oracle was removed + assertFalse(keeper.isOracle(newOracle), 'Oracle should be removed'); + assertEq(keeper.totalOracles(), initialTotalOracles - 1, 'Total oracles should be decremented'); + } + + function test_removeOracle_alreadyRemoved() public { + // Ensure oracle is not added + if (keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.removeOracle(newOracle); + } + + // Try to remove and expect revert + vm.prank(owner); + _startSnapshotGas('KeeperOraclesTest_test_removeOracle_alreadyRemoved'); + vm.expectRevert(Errors.AlreadyRemoved.selector); + keeper.removeOracle(newOracle); + _stopSnapshotGas(); + } + + // Test cases for updateConfig + function test_updateConfig_success() public { + string memory configIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u'; + + // Expect ConfigUpdated event + vm.expectEmit(true, false, false, false); + emit IKeeperOracles.ConfigUpdated(configIpfsHash); + + // Update config + vm.prank(owner); + _startSnapshotGas('KeeperOraclesTest_test_updateConfig_success'); + keeper.updateConfig(configIpfsHash); + _stopSnapshotGas(); + } + + // Test access control + function test_addOracle_onlyOwner() public { + vm.prank(nonOwner); + _startSnapshotGas('KeeperOraclesTest_test_addOracle_onlyOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + keeper.addOracle(newOracle); + _stopSnapshotGas(); + } + + function test_removeOracle_onlyOwner() public { + // Add oracle first if not already added + if (!keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.addOracle(newOracle); + } + + vm.prank(nonOwner); + _startSnapshotGas('KeeperOraclesTest_test_removeOracle_onlyOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + keeper.removeOracle(newOracle); + _stopSnapshotGas(); + } + + function test_updateConfig_onlyOwner() public { + string memory configIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u'; + + vm.prank(nonOwner); + _startSnapshotGas('KeeperOraclesTest_test_updateConfig_onlyOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + keeper.updateConfig(configIpfsHash); + _stopSnapshotGas(); + } + + // Test signature verification through KeeperRewards.updateRewards + function test_verifySignatures_throughKeeperRewards() public { + // Setup oracle for impersonation + _startOracleImpersonate(address(keeper)); + + // Use the _setEthVaultReward helper which generates and verifies signatures + // Use a known valid vault address from the forked environment + address genesisVault = _getForkVault(VaultType.EthGenesisVault); + + // Perform rewards update which uses _verifySignatures internally + _startSnapshotGas('KeeperOraclesTest_test_verifySignatures_throughKeeperRewards'); + _setEthVaultReward(genesisVault, int160(int256(1 ether)), 0); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(keeper)); + } +} diff --git a/test/KeeperRewards.t.sol b/test/KeeperRewards.t.sol new file mode 100644 index 00000000..14bba23d --- /dev/null +++ b/test/KeeperRewards.t.sol @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; +import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; +import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; +import {Keeper} from '../contracts/keeper/Keeper.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; + +contract KeeperRewardsTest is Test, EthHelpers { + // Fork contracts + ForkContracts public contracts; + + // Test vaults and accounts + EthVault public vault; + address public admin; + address public user; + + // Constants for testing + uint256 public depositAmount = 10 ether; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deposit ETH to the vault + _depositToVault(address(vault), depositAmount, user, user); + } + + // Test rewards update functionality + function test_updateRewards() public { + // Arrange: Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Get current nonce before update + uint64 initialNonce = contracts.keeper.rewardsNonce(); + uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); + bytes32 root = contracts.keeper.rewardsRoot(); + + // Create a simple rewards root for testing + bytes32 rewardsRoot = keccak256(abi.encode('test rewards root')); + string memory ipfsHash = 'rewardsIpfsHash'; + uint256 avgRewardPerSecond = 868240800; + + // Create the update parameters + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: ipfsHash, + avgRewardPerSecond: avgRewardPerSecond, + updateTimestamp: uint64(block.timestamp), + signatures: bytes('') + }); + + // Create a valid signature from the oracle + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' + ), + rewardsRoot, + keccak256(bytes(ipfsHash)), + avgRewardPerSecond, + updateParams.updateTimestamp, + initialNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + updateParams.signatures = abi.encodePacked(r, s, v); + + // Move time forward to allow update + vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() + 1); + + // Act: Call updateRewards + _startSnapshotGas('KeeperRewardsTest_test_updateRewards'); + contracts.keeper.updateRewards(updateParams); + _stopSnapshotGas(); + + // Assert: Verify state has changed correctly + assertEq(contracts.keeper.rewardsRoot(), rewardsRoot, 'Rewards root not updated correctly'); + assertEq( + contracts.keeper.prevRewardsRoot(), + root, + 'Previous rewards root should be zero for first update' + ); + assertEq(contracts.keeper.rewardsNonce(), initialNonce + 1, 'Nonce should be incremented'); + assertEq( + contracts.keeper.lastRewardsTimestamp(), + block.timestamp, + 'Last rewards timestamp not updated' + ); + + // Verify OsTokenVaultController was updated with the new avgRewardPerSecond + assertEq( + contracts.osTokenVaultController.avgRewardPerSecond(), + avgRewardPerSecond, + 'avgRewardPerSecond not updated in OsTokenVaultController' + ); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test updating rewards fails when called too early + function test_updateRewards_tooEarly() public { + // Arrange: Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Get current nonce and timestamp + uint64 initialNonce = contracts.keeper.rewardsNonce(); + uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); + + // Create rewards update parameters + bytes32 rewardsRoot = keccak256(abi.encode('test rewards root')); + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: 'rewardsIpfsHash', + avgRewardPerSecond: 1e15, + updateTimestamp: uint64(block.timestamp), + signatures: bytes('') + }); + + // Create valid signature + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' + ), + updateParams.rewardsRoot, + keccak256(bytes(updateParams.rewardsIpfsHash)), + updateParams.avgRewardPerSecond, + updateParams.updateTimestamp, + initialNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + updateParams.signatures = abi.encodePacked(r, s, v); + + // Move time forward but not enough to allow an update + vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() - 1); + + // Act & Assert: Call should revert as it's too early + _startSnapshotGas('KeeperRewardsTest_test_updateRewards_tooEarly'); + vm.expectRevert(Errors.TooEarlyUpdate.selector); + contracts.keeper.updateRewards(updateParams); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test setting minimum oracles for rewards updates + function test_setRewardsMinOracles() public { + // Arrange: Get the Keeper owner + address keeperOwner = contracts.keeper.owner(); + uint256 currentMinOracles = contracts.keeper.rewardsMinOracles(); + uint256 newMinOracles = currentMinOracles + 1; + + // Make sure we add enough oracles + while (contracts.keeper.totalOracles() < newMinOracles) { + address newOracle = makeAddr('newOracle'); + vm.prank(keeperOwner); + contracts.keeper.addOracle(newOracle); + } + + // Act: Set new min oracles + vm.prank(keeperOwner); + _startSnapshotGas('KeeperRewardsTest_test_setRewardsMinOracles'); + contracts.keeper.setRewardsMinOracles(newMinOracles); + _stopSnapshotGas(); + + // Assert + assertEq( + contracts.keeper.rewardsMinOracles(), + newMinOracles, + 'Min oracles not updated correctly' + ); + } + + // Test setting min oracles fails when value is invalid + function test_setRewardsMinOracles_invalidValue() public { + // Arrange: Get the Keeper owner and total oracles + address keeperOwner = contracts.keeper.owner(); + uint256 totalOracles = contracts.keeper.totalOracles(); + + // Act & Assert: Set to zero (should fail) + vm.prank(keeperOwner); + _startSnapshotGas('KeeperRewardsTest_test_setRewardsMinOracles_zero'); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setRewardsMinOracles(0); + _stopSnapshotGas(); + + // Act & Assert: Set to more than total oracles (should fail) + vm.prank(keeperOwner); + _startSnapshotGas('KeeperRewardsTest_test_setRewardsMinOracles_tooMany'); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setRewardsMinOracles(totalOracles + 1); + _stopSnapshotGas(); + } + + // Test harvest functionality + function test_harvest() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Set up a reward for the vault + int160 totalReward = int160(int256(0.5 ether)); + uint160 unlockedMevReward = 0.1 ether; + + // Create harvest params with a valid reward setup + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + totalReward, + unlockedMevReward + ); + + // Record initial state + uint256 initialBalance = address(vault).balance; + + // Act: Update state (harvests rewards) + _startSnapshotGas('KeeperRewardsTest_test_harvest'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Assert: Check rewards were harvested + uint256 finalBalance = address(vault).balance; + assertGt(finalBalance, initialBalance, 'Vault balance should increase after harvest'); + + // Get reward struct to verify nonce update + (int192 assets, uint64 nonce) = contracts.keeper.rewards(address(vault)); + uint64 currentNonce = contracts.keeper.rewardsNonce(); + assertEq(nonce, currentNonce, 'Reward nonce should match current nonce'); + assertEq(assets, totalReward, 'Recorded assets should match the reward'); + + // Check MEV reward + if (unlockedMevReward > 0) { + (uint192 mevAssets, uint64 mevNonce) = contracts.keeper.unlockedMevRewards(address(vault)); + assertEq(mevNonce, currentNonce, 'MEV reward nonce should match current nonce'); + assertEq(mevAssets, unlockedMevReward, 'Recorded MEV assets should match the reward'); + } + } + + // Test harvesting with invalid reward root + function test_harvest_invalidRewardsRoot() public { + // Collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set up valid reward parameters + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.5 ether)), + 0.1 ether + ); + + // Modify the rewards root to make it invalid + harvestParams.rewardsRoot = keccak256(abi.encode('invalid root')); + + // Act & Assert: Expect failure when rewards root doesn't match + _startSnapshotGas('KeeperRewardsTest_test_harvest_invalidRewardsRoot'); + vm.expectRevert(Errors.InvalidRewardsRoot.selector); + vault.updateState(harvestParams); + _stopSnapshotGas(); + } + + // Test harvest with invalid proof + function test_harvest_invalidProof() public { + // Collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.5 ether)), + 0.1 ether + ); + + // Create an invalid proof + bytes32[] memory invalidProof = new bytes32[](1); + invalidProof[0] = keccak256(abi.encode('invalid proof')); + harvestParams.proof = invalidProof; + + // Act & Assert: Expect failure with invalid proof + _startSnapshotGas('KeeperRewardsTest_test_harvest_invalidProof'); + vm.expectRevert(Errors.InvalidProof.selector); + vault.updateState(harvestParams); + _stopSnapshotGas(); + } + + // Test isHarvestRequired functionality + function test_isHarvestRequired() public { + // Arrange: Collateralize vault + _collateralizeEthVault(address(vault)); + + // Initially, vault should not require harvest after collateralization + assertFalse( + contracts.keeper.isHarvestRequired(address(vault)), + 'Vault should not require harvest initially' + ); + + // Update rewards twice to make the vault need harvesting + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Act & Assert: Now the vault should require harvesting + _startSnapshotGas('KeeperRewardsTest_test_isHarvestRequired'); + bool harvestRequired = contracts.keeper.isHarvestRequired(address(vault)); + _stopSnapshotGas(); + + assertTrue(harvestRequired, 'Vault should require harvest after two reward updates'); + } + + // Test canHarvest functionality + function test_canHarvest() public { + // Arrange: Collateralize vault + _collateralizeEthVault(address(vault)); + + // Update rewards once + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Act & Assert: Vault should be able to harvest + _startSnapshotGas('KeeperRewardsTest_test_canHarvest'); + bool canHarvest = contracts.keeper.canHarvest(address(vault)); + _stopSnapshotGas(); + + assertTrue(canHarvest, 'Vault should be able to harvest after reward update'); + + // Now harvest the vault + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + vault.updateState(harvestParams); + + // Vault should no longer need harvesting + assertFalse( + contracts.keeper.canHarvest(address(vault)), + 'Vault should not need harvesting after update' + ); + } + + // Test isCollateralized functionality + function test_isCollateralized() public { + // Arrange: Initially, vault should not be collateralized + assertFalse( + contracts.keeper.isCollateralized(address(vault)), + 'Vault should not be collateralized initially' + ); + + // Act: Collateralize the vault + _collateralizeEthVault(address(vault)); + + // Assert: Vault should now be collateralized + _startSnapshotGas('KeeperRewardsTest_test_isCollateralized'); + bool isCollateralized = contracts.keeper.isCollateralized(address(vault)); + _stopSnapshotGas(); + + assertTrue(isCollateralized, 'Vault should be collateralized after collateralization'); + } + + // Test handling negative rewards (penalties) + function test_harvestWithPenalties() public { + // Arrange: Collateralize vault and deposit a larger amount + _depositToVault(address(vault), 1 ether, user, user); + _collateralizeEthVault(address(vault)); + + // Set up a negative reward (penalty) + int160 totalReward = int160(int256(-0.1 ether)); + uint160 unlockedMevReward = 0; + + // Create harvest params with a penalty + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + totalReward, + unlockedMevReward + ); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + + // Act: Update state (applies penalty) + _startSnapshotGas('KeeperRewardsTest_test_harvestWithPenalties'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Assert: Check that assets decreased due to penalty + uint256 finalTotalAssets = vault.totalAssets(); + assertLt(finalTotalAssets, initialTotalAssets, 'Total assets should decrease after penalty'); + + // Check the difference matches the penalty + assertApproxEqAbs( + int256(initialTotalAssets) - int256(finalTotalAssets), + -totalReward, + 1e9, // Allow small rounding difference + 'Asset difference should approximately match the penalty' + ); + } + + // Test updating rewards with an excessive avgRewardPerSecond + function test_updateRewards_invalidAvgRewardPerSecond() public { + // Arrange: Start oracle impersonation + _startOracleImpersonate(address(contracts.keeper)); + + // Get current nonce + uint64 initialNonce = contracts.keeper.rewardsNonce(); + uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); + + // Get the maximum allowed reward per second + // This is an immutable value so we need to get it indirectly + // Set up excessive reward rate (we know the max should be 1e10 or 10%) + uint256 excessiveRewardRate = 1e11; // 100% per second, definitely too high + + // Create params with excessive rate + bytes32 rewardsRoot = keccak256(abi.encode('test rewards root')); + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: 'rewardsIpfsHash', + avgRewardPerSecond: excessiveRewardRate, + updateTimestamp: uint64(block.timestamp), + signatures: bytes('') + }); + + // Create valid signature + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' + ), + updateParams.rewardsRoot, + keccak256(bytes(updateParams.rewardsIpfsHash)), + updateParams.avgRewardPerSecond, + updateParams.updateTimestamp, + initialNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + updateParams.signatures = abi.encodePacked(r, s, v); + + // Move time forward to allow update + vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() + 1); + + // Act & Assert: Call should revert due to excessive reward rate + _startSnapshotGas('KeeperRewardsTest_test_updateRewards_invalidAvgRewardPerSecond'); + vm.expectRevert(Errors.InvalidAvgRewardPerSecond.selector); + contracts.keeper.updateRewards(updateParams); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test calling harvest directly from a non-vault address + function test_harvest_nonVault() public { + // Arrange: Create generic harvest params + IKeeperRewards.HarvestParams memory harvestParams = IKeeperRewards.HarvestParams({ + rewardsRoot: keccak256(abi.encode('test')), + reward: int160(int256(0.5 ether)), + unlockedMevReward: 0.1 ether, + proof: new bytes32[](0) + }); + + // Act & Assert: Call harvest directly from a non-vault address + _startSnapshotGas('KeeperRewardsTest_test_harvest_nonVault'); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.keeper.harvest(harvestParams); + _stopSnapshotGas(); + } + + // Test calling harvest when rewards nonce hasn't changed + function test_harvest_alreadyHarvested() public { + // Arrange: Collateralize and harvest once + _collateralizeEthVault(address(vault)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.5 ether)), + 0.1 ether + ); + vault.updateState(harvestParams); + + // Try to harvest with the same nonce (not updated yet) + bool canHarvest = contracts.keeper.canHarvest(address(vault)); + assertFalse(canHarvest, 'Vault should not be able to harvest without rewards update'); + + // Act & Assert: Harvesting should succeed but make no changes + int256 totalAssetsBefore = int256(vault.totalAssets()); + _startSnapshotGas('KeeperRewardsTest_test_harvest_alreadyHarvested'); + vault.updateState(harvestParams); // This should be a no-op + _stopSnapshotGas(); + int256 totalAssetsAfter = int256(vault.totalAssets()); + + // Assert no changes occurred + assertEq( + totalAssetsAfter, + totalAssetsBefore, + 'Assets should not change when harvesting already harvested rewards' + ); + } + + // Test multiple reward updates and harvests in sequence + function test_multipleRewardUpdatesAndHarvests() public { + // Arrange: Collateralize vault + _collateralizeEthVault(address(vault)); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + + // Perform multiple reward updates and harvests + uint256 expectedTotalReward = 0; + for (uint i = 0; i < 3; i++) { + // Set reward for this round + int160 cumRoundReward = int160(int256(0.1 ether * (i + 1))); + uint160 cumRoundMevReward = uint160(0.02 ether * (i + 1)); + int160 roundTotalReward = cumRoundReward + int160(int256(uint256(cumRoundMevReward))); + expectedTotalReward += 0.12 ether; + + // Update and harvest + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + roundTotalReward, + cumRoundMevReward + ); + + _startSnapshotGas( + string.concat( + 'KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_', + vm.toString(i + 1) + ) + ); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify reward was applied - use direct field access + (int192 rewardAssets, uint64 rewardNonce) = contracts.keeper.rewards(address(vault)); + assertEq(rewardNonce, contracts.keeper.rewardsNonce(), 'Reward nonce should be updated'); + assertEq(rewardAssets, roundTotalReward, 'Reward assets should be updated'); + + // MEV rewards check + (uint192 mevAssets, uint64 mevNonce) = contracts.keeper.unlockedMevRewards(address(vault)); + assertEq(mevNonce, contracts.keeper.rewardsNonce(), 'MEV nonce should be updated'); + assertEq(mevAssets, cumRoundMevReward, 'MEV assets should be updated'); + } + + // Assert final state includes all rewards + uint256 finalTotalAssets = vault.totalAssets(); + assertApproxEqAbs( + finalTotalAssets - initialTotalAssets, + expectedTotalReward, + 1e9, // Allow small rounding difference + 'Total reward accumulated should match expected sum' + ); + } +} diff --git a/test/KeeperValidators.t.sol b/test/KeeperValidators.t.sol new file mode 100644 index 00000000..b57454b1 --- /dev/null +++ b/test/KeeperValidators.t.sol @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {Keeper} from '../contracts/keeper/Keeper.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; + +contract KeeperValidatorsTest is Test, EthHelpers { + // Fork contracts + ForkContracts public contracts; + + // Test vault and accounts + EthVault public vault; + address public admin; + address public user; + address public owner; + + // Constants for testing + uint256 public depositAmount = 32 ether; // Full validator amount + uint256 public validatorsDeadline; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + owner = contracts.keeper.owner(); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deposit ETH to the vault + _depositToVault(address(vault), depositAmount, user, user); + + // Set validators deadline + validatorsDeadline = block.timestamp + 100000; + } + + function test_approveValidators_success() public { + // Start oracle impersonation for signature generation + _startOracleImpersonate(address(contracts.keeper)); + + // Prepare approval parameters + string memory ipfsHash = 'ipfsHash'; + uint256[] memory depositAmounts = new uint256[](1); + depositAmounts[0] = 32 ether / 1 gwei; + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + ipfsHash, + depositAmounts, + false + ); + + // Set up event expectations + vm.expectEmit(true, true, true, true); + emit IKeeperValidators.ValidatorsApproval(address(vault), ipfsHash); + + // Call approveValidators as the vault + vm.prank(address(vault)); + _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_success'); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + + // Assert: Verify vault is now collateralized + assertTrue( + contracts.keeper.isCollateralized(address(vault)), + 'Vault should be collateralized after validator approval' + ); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_approveValidators_accessDenied() public { + // Create a mock validator approval params directly + // This avoids the complexities of signature generation + IKeeperValidators.ApprovalParams memory approvalParams = IKeeperValidators.ApprovalParams({ + validatorsRegistryRoot: contracts.validatorsRegistry.get_deposit_root(), + validators: new bytes(176), // Empty validator data + signatures: new bytes(65), // Empty signature + exitSignaturesIpfsHash: 'ipfsHash', + deadline: block.timestamp + 1000 + }); + + // Act & Assert: Call from non-vault address should fail because of access control + // This should fail before signature validation + _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_accessDenied'); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + } + + function test_approveValidators_invalidRegistry() public { + // Start by collateralizing with valid parameters + _startOracleImpersonate(address(contracts.keeper)); + + // Get the approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + depositAmount, + 'ipfsHash', + false + ); + + // Change validators registry root to an invalid value + approvalParams.validatorsRegistryRoot = keccak256(abi.encode('invalid registry root')); + + // Stop oracle impersonation + _stopOracleImpersonate(address(contracts.keeper)); + + // Start impersonating the vault + vm.prank(address(vault)); + + // Act & Assert: Call should fail due to invalid registry root + // This happens before signature validation + _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_invalidRegistry'); + vm.expectRevert(Errors.InvalidValidatorsRegistryRoot.selector); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + } + + function test_approveValidators_invalidDeadline() public { + // Start oracle impersonation for signature generation + _startOracleImpersonate(address(contracts.keeper)); + + // Arrange: Prepare validation approval parameters with an expired deadline + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + depositAmount, + 'ipfsHash', + false + ); + + // Stop oracle impersonation + _stopOracleImpersonate(address(contracts.keeper)); + + // Set expired deadline + approvalParams.deadline = block.timestamp - 1; // Expired + + // Start impersonating the vault - this test will check deadline before signature validation + vm.prank(address(vault)); + + // Act & Assert: Call should fail due to expired deadline + _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_invalidDeadline'); + vm.expectRevert(Errors.DeadlineExpired.selector); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + } + + // Test updateExitSignatures functionality + function test_updateExitSignatures_success() public { + // Arrange: First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Set up event expectations + vm.expectEmit(true, true, false, true); + emit IKeeperValidators.ExitSignaturesUpdated( + address(this), + address(vault), + initialNonce, + exitSignaturesIpfsHash + ); + + // Act: Update exit signatures + _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_success'); + contracts.keeper.updateExitSignatures( + address(vault), + deadline, + exitSignaturesIpfsHash, + signatures + ); + _stopSnapshotGas(); + + // Assert: Check that nonce was incremented + assertEq( + contracts.keeper.exitSignaturesNonces(address(vault)), + initialNonce + 1, + 'Exit signatures nonce should be incremented' + ); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_invalidVault() public { + // Arrange: Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = 0; + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' + ), + address(contracts.keeper), // Using Keeper as vault (invalid) + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Act & Assert: Call should fail due to invalid vault + _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_invalidVault'); + vm.expectRevert(Errors.InvalidVault.selector); + contracts.keeper.updateExitSignatures( + address(contracts.keeper), // Using Keeper as vault (invalid) + deadline, + exitSignaturesIpfsHash, + signatures + ); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_notCollateralized() public { + // Arrange: Vault is not collateralized yet + assertFalse( + contracts.keeper.isCollateralized(address(vault)), + 'Vault should not be collateralized initially' + ); + + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = 0; + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Act & Assert: Call should fail due to non-collateralized vault + _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_notCollateralized'); + vm.expectRevert(Errors.InvalidVault.selector); + contracts.keeper.updateExitSignatures( + address(vault), + deadline, + exitSignaturesIpfsHash, + signatures + ); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_expiredDeadline() public { + // Arrange: First collateralize the vault + _collateralizeEthVault(address(vault)); + + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update with expired deadline + string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; + uint256 deadline = block.timestamp - 1; // Expired + uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Act & Assert: Call should fail due to expired deadline + _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_expiredDeadline'); + vm.expectRevert(Errors.DeadlineExpired.selector); + contracts.keeper.updateExitSignatures( + address(vault), + deadline, + exitSignaturesIpfsHash, + signatures + ); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_duplicateUpdate() public { + // Arrange: First collateralize the vault + _collateralizeEthVault(address(vault)); + + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // First update should succeed + contracts.keeper.updateExitSignatures( + address(vault), + deadline, + exitSignaturesIpfsHash, + signatures + ); + + // Act & Assert: Second update with same params should fail due to nonce mismatch + _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_duplicateUpdate'); + vm.expectRevert(Errors.InvalidOracle.selector); + contracts.keeper.updateExitSignatures( + address(vault), + deadline, + exitSignaturesIpfsHash, + signatures + ); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test setValidatorsMinOracles functionality + function test_setValidatorsMinOracles_success() public { + // Arrange: Get current min oracles + uint256 currentMinOracles = contracts.keeper.validatorsMinOracles(); + uint256 totalOracles = contracts.keeper.totalOracles(); + + // Ensure we set to a valid value (not exceeding total oracles) + uint256 newMinOracles = totalOracles > 1 ? totalOracles - 1 : 1; + + // Skip if we're already at target value + if (currentMinOracles == newMinOracles) { + newMinOracles = totalOracles; + } + + // Set up event expectations + vm.expectEmit(true, false, false, false); + emit IKeeperValidators.ValidatorsMinOraclesUpdated(newMinOracles); + + // Act: Set new min oracles + vm.prank(owner); + _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_success'); + contracts.keeper.setValidatorsMinOracles(newMinOracles); + _stopSnapshotGas(); + + // Assert: Check value was updated + assertEq( + contracts.keeper.validatorsMinOracles(), + newMinOracles, + 'Min oracles should be updated' + ); + } + + function test_setValidatorsMinOracles_unauthorized() public { + // Arrange: Get current min oracles + uint256 currentMinOracles = contracts.keeper.validatorsMinOracles(); + + // Act & Assert: Call from non-owner should fail + address nonOwner = makeAddr('nonOwner'); + vm.prank(nonOwner); + _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_unauthorized'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + contracts.keeper.setValidatorsMinOracles(currentMinOracles + 1); + _stopSnapshotGas(); + } + + function test_setValidatorsMinOracles_invalidValue() public { + // Arrange: Get total oracles + uint256 totalOracles = contracts.keeper.totalOracles(); + + // Act & Assert: Setting to zero should fail + vm.prank(owner); + _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_zero'); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setValidatorsMinOracles(0); + _stopSnapshotGas(); + + // Act & Assert: Setting above total oracles should fail + vm.prank(owner); + _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_tooHigh'); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setValidatorsMinOracles(totalOracles + 1); + _stopSnapshotGas(); + } +} diff --git a/test/Multicall.t.sol b/test/Multicall.t.sol new file mode 100644 index 00000000..ca564d6c --- /dev/null +++ b/test/Multicall.t.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {MulticallMock} from '../contracts/mocks/MulticallMock.sol'; + +contract MulticallTest is Test { + MulticallMock public multicall; + + function setUp() public { + multicall = new MulticallMock(); + } + + function test_multipleSuccessfulCalls() public { + bytes[] memory data = new bytes[](3); + data[0] = abi.encodeWithSelector(multicall.setValue.selector, 123); + data[1] = abi.encodeWithSelector(multicall.setMessage.selector, 'Hello, Multicall'); + data[2] = abi.encodeWithSelector(multicall.setFlag.selector, true); + + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, 3); + assertEq(abi.decode(results[0], (uint256)), 123); + assertEq(abi.decode(results[1], (string)), 'Hello, Multicall'); + assertEq(abi.decode(results[2], (bool)), true); + + assertEq(multicall.value(), 123); + assertEq(multicall.message(), 'Hello, Multicall'); + assertEq(multicall.flag(), true); + } + + function test_emptyCallsArray() public { + bytes[] memory data = new bytes[](0); + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, 0); + } + + function test_multipleParams() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector( + multicall.multipleParams.selector, + 456, + 'Multiple params', + false + ); + + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, 1); + (uint256 a, string memory b, bool c) = abi.decode(results[0], (uint256, string, bool)); + assertEq(a, 456); + assertEq(b, 'Multiple params'); + assertEq(c, false); + + assertEq(multicall.value(), 456); + assertEq(multicall.message(), 'Multiple params'); + assertEq(multicall.flag(), false); + } + + function test_revertWithMessage() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.revertWithMessage.selector); + + vm.expectRevert('Intentional revert with message'); + multicall.multicall(data); + } + + function test_revertWithoutMessage() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.revertWithoutMessage.selector); + + vm.expectRevert(); + multicall.multicall(data); + } + + function test_invalidCalldata() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodePacked('invalidCalldata'); + + vm.expectRevert(); + multicall.multicall(data); + } + + function test_mixSuccessAndFailure() public { + // First set a value that should remain after the revert + multicall.setValue(42); + + bytes[] memory data = new bytes[](3); + data[0] = abi.encodeWithSelector(multicall.setValue.selector, 789); + data[1] = abi.encodeWithSelector(multicall.revertWithMessage.selector); + data[2] = abi.encodeWithSelector(multicall.setFlag.selector, true); + + vm.expectRevert('Intentional revert with message'); + multicall.multicall(data); + + // Check that the initial value remains since the entire multicall reverted + assertEq(multicall.value(), 42); + // The flag should not be set either + assertEq(multicall.flag(), false); + } + + function test_delegateCall() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.checkCaller.selector); + + bytes[] memory results = multicall.multicall(data); + + // The caller should be this test contract, not the multicall contract + assertEq(abi.decode(results[0], (address)), address(this)); + assertEq(multicall.caller(), address(this)); + } + + function testSequentialExecution() public { + // Add a function to the mock contract that increments the current value + bytes[] memory data = new bytes[](2); + data[0] = abi.encodeWithSelector(multicall.setValue.selector, 100); + // For the second call, we'll manually encode a call that adds 50 to whatever the current value is + data[1] = abi.encodeWithSignature('addToValue(uint256)', 50); + + bytes[] memory results = multicall.multicall(data); + + assertEq(abi.decode(results[0], (uint256)), 100); + assertEq(abi.decode(results[1], (uint256)), 150); + assertEq(multicall.value(), 150); + } + + function test_largeNumberOfCalls() public { + uint256 numCalls = 20; + bytes[] memory data = new bytes[](numCalls); + + for (uint256 i = 0; i < numCalls; i++) { + data[i] = abi.encodeWithSelector(multicall.setValue.selector, i); + } + + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, numCalls); + for (uint256 i = 0; i < numCalls; i++) { + assertEq(abi.decode(results[i], (uint256)), i); + } + + // Value should be set to the last call's argument + assertEq(multicall.value(), numCalls - 1); + } +} diff --git a/test/OsToken.t.sol b/test/OsToken.t.sol new file mode 100644 index 00000000..dc1fef21 --- /dev/null +++ b/test/OsToken.t.sol @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {OsToken} from '../contracts/tokens/OsToken.sol'; +import {IOsToken} from '../contracts/interfaces/IOsToken.sol'; +import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract OsTokenTest is Test, EthHelpers { + // Testing contracts + ForkContracts public contracts; + OsToken public osToken; + + // Test addresses + address public owner; + address public user; + address public controller; + + function setUp() public { + // Activate Ethereum fork + contracts = _activateEthereumFork(); + + // Get the existing OsToken contract from the fork + osToken = OsToken(_osToken); + + // Setup test addresses + owner = makeAddr('owner'); + user = makeAddr('user'); + controller = makeAddr('controller'); + + // Fund user account for transactions + vm.deal(user, 100 ether); + } + + // Test initialization and basic properties + function test_initialization() public view { + // Check name and symbol + assertEq(osToken.name(), 'Staked ETH', 'Wrong token name'); + assertEq(osToken.symbol(), 'osETH', 'Wrong token symbol'); + } + + // Test controller management + function test_setController() public { + // Get current owner + address currentOwner = osToken.owner(); + vm.startPrank(currentOwner); + + // Add new controller + _startSnapshotGas('OsTokenTest_test_setController_add'); + osToken.setController(controller, true); + _stopSnapshotGas(); + + // Verify controller was added + assertTrue(osToken.controllers(controller), 'Controller should be enabled'); + + // Remove controller + _startSnapshotGas('OsTokenTest_test_setController_remove'); + osToken.setController(controller, false); + _stopSnapshotGas(); + + // Verify controller was removed + assertFalse(osToken.controllers(controller), 'Controller should be disabled'); + + vm.stopPrank(); + } + + // Test controller management access control + function test_setController_onlyOwner() public { + vm.prank(user); + _startSnapshotGas('OsTokenTest_test_setController_onlyOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', user)); + osToken.setController(controller, true); + _stopSnapshotGas(); + } + + // Test setController with zero address + function test_setController_zeroAddress() public { + address currentOwner = osToken.owner(); + vm.prank(currentOwner); + _startSnapshotGas('OsTokenTest_test_setController_zeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + osToken.setController(address(0), true); + _stopSnapshotGas(); + } + + // Test minting + function test_mint() public { + // Setup controller + address currentOwner = osToken.owner(); + vm.prank(currentOwner); + osToken.setController(controller, true); + + uint256 amount = 100 ether; + uint256 initialBalance = osToken.balanceOf(user); + + // Mint tokens + vm.prank(controller); + _startSnapshotGas('OsTokenTest_test_mint'); + osToken.mint(user, amount); + _stopSnapshotGas(); + + // Verify balance increased + assertEq( + osToken.balanceOf(user), + initialBalance + amount, + 'Balance should increase by minted amount' + ); + } + + // Test minting access control + function test_mint_onlyController() public { + uint256 amount = 100 ether; + + // Try to mint without being a controller + vm.prank(user); + _startSnapshotGas('OsTokenTest_test_mint_onlyController'); + vm.expectRevert(Errors.AccessDenied.selector); + osToken.mint(user, amount); + _stopSnapshotGas(); + } + + // Test burning + function test_burn() public { + // Setup controller and mint tokens first + address currentOwner = osToken.owner(); + vm.prank(currentOwner); + osToken.setController(controller, true); + + uint256 amount = 100 ether; + vm.prank(controller); + osToken.mint(user, amount); + + uint256 initialBalance = osToken.balanceOf(user); + + // Burn tokens + vm.prank(controller); + _startSnapshotGas('OsTokenTest_test_burn'); + osToken.burn(user, amount); + _stopSnapshotGas(); + + // Verify balance decreased + assertEq( + osToken.balanceOf(user), + initialBalance - amount, + 'Balance should decrease by burned amount' + ); + } + + // Test burning access control + function test_burn_onlyController() public { + // Mint tokens first using the _mintOsToken helper + uint256 amount = 100 ether; + _mintOsToken(user, amount); + + // Try to burn without being a controller + vm.prank(user); + _startSnapshotGas('OsTokenTest_test_burn_onlyController'); + vm.expectRevert(Errors.AccessDenied.selector); + osToken.burn(user, amount); + _stopSnapshotGas(); + } + + // Test integration with OsTokenVaultController + function test_controllerIntegration() public { + // Test that the OsTokenVaultController can mint tokens + uint256 amount = 10 ether; + uint256 initialBalance = osToken.balanceOf(user); + + // Use the vault controller to mint tokens + _startSnapshotGas('OsTokenTest_test_controllerIntegration_mint'); + _mintOsToken(user, amount); + _stopSnapshotGas(); + + // Verify balance increased + assertEq( + osToken.balanceOf(user), + initialBalance + amount, + 'Balance should increase by minted amount' + ); + + // Test burning from the controller + vm.prank(address(contracts.osTokenVaultController)); + _startSnapshotGas('OsTokenTest_test_controllerIntegration_burn'); + osToken.burn(user, amount); + _stopSnapshotGas(); + + // Verify balance decreased back to initial + assertEq( + osToken.balanceOf(user), + initialBalance, + 'Balance should decrease back to initial amount' + ); + } + + // Test token permit functionality + function test_permit() public { + uint256 ownerPrivateKey = 123456; // Sample private key for testing + address tokenOwner = vm.addr(ownerPrivateKey); + + // Mint tokens to the token owner + _mintOsToken(tokenOwner, 100 ether); + + // Create permit data + uint256 value = 10 ether; + uint256 deadline = block.timestamp + 1 hours; + uint256 nonceBefore = osToken.nonces(tokenOwner); + + // Generate signature + bytes32 domainSeparator = osToken.DOMAIN_SEPARATOR(); + bytes32 permitTypehash = keccak256( + 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' + ); + + bytes32 structHash = keccak256( + abi.encode(permitTypehash, tokenOwner, user, value, nonceBefore, deadline) + ); + + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + // Execute permit + _startSnapshotGas('OsTokenTest_test_permit'); + osToken.permit(tokenOwner, user, value, deadline, v, r, s); + _stopSnapshotGas(); + + // Verify allowance was set + assertEq(osToken.allowance(tokenOwner, user), value, 'Allowance should be set to permit value'); + + // Verify nonce was incremented + assertEq(osToken.nonces(tokenOwner), nonceBefore + 1, 'Nonce should be incremented'); + } + + // Test permit with expired deadline + function test_permit_expiredDeadline() public { + uint256 ownerPrivateKey = 123456; + address tokenOwner = vm.addr(ownerPrivateKey); + + // Create permit with expired deadline + uint256 expiredDeadline = block.timestamp - 1 hours; + + // Generate signature (exact signature doesn't matter as we'll hit the deadline check first) + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, bytes32(0)); + + // Execute permit with expired deadline + _startSnapshotGas('OsTokenTest_test_permit_expiredDeadline'); + vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 + osToken.permit(tokenOwner, user, 1 ether, expiredDeadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with invalid signature + function test_permit_invalidSignature() public { + uint256 ownerPrivateKey = 123456; + address tokenOwner = vm.addr(ownerPrivateKey); + uint256 wrongPrivateKey = 654321; + + // Create valid permit data + uint256 value = 10 ether; + uint256 deadline = block.timestamp + 1 hours; + uint256 nonce = osToken.nonces(tokenOwner); + + // Generate invalid signature (using wrong private key) + bytes32 domainSeparator = osToken.DOMAIN_SEPARATOR(); + bytes32 permitTypehash = keccak256( + 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' + ); + + bytes32 structHash = keccak256( + abi.encode(permitTypehash, tokenOwner, user, value, nonce, deadline) + ); + + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, digest); + + // Execute permit with invalid signature + _startSnapshotGas('OsTokenTest_test_permit_invalidSignature'); + vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 + osToken.permit(tokenOwner, user, value, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with zero address spender + function test_permit_zeroAddress() public { + uint256 ownerPrivateKey = 123456; + address tokenOwner = vm.addr(ownerPrivateKey); + + // Create permit with zero address + uint256 deadline = block.timestamp + 1 hours; + + // Generate signature (exact signature doesn't matter as we'll hit the zero address check first) + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, bytes32(0)); + + // Execute permit with zero address + _startSnapshotGas('OsTokenTest_test_permit_zeroAddress'); + vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 + osToken.permit(tokenOwner, address(0), 1 ether, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test ERC20 transfer and transferFrom functionality + function test_erc20_transfers() public { + // Mint tokens to the user + uint256 amount = 50 ether; + _mintOsToken(user, amount); + + address recipient = makeAddr('recipient'); + uint256 transferAmount = 10 ether; + + // Test transfer function + vm.prank(user); + _startSnapshotGas('OsTokenTest_test_erc20_transfer'); + bool transferSuccess = osToken.transfer(recipient, transferAmount); + _stopSnapshotGas(); + + assertTrue(transferSuccess, 'Transfer should succeed'); + assertEq(osToken.balanceOf(recipient), transferAmount, 'Recipient should receive tokens'); + assertEq(osToken.balanceOf(user), amount - transferAmount, "User's balance should be reduced"); + + // Test transferFrom function + address spender = makeAddr('spender'); + uint256 approvalAmount = 20 ether; + + // Approve spender + vm.prank(user); + osToken.approve(spender, approvalAmount); + + // Use transferFrom + vm.prank(spender); + _startSnapshotGas('OsTokenTest_test_erc20_transferFrom'); + bool transferFromSuccess = osToken.transferFrom(user, recipient, 5 ether); + _stopSnapshotGas(); + + assertTrue(transferFromSuccess, 'TransferFrom should succeed'); + assertEq( + osToken.balanceOf(recipient), + transferAmount + 5 ether, + 'Recipient should receive additional tokens' + ); + assertEq( + osToken.balanceOf(user), + amount - transferAmount - 5 ether, + "User's balance should be further reduced" + ); + assertEq( + osToken.allowance(user, spender), + approvalAmount - 5 ether, + 'Allowance should be reduced' + ); + } + + // Test integration with full deposit flow + function test_fullDepositFlow() public { + // Create a vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, user, initParams, false); + + // Collateralize vault + _collateralizeEthVault(vaultAddr); + + // Deposit ETH to mint vault tokens + uint256 depositAmount = 10 ether; + uint256 initialOsTokenBalance = osToken.balanceOf(user); + + // Deposit and mint osToken in one transaction + vm.deal(user, user.balance + depositAmount); + vm.prank(user); + _startSnapshotGas('OsTokenTest_test_fullDepositFlow'); + uint256 mintedOsTokenShares = IEthVault(vaultAddr).depositAndMintOsToken{value: depositAmount}( + user, + type(uint256).max, // max possible amount + address(0) + ); + _stopSnapshotGas(); + + // Verify osToken was minted + assertGt(osToken.balanceOf(user), initialOsTokenBalance, 'osToken balance should increase'); + + // Due to conversion rates and fees, the exact amounts may not match perfectly + // We verify the amounts are close enough (within 5%) + uint256 actualIncrease = osToken.balanceOf(user) - initialOsTokenBalance; + assertApproxEqRel( + actualIncrease, + mintedOsTokenShares, + 0.05e18, // 5% tolerance + 'Minted osToken amount too far from expected' + ); + } +} diff --git a/test/OsTokenConfig.t.sol b/test/OsTokenConfig.t.sol new file mode 100644 index 00000000..0750d4ec --- /dev/null +++ b/test/OsTokenConfig.t.sol @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {OsTokenConfig} from '../contracts/tokens/OsTokenConfig.sol'; +import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract OsTokenConfigTest is Test, EthHelpers { + // Test accounts + address public owner; + address public nonOwner; + address public newRedeemer; + address public vault; + address public anotherVault; + + // Contract under test + IOsTokenConfig public osTokenConfig; + + // Deployment constants + uint256 constant MAX_PERCENT = 1e18; // 100% + uint256 constant DISABLED_LIQ_THRESHOLD = type(uint64).max; + + function setUp() public { + // Activate Ethereum fork and get contracts + ForkContracts memory contracts = _activateEthereumFork(); + + // Get the OsTokenConfig contract from the fork + osTokenConfig = contracts.osTokenConfig; + + // Set up test accounts + owner = Ownable(address(osTokenConfig)).owner(); + nonOwner = makeAddr('nonOwner'); + newRedeemer = makeAddr('newRedeemer'); + vault = makeAddr('vault'); + anotherVault = makeAddr('anotherVault'); + } + + // Test for initial contract state + function test_initialState() public view { + // Check that redeemer is already set + address currentRedeemer = osTokenConfig.redeemer(); + assertFalse(currentRedeemer == address(0), 'Redeemer should be set'); + + // Get default config and check it's valid + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(0)); + assertTrue(config.ltvPercent > 0, 'Default LTV should be greater than 0'); + assertTrue( + config.ltvPercent <= MAX_PERCENT, + 'Default LTV should be less than or equal to max percent' + ); + + // Check that liqThresholdPercent is either valid or disabled + if (config.liqThresholdPercent != DISABLED_LIQ_THRESHOLD) { + assertTrue( + config.liqThresholdPercent > config.ltvPercent, + 'Default liq threshold should be greater than LTV' + ); + assertTrue( + config.liqThresholdPercent < MAX_PERCENT, + 'Default liq threshold should be less than max percent' + ); + } + + // Check liqBonus constraints + if (config.liqThresholdPercent == DISABLED_LIQ_THRESHOLD) { + assertEq(config.liqBonusPercent, 0, 'When liquidations disabled, bonus should be 0'); + } else { + assertTrue( + config.liqBonusPercent >= MAX_PERCENT, + 'Default liq bonus should be at least max percent' + ); + + // Check threshold * bonus <= MAX_PERCENT + uint256 product = (config.liqThresholdPercent * config.liqBonusPercent) / MAX_PERCENT; + assertTrue(product <= MAX_PERCENT, 'Threshold * bonus should be <= max percent'); + } + } + + // Test setting redeemer address + function test_setRedeemer() public { + // Get current redeemer + address currentRedeemer = osTokenConfig.redeemer(); + + // Make sure our new redeemer is different + if (newRedeemer == currentRedeemer) { + newRedeemer = makeAddr('anotherNewRedeemer'); + } + + // Set up expected event + vm.expectEmit(true, false, false, false); + emit IOsTokenConfig.RedeemerUpdated(newRedeemer); + + // Set new redeemer as owner + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_setRedeemer'); + osTokenConfig.setRedeemer(newRedeemer); + _stopSnapshotGas(); + + // Verify redeemer was updated + assertEq(osTokenConfig.redeemer(), newRedeemer, 'Redeemer not updated correctly'); + + // Reset to original state for other tests + vm.prank(owner); + osTokenConfig.setRedeemer(currentRedeemer); + } + + // Test non-owner trying to set redeemer (should fail) + function test_setRedeemer_notOwner() public { + // Get current redeemer + address currentRedeemer = osTokenConfig.redeemer(); + + // Attempt to set redeemer as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas('OsTokenConfigForkTest_test_setRedeemer_notOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + osTokenConfig.setRedeemer(newRedeemer); + _stopSnapshotGas(); + + // Verify redeemer was not changed + assertEq(osTokenConfig.redeemer(), currentRedeemer, 'Redeemer should not be changed'); + } + + // Test setting the same redeemer (should fail) + function test_setRedeemer_sameValue() public { + // Get current redeemer + address currentRedeemer = osTokenConfig.redeemer(); + + // Attempt to set the same redeemer, should revert + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_setRedeemer_sameValue'); + vm.expectRevert(Errors.ValueNotChanged.selector); + osTokenConfig.setRedeemer(currentRedeemer); + _stopSnapshotGas(); + + // Verify redeemer was not changed + assertEq(osTokenConfig.redeemer(), currentRedeemer, 'Redeemer should not be changed'); + } + + // Test updating config for a specific vault + function test_updateConfig_forVault() public { + // Create new config with reasonable values + IOsTokenConfig.Config memory newConfig = IOsTokenConfig.Config({ + ltvPercent: 7e17, // 70% + liqThresholdPercent: 8e17, // 80% + liqBonusPercent: 1.2e18 // 120% + }); + + // Set up expected event + vm.expectEmit(true, true, true, true); + emit IOsTokenConfig.OsTokenConfigUpdated( + vault, + newConfig.liqBonusPercent, + newConfig.liqThresholdPercent, + newConfig.ltvPercent + ); + + // Update config for vault + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_forVault'); + osTokenConfig.updateConfig(vault, newConfig); + _stopSnapshotGas(); + + // Verify config was updated for vault + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(vault); + assertEq(config.ltvPercent, newConfig.ltvPercent, 'Vault LTV not updated correctly'); + assertEq( + config.liqThresholdPercent, + newConfig.liqThresholdPercent, + 'Vault liquidation threshold not updated correctly' + ); + assertEq( + config.liqBonusPercent, + newConfig.liqBonusPercent, + 'Vault liquidation bonus not updated correctly' + ); + + // Get default config + IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); + + // Check default config was not affected + assertNotEq(config.ltvPercent, defaultConfig.ltvPercent, 'Default LTV should not be changed'); + assertNotEq( + config.liqThresholdPercent, + defaultConfig.liqThresholdPercent, + 'Default liquidation threshold should not be changed' + ); + assertNotEq( + config.liqBonusPercent, + defaultConfig.liqBonusPercent, + 'Default liquidation bonus should not be changed' + ); + } + + // Test non-owner trying to update config (should fail) + function test_updateConfig_notOwner() public { + // Create new config + IOsTokenConfig.Config memory newConfig = IOsTokenConfig.Config({ + ltvPercent: 7e17, // 70% + liqThresholdPercent: 8e17, // 80% + liqBonusPercent: 1.2e18 // 120% + }); + + // Attempt to update config as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_notOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + osTokenConfig.updateConfig(vault, newConfig); + _stopSnapshotGas(); + } + + // Test updating config with invalid LTV percent + function test_updateConfig_invalidLtvPercent() public { + // Get default config + IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); + + // Test with ltvPercent = 0 + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 0, + liqThresholdPercent: defaultConfig.liqThresholdPercent, + liqBonusPercent: defaultConfig.liqBonusPercent + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_zero'); + vm.expectRevert(Errors.InvalidLtvPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with ltvPercent > MAX_PERCENT (1e18) + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: uint64(MAX_PERCENT + 1), + liqThresholdPercent: defaultConfig.liqThresholdPercent, + liqBonusPercent: defaultConfig.liqBonusPercent + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_tooHigh'); + vm.expectRevert(Errors.InvalidLtvPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test updating config with invalid liquidation threshold percent + function test_updateConfig_invalidLiqThresholdPercent() public { + // Test with liqThresholdPercent = 0 (when not disabled) + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: 0, + liqBonusPercent: 1.1e18 // 110% + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_zero'); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with liqThresholdPercent >= MAX_PERCENT (1e18) + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: uint64(MAX_PERCENT), + liqBonusPercent: 1.1e18 // 110% + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_tooHigh'); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with ltvPercent > liqThresholdPercent + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 9e17, // 90% + liqThresholdPercent: 8e17, // 80% + liqBonusPercent: 1.1e18 // 110% + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_ltv'); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test updating config with invalid liquidation bonus percent + function test_updateConfig_invalidLiqBonusPercent() public { + // Test with liqBonusPercent < MAX_PERCENT (1e18) + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: 7e17, // 70% + liqBonusPercent: 0.9e18 // 90% + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_tooLow'); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with threshold * bonus > MAX_PERCENT + // If threshold = 95% and bonus = 106%, then 0.95 * 1.06 = 1.007 > 1.0 + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 8e17, // 80% + liqThresholdPercent: 95e16, // 95% + liqBonusPercent: 1.06e18 // 106% + }); + + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_product'); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test disabled liquidations configuration + function test_updateConfig_disabledLiquidations() public { + // Create config with disabled liquidations + IOsTokenConfig.Config memory disabledLiqConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: uint64(DISABLED_LIQ_THRESHOLD), + liqBonusPercent: 0 // Must be 0 when liquidations disabled + }); + + // Update config for vault + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_disabledLiquidations'); + osTokenConfig.updateConfig(vault, disabledLiqConfig); + _stopSnapshotGas(); + + // Verify config was updated correctly + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(vault); + assertEq(config.ltvPercent, disabledLiqConfig.ltvPercent, 'Vault LTV not updated correctly'); + assertEq( + config.liqThresholdPercent, + uint64(DISABLED_LIQ_THRESHOLD), + 'Vault liquidation threshold should be disabled' + ); + assertEq(config.liqBonusPercent, 0, 'Vault liquidation bonus should be 0'); + } + + // Test invalid disabled liquidations configuration + function test_updateConfig_invalidDisabledLiquidations() public { + // Create config with disabled liquidations but non-zero bonus + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: uint64(DISABLED_LIQ_THRESHOLD), + liqBonusPercent: 1.1e18 // Should be 0 when liquidations disabled + }); + + // Attempt to update config, should revert + vm.prank(owner); + _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidDisabledLiquidations'); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test getConfig for vault with no specific config + function test_getConfig_defaultFallback() public view { + // Get default config + IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); + + // Verify vault with no specific config gets default config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(anotherVault); + assertEq(config.ltvPercent, defaultConfig.ltvPercent, 'Should return default LTV'); + assertEq( + config.liqThresholdPercent, + defaultConfig.liqThresholdPercent, + 'Should return default liquidation threshold' + ); + assertEq( + config.liqBonusPercent, + defaultConfig.liqBonusPercent, + 'Should return default liquidation bonus' + ); + } + + function test_updateDefaultConfig_success() public { + // Define new default configuration values + uint64 newLtvPercent = 0.7e18; // 70% + uint64 newLiqThresholdPercent = 0.8e18; // 80% + uint128 newLiqBonusPercent = 1.1e18; // 110% + + IOsTokenConfig.Config memory newDefaultConfig = IOsTokenConfig.Config({ + ltvPercent: newLtvPercent, + liqThresholdPercent: newLiqThresholdPercent, + liqBonusPercent: newLiqBonusPercent + }); + + // Test address that doesn't have a specific config + address randomVault = makeAddr('randomVault'); + + // Expect OsTokenConfigUpdated event + vm.expectEmit(true, false, true, true); + emit IOsTokenConfig.OsTokenConfigUpdated( + address(0), + newLiqBonusPercent, + newLiqThresholdPercent, + newLtvPercent + ); + + // Update the default configuration + vm.prank(owner); + _startSnapshotGas('OsTokenConfigTest_test_updateDefaultConfig_success'); + osTokenConfig.updateConfig(address(0), newDefaultConfig); + _stopSnapshotGas(); + + // Get the config for a random vault without specific config + IOsTokenConfig.Config memory retrievedConfig = osTokenConfig.getConfig(randomVault); + + // Verify the default config was updated and is returned for vaults without specific config + assertEq(retrievedConfig.ltvPercent, newLtvPercent, 'LTV percent not updated correctly'); + assertEq( + retrievedConfig.liqThresholdPercent, + newLiqThresholdPercent, + 'Liquidation threshold percent not updated correctly' + ); + assertEq( + retrievedConfig.liqBonusPercent, + newLiqBonusPercent, + 'Liquidation bonus percent not updated correctly' + ); + } +} diff --git a/test/OsTokenFlashLoans.t.sol b/test/OsTokenFlashLoans.t.sol new file mode 100644 index 00000000..ae3cb44c --- /dev/null +++ b/test/OsTokenFlashLoans.t.sol @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {OsTokenFlashLoans, IOsTokenFlashLoans} from '../contracts/tokens/OsTokenFlashLoans.sol'; +import {OsTokenFlashLoanRecipientMock} from '../contracts/mocks/OsTokenFlashLoanRecipientMock.sol'; +import {OsToken} from '../contracts/tokens/OsToken.sol'; +import {IOsTokenFlashLoanRecipient} from '../contracts/interfaces/IOsTokenFlashLoanRecipient.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract OsTokenFlashLoansTest is Test, EthHelpers { + // Constants for deployed contracts + uint256 public constant MAX_FLASH_LOAN_AMOUNT = 100_000 ether; + + ForkContracts public contracts; + + // Contract instances + OsTokenFlashLoans public flashLoans; + OsToken public osToken; + OsTokenFlashLoanRecipientMock public recipient; + + // Test accounts + address public admin; + address public user; + + function setUp() public { + // Fork mainnet + contracts = _activateEthereumFork(); + + // Connect to deployed contracts + flashLoans = OsTokenFlashLoans(_osTokenFlashLoans); + osToken = OsToken(_osToken); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + vm.deal(user, 100 ether); + + // Deploy mock recipient + recipient = new OsTokenFlashLoanRecipientMock(_osToken, _osTokenFlashLoans); + + // Mint tokens to the recipient for repayment + _mintOsToken(address(recipient), 1000 ether); + } + + function test_flashLoan_success() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + uint256 flashLoanAmount = 100 ether; + + // Record pre-loan state + uint256 recipientPreBalance = osToken.balanceOf(address(recipient)); + uint256 flashLoansPreBalance = osToken.balanceOf(_osTokenFlashLoans); + + // Execute the flash loan + vm.expectEmit(true, true, false, false); + emit IOsTokenFlashLoans.OsTokenFlashLoan(address(recipient), flashLoanAmount); + + vm.prank(address(recipient)); + recipient.executeFlashLoan(flashLoanAmount, '0x'); + + // Verify post-loan state + uint256 recipientPostBalance = osToken.balanceOf(address(recipient)); + uint256 flashLoansPostBalance = osToken.balanceOf(_osTokenFlashLoans); + + // Flash loan contract's balance should be unchanged + // (It mints tokens, receives repayment, then burns the tokens) + assertEq( + flashLoansPostBalance, + flashLoansPreBalance, + 'Flash loans contract balance should remain the same' + ); + + // Recipient's balance should be reduced by the loan amount + // (It repays the loan from its own balance) + assertEq( + recipientPostBalance, + recipientPreBalance, + 'Recipient should have the same balance after repaying the loan' + ); + } + + function test_flashLoan_failure() public { + // Configure recipient to NOT repay the loan + recipient.setShouldRepayLoan(false); + + uint256 flashLoanAmount = 100 ether; + + // Execute flash loan - should revert because loan isn't repaid + vm.prank(address(recipient)); + vm.expectRevert(Errors.FlashLoanFailed.selector); + recipient.executeFlashLoan(flashLoanAmount, '0x'); + } + + function test_flashLoan_zeroAmount() public { + // Try to execute flash loan with 0 amount - should revert + vm.prank(address(recipient)); + vm.expectRevert(Errors.InvalidShares.selector); + recipient.executeFlashLoan(0, '0x'); + } + + function test_flashLoan_excessiveAmount() public { + // Try to execute flash loan with more than the max amount - should revert + uint256 excessiveAmount = MAX_FLASH_LOAN_AMOUNT + 1; + + vm.prank(address(recipient)); + vm.expectRevert(Errors.InvalidShares.selector); + recipient.executeFlashLoan(excessiveAmount, '0x'); + } + + function test_flashLoan_withUserData() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + uint256 flashLoanAmount = 100 ether; + bytes memory userData = abi.encode('test data'); + + // Execute flash loan with user data + vm.prank(address(recipient)); + recipient.executeFlashLoan(flashLoanAmount, userData); + + // Test passes if the loan executes without reverting + // (We can't easily verify the userData was received correctly without modifying the recipient) + } + + function test_flashLoan_maxAmount() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + // Ensure recipient has enough tokens to repay max loan + _mintOsToken(address(recipient), MAX_FLASH_LOAN_AMOUNT); + + // Execute flash loan with maximum allowed amount + vm.prank(address(recipient)); + recipient.executeFlashLoan(MAX_FLASH_LOAN_AMOUNT, '0x'); + + // Test passes if the loan executes without reverting + } + + function test_flashLoan_reentrancy() public { + // Create a malicious recipient that attempts re-entrancy + MaliciousRecipient malicious = new MaliciousRecipient(_osToken, _osTokenFlashLoans); + + // Mint tokens to the malicious recipient for repayment + _mintOsToken(address(recipient), 1000 ether); + + // Attempt the attack - should fail due to nonReentrant modifier + vm.prank(address(malicious)); + vm.expectRevert(); // Either a custom error or a low-level revert + malicious.executeAttack(100 ether); + } + + function test_flashLoan_gasUsage() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + uint256 flashLoanAmount = 100 ether; + + // Measure gas usage + vm.prank(address(recipient)); + uint256 gasStart = gasleft(); + recipient.executeFlashLoan(flashLoanAmount, '0x'); + uint256 gasUsed = gasStart - gasleft(); + + // Optional: assert gas usage is below a reasonable threshold + assertLt(gasUsed, 300000, 'Flash loan gas usage should be reasonable'); + } +} + +// A malicious recipient that attempts to perform a re-entrancy attack +contract MaliciousRecipient is IOsTokenFlashLoanRecipient { + address public osToken; + address public flashLoanContract; + bool public attacking; + + constructor(address _osToken, address _flashLoanContract) { + osToken = _osToken; + flashLoanContract = _flashLoanContract; + } + + function executeAttack(uint256 amount) external { + OsTokenFlashLoans(flashLoanContract).flashLoan(amount, '0x'); + } + + function receiveFlashLoan(uint256 osTokenShares, bytes calldata) external override { + require(msg.sender == flashLoanContract, 'Caller is not flash loan contract'); + + if (!attacking) { + attacking = true; + + // Try to call flashLoan again (re-entrancy attempt) + OsTokenFlashLoans(flashLoanContract).flashLoan(osTokenShares, '0x'); + + attacking = false; + } + + // Repay the original loan + IERC20(osToken).transfer(msg.sender, osTokenShares); + } +} diff --git a/test/OwnMevEscrow.spec.ts b/test/OwnMevEscrow.spec.ts deleted file mode 100644 index aea75a7b..00000000 --- a/test/OwnMevEscrow.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ethers } from 'hardhat' -import { ContractFactory, Wallet } from 'ethers' -import { OwnMevEscrow__factory } from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { expect } from './shared/expect' - -describe('OwnMevEscrow', () => { - let ownMevEscrowFactory: ContractFactory - let vault: Wallet, other: Wallet - - before(async () => { - ;[vault, other] = await (ethers as any).getSigners() - ownMevEscrowFactory = await ethers.getContractFactory('OwnMevEscrow') - }) - - it('vault deployment gas', async () => { - const contract = await ownMevEscrowFactory.deploy(await vault.getAddress()) - await snapshotGasCost(contract.deploymentTransaction() as any) - }) - - it('only vault can withdraw assets', async () => { - const tx = await ethers.deployContract('OwnMevEscrow', [await vault.getAddress()]) - const contract = await tx.waitForDeployment() - const ownMevEscrow = OwnMevEscrow__factory.connect(await contract.getAddress(), other) - await expect(ownMevEscrow.connect(other).harvest()).to.be.revertedWithCustomError( - ownMevEscrow, - 'HarvestFailed' - ) - }) - - it('emits event on transfers', async () => { - const value = ethers.parseEther('1') - const tx = await ethers.deployContract('OwnMevEscrow', [await vault.getAddress()]) - const contract = await tx.waitForDeployment() - const ownMevEscrow = OwnMevEscrow__factory.connect(await contract.getAddress(), other) - - await expect( - other.sendTransaction({ - to: await ownMevEscrow.getAddress(), - value: value, - }) - ) - .to.be.emit(ownMevEscrow, 'MevReceived') - .withArgs(value) - }) -}) diff --git a/test/OwnMevEscrow.t.sol b/test/OwnMevEscrow.t.sol new file mode 100644 index 00000000..32ee7e68 --- /dev/null +++ b/test/OwnMevEscrow.t.sol @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {OwnMevEscrow} from '../contracts/vaults/ethereum/mev/OwnMevEscrow.sol'; +import {IVaultEthStaking} from '../contracts/interfaces/IVaultEthStaking.sol'; +import {IOwnMevEscrow} from '../contracts/interfaces/IOwnMevEscrow.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; + +contract OwnMevEscrowTest is Test, EthHelpers { + ForkContracts public contracts; + OwnMevEscrow public escrow; + EthVault public vault; + address public user; + address public admin; + + function setUp() public { + // Activate Ethereum fork + contracts = _activateEthereumFork(); + + // Setup test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault with own MEV escrow + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, true); + vault = EthVault(payable(vaultAddr)); + + // Get the vault's own MEV escrow + escrow = OwnMevEscrow(payable(vault.mevEscrow())); + } + + // Test 1: Verify initialization + function test_initialization() public view { + assertEq(escrow.vault(), address(vault), 'Vault address should match'); + } + + // Test 2: Receive ETH and emit event + function test_receiveMev() public { + uint256 sendAmount = 1 ether; + + // Expect MevReceived event + vm.expectEmit(true, true, true, true); + emit IOwnMevEscrow.MevReceived(sendAmount); + + // Send ETH to the escrow + vm.prank(user); + _startSnapshotGas('OwnMevEscrowTest_test_receiveMev'); + (bool success, ) = address(escrow).call{value: sendAmount}(''); + _stopSnapshotGas(); + assertTrue(success, 'Transfer to escrow failed'); + + // Verify balance + assertEq(address(escrow).balance, sendAmount, 'Escrow balance should be updated'); + } + + // Test 3: Successful harvest + function test_harvest_fromVault() public { + // Send ETH to the escrow + uint256 sendAmount = 1 ether; + vm.prank(user); + (bool success, ) = address(escrow).call{value: sendAmount}(''); + assertTrue(success, 'Transfer to escrow failed'); + + // Get initial vault balance + uint256 initialVaultBalance = address(vault).balance; + + // Expect Harvested event + vm.expectEmit(true, true, true, true); + emit IOwnMevEscrow.Harvested(sendAmount); + + // Harvest from vault + vm.prank(address(vault)); + _startSnapshotGas('OwnMevEscrowTest_test_harvest_fromVault'); + uint256 harvested = escrow.harvest(); + _stopSnapshotGas(); + + // Verify harvested amount + assertEq(harvested, sendAmount, 'Harvest should return correct amount'); + + // Verify escrow balance is zero + assertEq(address(escrow).balance, 0, 'Escrow balance should be zero after harvest'); + + // Verify vault balance increased + assertEq( + address(vault).balance, + initialVaultBalance + sendAmount, + 'Vault balance should increase' + ); + } + + // Test 4: Failed harvest from non-vault + function test_harvest_fromNonVault() public { + // Send ETH to the escrow + uint256 sendAmount = 1 ether; + vm.prank(user); + (bool success, ) = address(escrow).call{value: sendAmount}(''); + assertTrue(success, 'Transfer to escrow failed'); + + // Try to harvest from non-vault account + vm.prank(user); + _startSnapshotGas('OwnMevEscrowTest_test_harvest_fromNonVault'); + vm.expectRevert(Errors.HarvestFailed.selector); + escrow.harvest(); + _stopSnapshotGas(); + + // Verify escrow balance unchanged + assertEq(address(escrow).balance, sendAmount, 'Escrow balance should remain unchanged'); + } + + // Test 5: Harvest with zero balance + function test_harvest_zeroBalance() public { + // Verify escrow has zero balance initially + assertEq(address(escrow).balance, 0, 'Escrow should start with zero balance'); + + // Harvest from vault with zero balance + vm.prank(address(vault)); + _startSnapshotGas('OwnMevEscrowTest_test_harvest_zeroBalance'); + uint256 harvested = escrow.harvest(); + _stopSnapshotGas(); + + // Verify returned zero + assertEq(harvested, 0, 'Harvest should return zero for empty escrow'); + } + + // Test 6: Multiple harvests + function test_multipleHarvests() public { + // Send ETH to the escrow multiple times + uint256 firstAmount = 1 ether; + vm.prank(user); + (bool success1, ) = address(escrow).call{value: firstAmount}(''); + assertTrue(success1, 'First transfer to escrow failed'); + + // Harvest first time + vm.prank(address(vault)); + uint256 firstHarvest = escrow.harvest(); + assertEq(firstHarvest, firstAmount, 'First harvest amount incorrect'); + + // Send more ETH + uint256 secondAmount = 2 ether; + vm.prank(user); + (bool success2, ) = address(escrow).call{value: secondAmount}(''); + assertTrue(success2, 'Second transfer to escrow failed'); + + // Harvest second time + vm.prank(address(vault)); + _startSnapshotGas('OwnMevEscrowTest_test_multipleHarvests'); + uint256 secondHarvest = escrow.harvest(); + _stopSnapshotGas(); + assertEq(secondHarvest, secondAmount, 'Second harvest amount incorrect'); + } + + // Test 7: Multiple senders + function test_multipleSenders() public { + // Create another user + address anotherUser = makeAddr('anotherUser'); + vm.deal(anotherUser, 5 ether); + + // Send ETH from multiple accounts + uint256 firstAmount = 1 ether; + vm.prank(user); + (bool success1, ) = address(escrow).call{value: firstAmount}(''); + assertTrue(success1, 'First transfer to escrow failed'); + + uint256 secondAmount = 2 ether; + vm.prank(anotherUser); + (bool success2, ) = address(escrow).call{value: secondAmount}(''); + assertTrue(success2, 'Second transfer to escrow failed'); + + // Verify escrow balance is the sum of both transfers + assertEq(address(escrow).balance, firstAmount + secondAmount, 'Escrow balance incorrect'); + + // Harvest all funds at once + vm.prank(address(vault)); + _startSnapshotGas('OwnMevEscrowTest_test_multipleSenders'); + uint256 harvested = escrow.harvest(); + _stopSnapshotGas(); + + // Verify harvested the total amount + assertEq(harvested, firstAmount + secondAmount, 'Harvested amount incorrect'); + } + + // Test 8: Create escrow directly + function test_createEscrowDirectly() public { + address newVault = makeAddr('newVault'); + + // Create a new escrow with newVault as the vault address + OwnMevEscrow newEscrow = new OwnMevEscrow(newVault); + + // Verify initialization + assertEq(newEscrow.vault(), newVault, 'New escrow vault address incorrect'); + } +} diff --git a/test/PriceFeed.t.sol b/test/PriceFeed.t.sol new file mode 100644 index 00000000..938cd10b --- /dev/null +++ b/test/PriceFeed.t.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {PriceFeed} from '../contracts/tokens/PriceFeed.sol'; +import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; +import {IChainlinkAggregator} from '../contracts/interfaces/IChainlinkAggregator.sol'; +import {IChainlinkV3Aggregator} from '../contracts/interfaces/IChainlinkV3Aggregator.sol'; +import {IBalancerRateProvider} from '../contracts/interfaces/IBalancerRateProvider.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract PriceFeedTest is Test, EthHelpers { + // Test contracts + PriceFeed public priceFeed; + IOsTokenVaultController public osTokenVaultController; + + // Test addresses + address public user; + + // Fork contracts + ForkContracts public contracts; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + osTokenVaultController = contracts.osTokenVaultController; + + // Set up test accounts + user = makeAddr('user'); + + // Deploy the PriceFeed contract + priceFeed = new PriceFeed(address(osTokenVaultController), 'StakeWise osETH/ETH Price Feed'); + } + + // Test constructor and initialization + function test_constructor() public view { + assertEq( + priceFeed.osTokenVaultController(), + address(osTokenVaultController), + 'OsTokenVaultController address not set correctly' + ); + assertEq( + priceFeed.description(), + 'StakeWise osETH/ETH Price Feed', + 'Description not set correctly' + ); + assertEq(priceFeed.version(), 0, 'Version should be 0'); + } + + // Test getRate function (Balancer interface) + function test_getRate() public view { + uint256 rate = priceFeed.getRate(); + + // Get the expected rate directly from the vault controller + uint256 expectedRate = osTokenVaultController.convertToAssets(10 ** priceFeed.decimals()); + + assertEq(rate, expectedRate, 'Rate should match osTokenVaultController.convertToAssets'); + } + + // Test getRate with gas snapshot + function test_getRate_gas() public { + _startSnapshotGas('PriceFeedTest_test_getRate_gas'); + priceFeed.getRate(); + _stopSnapshotGas(); + } + + // Test latestAnswer function (Chainlink interface) + function test_latestAnswer() public view { + int256 answer = priceFeed.latestAnswer(); + + // Get the expected rate directly from the vault controller + uint256 expectedRate = osTokenVaultController.convertToAssets(10 ** priceFeed.decimals()); + + assertEq(answer, int256(expectedRate), 'Answer should match the rate from getRate()'); + } + + // Test latestAnswer with gas snapshot + function test_latestAnswer_gas() public { + _startSnapshotGas('PriceFeedTest_test_latestAnswer_gas'); + priceFeed.latestAnswer(); + _stopSnapshotGas(); + } + + // Test latestTimestamp function + function test_latestTimestamp() public view { + uint256 timestamp = priceFeed.latestTimestamp(); + assertEq(timestamp, block.timestamp, 'Timestamp should be the current block timestamp'); + } + + // Test decimals function + function test_decimals() public view { + uint8 dec = priceFeed.decimals(); + assertEq(dec, 18, 'Decimals should be 18'); + } + + // Test latestRoundData function (Chainlink V3 interface) + function test_latestRoundData() public view { + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) = priceFeed.latestRoundData(); + + // Check return values + assertEq(roundId, 0, 'RoundId should be 0'); + + int256 expectedAnswer = priceFeed.latestAnswer(); + assertEq(answer, expectedAnswer, 'Answer should match latestAnswer()'); + + assertEq(startedAt, block.timestamp, 'StartedAt should be current block timestamp'); + assertEq(updatedAt, block.timestamp, 'UpdatedAt should be current block timestamp'); + assertEq(answeredInRound, 0, 'AnsweredInRound should be 0'); + } + + // Test latestRoundData with gas snapshot + function test_latestRoundData_gas() public { + _startSnapshotGas('PriceFeedTest_test_latestRoundData_gas'); + priceFeed.latestRoundData(); + _stopSnapshotGas(); + } + + // Test consistency between different interface methods + function test_interfaceConsistency() public view { + uint256 balancerRate = priceFeed.getRate(); + int256 chainlinkAnswer = priceFeed.latestAnswer(); + + assertEq( + int256(balancerRate), + chainlinkAnswer, + 'Balancer rate and Chainlink answer should be consistent' + ); + + (, int256 roundDataAnswer, , , ) = priceFeed.latestRoundData(); + + assertEq( + chainlinkAnswer, + roundDataAnswer, + 'Chainlink answer and round data answer should be consistent' + ); + } + + // Test timestamp consistency across methods + function test_timestampConsistency() public view { + uint256 timestamp = priceFeed.latestTimestamp(); + + (, , uint256 startedAt, uint256 updatedAt, ) = priceFeed.latestRoundData(); + + assertEq( + timestamp, + block.timestamp, + 'Timestamp from latestTimestamp should be block.timestamp' + ); + assertEq(startedAt, block.timestamp, 'StartedAt should be block.timestamp'); + assertEq(updatedAt, block.timestamp, 'UpdatedAt should be block.timestamp'); + } +} diff --git a/test/RewardSplitterFactory.spec.ts b/test/RewardSplitterFactory.spec.ts deleted file mode 100644 index 347e459f..00000000 --- a/test/RewardSplitterFactory.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - RewardSplitterFactory__factory, - RewardSplitter__factory, - RewardSplitterFactory, -} from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { createRewardSplitterFactory, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' - -describe('RewardSplitterFactory', () => { - let admin: Wallet - let vault: EthVault, rewardSplitterFactory: RewardSplitterFactory - - before('create fixture loader', async () => { - ;[admin] = (await (ethers as any).getSigners()).slice(1, 2) - }) - - beforeEach(async () => { - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthVault(admin, { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - }) - rewardSplitterFactory = await createRewardSplitterFactory() - }) - - it('splitter deployment gas', async () => { - const receipt = await rewardSplitterFactory - .connect(admin) - .createRewardSplitter(await vault.getAddress()) - await snapshotGasCost(receipt) - }) - - it('factory deploys correctly', async () => { - let factory = await ethers.getContractFactory('RewardSplitter') - const rewardSplitterImpl = await factory.deploy() - const rewardSplitterImplAddress = await rewardSplitterImpl.getAddress() - - factory = await ethers.getContractFactory('RewardSplitterFactory') - const rewardsFactory = RewardSplitterFactory__factory.connect( - await (await factory.deploy(rewardSplitterImplAddress)).getAddress(), - admin - ) - expect(await rewardsFactory.implementation()).to.eq(rewardSplitterImplAddress) - }) - - it('splitter deploys correctly', async () => { - const rewardSplitterAddress = await rewardSplitterFactory - .connect(admin) - .createRewardSplitter.staticCall(await vault.getAddress()) - const receipt = await rewardSplitterFactory - .connect(admin) - .createRewardSplitter(await vault.getAddress()) - await expect(receipt) - .to.emit(rewardSplitterFactory, 'RewardSplitterCreated') - .withArgs(admin.address, await vault.getAddress(), rewardSplitterAddress) - - const rewardSplitter = RewardSplitter__factory.connect(rewardSplitterAddress, admin) - expect(await rewardSplitter.vault()).to.eq(await vault.getAddress()) - expect(await rewardSplitter.owner()).to.eq(admin.address) - expect(await rewardSplitter.totalShares()).to.eq(0) - }) -}) diff --git a/test/SharedMevEscrow.spec.ts b/test/SharedMevEscrow.spec.ts deleted file mode 100644 index b4dc3887..00000000 --- a/test/SharedMevEscrow.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { SharedMevEscrow, VaultsRegistry } from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { expect } from './shared/expect' - -import { ethVaultFixture } from './shared/fixtures' - -describe('SharedMevEscrow', () => { - let other: Wallet, sharedMevEscrow: SharedMevEscrow, vaultsRegistry: VaultsRegistry - - beforeEach('deploy fixture', async () => { - ;[other] = (await (ethers as any).getSigners()).slice(1, 2) - ;({ sharedMevEscrow, vaultsRegistry } = await loadFixture(ethVaultFixture)) - }) - - it('vault deployment gas', async () => { - const sharedMevEscrowFactory = await ethers.getContractFactory('SharedMevEscrow') - const tx = await sharedMevEscrowFactory.deploy(await vaultsRegistry.getAddress()) - await snapshotGasCost(tx.deploymentTransaction() as any) - }) - - it('only vault can withdraw assets', async () => { - await expect( - sharedMevEscrow.connect(other).harvest(ethers.parseEther('1')) - ).to.be.revertedWithCustomError(sharedMevEscrow, 'HarvestFailed') - }) - - it('emits event on transfers', async () => { - const value = ethers.parseEther('1') - - await expect( - other.sendTransaction({ - to: await sharedMevEscrow.getAddress(), - value: value, - }) - ) - .to.be.emit(sharedMevEscrow, 'MevReceived') - .withArgs(value) - }) -}) diff --git a/test/SharedMevEscrow.t.sol b/test/SharedMevEscrow.t.sol new file mode 100644 index 00000000..05c49bac --- /dev/null +++ b/test/SharedMevEscrow.t.sol @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; +import {SharedMevEscrow} from '../contracts/vaults/ethereum/mev/SharedMevEscrow.sol'; +import {ISharedMevEscrow} from '../contracts/interfaces/ISharedMevEscrow.sol'; +import {IVaultEthStaking} from '../contracts/interfaces/IVaultEthStaking.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; + +// Mock VaultEthStaking for testing +contract MockVaultEthStaking { + uint256 public receivedAmount; + + function receiveFromMevEscrow() external payable { + receivedAmount += msg.value; + } +} + +// Mock non-compliant vault that doesn't implement receiveFromMevEscrow +contract MockNonCompliantVault { + // No receiveFromMevEscrow function +} + +contract SharedMevEscrowTest is Test { + VaultsRegistry public vaultsRegistry; + SharedMevEscrow public mevEscrow; + + address public owner; + MockVaultEthStaking public registeredVault; + address public nonRegisteredAccount; + MockNonCompliantVault public nonCompliantVault; + address public mevSender; + + uint256 public mevAmount = 1 ether; + + function setUp() public { + // Setup test accounts + owner = makeAddr('owner'); + nonRegisteredAccount = makeAddr('nonRegisteredAccount'); + mevSender = makeAddr('mevSender'); + + // Fund accounts + vm.deal(mevSender, 10 ether); + + // Deploy VaultsRegistry + vm.prank(owner); + vaultsRegistry = new VaultsRegistry(); + + // Deploy mock vaults + registeredVault = new MockVaultEthStaking(); + nonCompliantVault = new MockNonCompliantVault(); + + // Register compliant vault + vm.prank(owner); + vaultsRegistry.addVault(address(registeredVault)); + + // Register non-compliant vault + vm.prank(owner); + vaultsRegistry.addVault(address(nonCompliantVault)); + + // Deploy SharedMevEscrow + mevEscrow = new SharedMevEscrow(address(vaultsRegistry)); + } + + function test_initialization() public view { + // Verify the VaultsRegistry is set correctly + assertTrue(address(vaultsRegistry) != address(0), 'VaultsRegistry should be set'); + } + + function test_receiveMev() public { + // Initial balance + uint256 initialBalance = address(mevEscrow).balance; + + // Expect MevReceived event + vm.expectEmit(true, true, true, true); + emit ISharedMevEscrow.MevReceived(mevAmount); + + // Send MEV to escrow + vm.prank(mevSender); + (bool success, ) = address(mevEscrow).call{value: mevAmount}(''); + + // Verify transfer successful + assertTrue(success, 'MEV transfer should succeed'); + assertEq( + address(mevEscrow).balance, + initialBalance + mevAmount, + 'MEV escrow balance should increase' + ); + } + + function test_harvest_registered() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Expect Harvested event + vm.expectEmit(true, true, true, true); + emit ISharedMevEscrow.Harvested(address(registeredVault), mevAmount); + + // Harvest MEV + vm.prank(address(registeredVault)); + mevEscrow.harvest(mevAmount); + + // Verify successful harvest + assertEq(registeredVault.receivedAmount(), mevAmount, 'Vault should receive MEV'); + assertEq(address(mevEscrow).balance, 0, 'MEV escrow should be empty after harvest'); + } + + function test_harvest_nonRegistered() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Attempt to harvest from non-registered account + vm.prank(nonRegisteredAccount); + vm.expectRevert(Errors.HarvestFailed.selector); + mevEscrow.harvest(mevAmount); + + // Verify no MEV was harvested + assertEq(address(mevEscrow).balance, mevAmount, 'MEV escrow balance should remain unchanged'); + } + + function test_harvest_nonCompliantVault() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Attempt to harvest from non-compliant vault + // This should revert because the vault doesn't implement receiveFromMevEscrow + vm.prank(address(nonCompliantVault)); + vm.expectRevert(); + mevEscrow.harvest(mevAmount); + + // Verify no MEV was harvested + assertEq(address(mevEscrow).balance, mevAmount, 'MEV escrow balance should remain unchanged'); + } + + function test_harvest_partialAmount() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Partial harvest + uint256 harvestAmount = mevAmount / 2; + + // Expect Harvested event + vm.expectEmit(true, true, true, true); + emit ISharedMevEscrow.Harvested(address(registeredVault), harvestAmount); + + // Harvest partial MEV + vm.prank(address(registeredVault)); + mevEscrow.harvest(harvestAmount); + + // Verify partial harvest + assertEq(registeredVault.receivedAmount(), harvestAmount, 'Vault should receive partial MEV'); + assertEq( + address(mevEscrow).balance, + mevAmount - harvestAmount, + 'MEV escrow should contain remaining MEV' + ); + } + + function test_harvest_multipleVaults() public { + // Deploy another mock vault + MockVaultEthStaking anotherVault = new MockVaultEthStaking(); + + // Register the another vault + vm.prank(owner); + vaultsRegistry.addVault(address(anotherVault)); + + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount * 2); + + // First vault harvests + vm.prank(address(registeredVault)); + mevEscrow.harvest(mevAmount); + + // Second vault harvests + vm.prank(address(anotherVault)); + mevEscrow.harvest(mevAmount); + + // Verify both harvests + assertEq(registeredVault.receivedAmount(), mevAmount, 'First vault should receive MEV'); + assertEq(anotherVault.receivedAmount(), mevAmount, 'Second vault should receive MEV'); + assertEq(address(mevEscrow).balance, 0, 'MEV escrow should be empty after both harvests'); + } + + function test_harvest_exceedBalance() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Attempt to harvest more than available + uint256 excessAmount = mevAmount * 2; + + // This should revert due to insufficient balance + vm.prank(address(registeredVault)); + vm.expectRevert(); + mevEscrow.harvest(excessAmount); + + // Verify no MEV was harvested + assertEq(registeredVault.receivedAmount(), 0, 'Vault should not receive any MEV'); + assertEq(address(mevEscrow).balance, mevAmount, 'MEV escrow balance should remain unchanged'); + } +} diff --git a/test/VaultAdmin.t.sol b/test/VaultAdmin.t.sol new file mode 100644 index 00000000..c2b96a4f --- /dev/null +++ b/test/VaultAdmin.t.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultAdmin} from "../contracts/interfaces/IVaultAdmin.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {CommonBase} from "../lib/forge-std/src/Base.sol"; +import {StdAssertions} from "../lib/forge-std/src/StdAssertions.sol"; +import {StdChains} from "../lib/forge-std/src/StdChains.sol"; +import {StdCheats, StdCheatsSafe} from "../lib/forge-std/src/StdCheats.sol"; +import {StdUtils} from "../lib/forge-std/src/StdUtils.sol"; +import {Test} from "../lib/forge-std/src/Test.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; + +contract VaultAdminTest is Test, EthHelpers { + ForkContracts public contracts; + address public vault; + + address public admin; + address public nonAdmin; + address public newAdmin; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + nonAdmin = makeAddr('nonAdmin'); + newAdmin = makeAddr('newAdmin'); + + // Create a vault with admin as the admin + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'initialIpfsHash' + }) + ); + vault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + } + + function test_initialization() public { + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'initialIpfsHash' + }) + ); + + _startSnapshotGas('VaultAdminTest_test_initialization'); + address newVault = _createVault(VaultType.EthVault, admin, initParams, false); + _stopSnapshotGas(); + + assertEq( + IVaultAdmin(newVault).admin(), + admin, + 'Admin should be set correctly during initialization' + ); + } + + function test_initialAdmin() public view { + assertEq(IVaultAdmin(vault).admin(), admin, 'Initial admin should be set correctly'); + } + + function test_setAdmin_byAdmin() public { + // Expect the AdminUpdated event + vm.expectEmit(true, true, false, false); + emit IVaultAdmin.AdminUpdated(admin, newAdmin); + + // Call setAdmin as the current admin + vm.prank(admin); + _startSnapshotGas('VaultAdminTest_test_setAdmin_byAdmin'); + IVaultAdmin(vault).setAdmin(newAdmin); + _stopSnapshotGas(); + + // Verify admin was updated + assertEq(IVaultAdmin(vault).admin(), newAdmin, 'Admin should be updated'); + } + + function test_setAdmin_byNonAdmin() public { + // Call setAdmin as a non-admin user + vm.prank(nonAdmin); + _startSnapshotGas('VaultAdminTest_test_setAdmin_byNonAdmin'); + vm.expectRevert(Errors.AccessDenied.selector); + IVaultAdmin(vault).setAdmin(newAdmin); + _stopSnapshotGas(); + + // Verify admin was not changed + assertEq(IVaultAdmin(vault).admin(), admin, 'Admin should not be changed by non-admin'); + } + + function test_setAdmin_toZeroAddress() public { + // Call setAdmin with zero address + vm.prank(admin); + _startSnapshotGas('VaultAdminTest_test_setAdmin_toZeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + IVaultAdmin(vault).setAdmin(address(0)); + _stopSnapshotGas(); + + // Verify admin was not changed + assertEq(IVaultAdmin(vault).admin(), admin, 'Admin should not be changed to zero address'); + } + + function test_setMetadata_byAdmin() public { + string memory newMetadata = 'newIpfsHash'; + + // Expect the MetadataUpdated event + vm.expectEmit(true, false, false, false); + emit IVaultAdmin.MetadataUpdated(admin, newMetadata); + + // Call setMetadata as the admin + vm.prank(admin); + _startSnapshotGas('VaultAdminTest_test_setMetadata_byAdmin'); + IVaultAdmin(vault).setMetadata(newMetadata); + _stopSnapshotGas(); + } + + function test_setMetadata_byNonAdmin() public { + string memory newMetadata = 'newIpfsHash'; + + // Call setMetadata as a non-admin user + vm.prank(nonAdmin); + _startSnapshotGas('VaultAdminTest_test_setMetadata_byNonAdmin'); + vm.expectRevert(Errors.AccessDenied.selector); + IVaultAdmin(vault).setMetadata(newMetadata); + _stopSnapshotGas(); + } + + function test_checkAdmin_withOtherFunctions() public { + // Test some other functions that use _checkAdmin internally + + // Set fee recipient (from VaultFee which uses _checkAdmin) + vm.prank(nonAdmin); + _startSnapshotGas('VaultAdminTest_test_checkAdmin_withOtherFunctions_nonAdmin'); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).setFeeRecipient(nonAdmin); + _stopSnapshotGas(); + + // Now try as admin + vm.prank(admin); + _startSnapshotGas('VaultAdminTest_test_checkAdmin_withOtherFunctions_admin'); + IEthVault(vault).setFeeRecipient(admin); + _stopSnapshotGas(); + + // Verify fee recipient was updated + assertEq(IEthVault(vault).feeRecipient(), admin, 'Fee recipient should be updated by admin'); + } +} diff --git a/test/VaultEnterExit.t.sol b/test/VaultEnterExit.t.sol new file mode 100644 index 00000000..c6fe789d --- /dev/null +++ b/test/VaultEnterExit.t.sol @@ -0,0 +1,788 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract VaultEnterExitTest is Test, EthHelpers { + ForkContracts public contracts; + EthVault public vault; + + address public sender; + address public sender2; + address public receiver; + address public admin; + address public referrer = address(0); + + uint256 public depositAmount = 1 ether; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + sender2 = makeAddr('sender2'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(sender2, 100 ether); + vm.deal(admin, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + vm.deal( + vaultAddr, + vault.convertToAssets(vault.queuedShares()) + vault.totalExitingAssets() + vaultAddr.balance + ); + } + + function test_deposit_zeroAddress() public { + // Try to deposit to address(0) + vm.prank(sender); + vm.expectRevert(Errors.ZeroAddress.selector); + _startSnapshotGas('VaultEnterExitTest_test_deposit_zeroAddress'); + vault.deposit{value: depositAmount}(address(0), referrer); + _stopSnapshotGas(); + } + + function test_deposit_zeroAmount() public { + // Try to deposit 0 ETH + vm.prank(sender); + vm.expectRevert(Errors.InvalidAssets.selector); + _startSnapshotGas('VaultEnterExitTest_test_deposit_zeroAmount'); + vault.deposit{value: 0}(receiver, referrer); + _stopSnapshotGas(); + } + + function test_deposit_exceedingCapacity() public { + // Create a new vault with a small capacity + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 33 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault smallVault = EthVault(payable(vaultAddr)); + + // First deposit an amount under capacity + _depositToVault(address(smallVault), 32 ether, sender, sender); + + // Then try to deposit an amount that would exceed capacity + vm.prank(sender); + vm.expectRevert(Errors.CapacityExceeded.selector); + _startSnapshotGas('VaultEnterExitTest_test_deposit_exceedingCapacity'); + smallVault.deposit{value: 1.1 ether}(sender, referrer); + _stopSnapshotGas(); + } + + function test_deposit_success_basic() public { + // Record initial balances and state + uint256 senderBalanceBefore = sender.balance; + uint256 vaultBalanceBefore = address(vault).balance; + uint256 totalSharesBefore = vault.totalShares(); + uint256 totalAssetsBefore = vault.totalAssets(); + + // Perform the deposit + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_deposit_success_basic'); + uint256 shares = vault.deposit{value: depositAmount}(sender, referrer); + _stopSnapshotGas(); + + // Verify ETH was transferred correctly + assertEq( + sender.balance, + senderBalanceBefore - depositAmount, + "Sender's ETH balance should decrease" + ); + assertEq( + address(vault).balance, + vaultBalanceBefore + depositAmount, + "Vault's ETH balance should increase" + ); + + // Verify shares were minted correctly + assertEq(vault.getShares(sender), shares, 'Sender should receive the correct number of shares'); + assertEq( + vault.totalShares(), + totalSharesBefore + shares, + 'Total shares should increase by the minted amount' + ); + assertEq( + vault.totalAssets(), + totalAssetsBefore + depositAmount, + 'Total assets should increase by deposit amount' + ); + + // Verify the conversion between assets and shares + assertEq( + vault.convertToAssets(shares), + depositAmount, + 'Shares should convert back to the deposited amount' + ); + } + + function test_deposit_success_differentReceiver() public { + // Record initial balances and state + uint256 senderSharesBefore = vault.getShares(sender); + uint256 receiverSharesBefore = vault.getShares(receiver); + + // Perform the deposit with a different receiver + uint256 depositAssets = 1.5 ether; + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_deposit_success_differentReceiver'); + uint256 shares = vault.deposit{value: depositAssets}(receiver, referrer); + _stopSnapshotGas(); + + // Verify shares were minted to the receiver, not the sender + assertEq(vault.getShares(sender), senderSharesBefore, "Sender's shares should not change"); + assertEq( + vault.getShares(receiver), + receiverSharesBefore + shares, + 'Receiver should get the minted shares' + ); + } + + function test_deposit_success_multipleDeposits() public { + // First deposit + uint256 firstDeposit = 1 ether; + vm.prank(sender); + uint256 firstShares = vault.deposit{value: firstDeposit}(sender, referrer); + + // Second deposit + uint256 secondDeposit = 2 ether; + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_deposit_success_multipleDeposits'); + uint256 secondShares = vault.deposit{value: secondDeposit}(sender, referrer); + _stopSnapshotGas(); + + // Check the relationship between deposits + // Second deposit is 2x the first, so should get approximately 2x the shares + // (allowing for minor differences due to rounding or fees) + assertApproxEqRel( + secondShares, + firstShares * 2, + 0.01e18, // 1% tolerance + 'Second deposit should get proportional shares relative to the first deposit' + ); + + // Verify total shares + assertEq( + vault.getShares(sender), + firstShares + secondShares, + 'Total shares should be the sum of both deposits' + ); + } + + function test_deposit_success_withReferrer() public { + // Set up a referrer + address validReferrer = makeAddr('referrer'); + + // Record initial balances and state + uint256 senderBalanceBefore = sender.balance; + uint256 vaultBalanceBefore = address(vault).balance; + + // Perform the deposit with a referrer + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_deposit_success_withReferrer'); + uint256 shares = vault.deposit{value: depositAmount}(sender, validReferrer); + _stopSnapshotGas(); + + // Verify deposit succeeded with referrer + assertEq( + sender.balance, + senderBalanceBefore - depositAmount, + "Sender's ETH balance should decrease" + ); + assertEq( + address(vault).balance, + vaultBalanceBefore + depositAmount, + "Vault's ETH balance should increase" + ); + assertEq(vault.getShares(sender), shares, 'Sender should receive the correct number of shares'); + + // Note: In a real implementation, we might want to check for referral tracking or rewards, + // but the current contract doesn't seem to have specific referrer handling beyond the event + } + + function test_deposit_success_receiveFunction() public { + // Record initial balances and state + uint256 senderBalanceBefore = sender.balance; + uint256 vaultBalanceBefore = address(vault).balance; + uint256 senderSharesBefore = vault.getShares(sender); + + // Deposit using the receive function (direct transfer) + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_deposit_success_receiveFunction'); + (bool success, ) = address(vault).call{value: depositAmount}(''); + _stopSnapshotGas(); + + // Verify transfer succeeded + assertTrue(success, 'Direct transfer should succeed'); + + // Verify ETH was transferred correctly + assertEq( + sender.balance, + senderBalanceBefore - depositAmount, + "Sender's ETH balance should decrease" + ); + assertEq( + address(vault).balance, + vaultBalanceBefore + depositAmount, + "Vault's ETH balance should increase" + ); + + // Verify shares were minted to the sender + assertGt(vault.getShares(sender), senderSharesBefore, 'Sender should receive shares'); + } + + function test_enterExitQueue_basicFlow() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Collateralize the vault (required for exit queue to work with actual validators) + _collateralizeEthVault(address(vault)); + + // 3. Enter exit queue + uint256 shares = vault.getShares(sender); + uint256 queuedSharesBefore = vault.queuedShares(); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_basicFlow'); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + // 4. Verify the position ticket was created and shares moved to the queue + assertEq( + vault.queuedShares(), + queuedSharesBefore + shares, + 'Queued shares should equal the shares sent to exit queue' + ); + assertEq(vault.getShares(sender), 0, 'Sender should have 0 shares after entering exit queue'); + + // 5. Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 7. Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); + + // 8. Calculate exited assets + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault + .calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + assertApproxEqAbs(leftTickets, 0, 1, 'All tickets should be processed'); + assertApproxEqAbs(exitedTickets, shares, 1, 'Exited tickets should equal the shares entered'); + assertApproxEqAbs( + exitedAssets, + depositAmount, + 1e9, + 'Exited assets should approximately equal deposit amount' + ); + + // 9. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + + vm.prank(receiver); + _startSnapshotGas('VaultEnterExitTest_test_claimExitedAssets'); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // 10. Verify assets were transferred to the receiver + uint256 receiverBalanceAfter = address(receiver).balance; + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets, + 'Receiver should have received the exited assets' + ); + } + + function test_enterExitQueue_directRedemption() public { + address _newVault = _createVault( + VaultType.EthVault, + admin, + abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ), + false + ); + IEthVault newVault = IEthVault(_newVault); + + // 1. Deposit ETH + _depositToVault(_newVault, depositAmount, sender, sender); + + // 2. Enter exit queue (without collateralizing the vault) + uint256 shares = newVault.getShares(sender); + uint256 assets = newVault.convertToAssets(shares); + + uint256 receiverBalanceBefore = address(receiver).balance; + + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_directRedemption'); + uint256 positionTicket = newVault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + // 3. Verify direct redemption occurred (max uint256 ticket indicates direct redemption) + assertEq( + positionTicket, + type(uint256).max, + 'Position ticket should be max uint256 for direct redemption' + ); + assertEq(newVault.getShares(sender), 0, 'Sender should have 0 shares after direct redemption'); + assertApproxEqAbs( + address(receiver).balance - receiverBalanceBefore, + assets, + 1e9, + 'Assets should be transferred directly to receiver' + ); + } + + function test_claimExitedAssets_insufficientDelay() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + + // 3. Enter exit queue + uint256 shares = vault.getShares(sender); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + + // 4. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 5. Try to claim before the delay has passed + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); + + vm.prank(receiver); + _startSnapshotGas('VaultEnterExitTest_test_claimExitedAssets_insufficientDelay'); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + } + + function test_enterExitQueue_invalidParams() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Try to enter exit queue with 0 shares + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroShares'); + vm.expectRevert(Errors.InvalidShares.selector); + vault.enterExitQueue(0, receiver); + _stopSnapshotGas(); + + // 3. Try to enter exit queue with zero address as receiver + uint256 sharesToExit = vault.getShares(sender); + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.enterExitQueue(sharesToExit, address(0)); + _stopSnapshotGas(); + + // 4. Try to enter exit queue with more shares than owned + uint256 shares = vault.getShares(sender); + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_invalidParams_tooManyShares'); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.enterExitQueue(shares + 1, receiver); + _stopSnapshotGas(); + } + + function test_calculateExitedAssets_invalidPosition() public { + // Try to calculate exited assets for a non-existent position + _startSnapshotGas('VaultEnterExitTest_test_calculateExitedAssets_invalidPosition'); + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault + .calculateExitedAssets( + receiver, + 999, // Non-existent position ticket + vm.getBlockTimestamp(), + 0 + ); + _stopSnapshotGas(); + + assertEq(leftTickets, 0, 'Left tickets should be 0 for non-existent position'); + assertEq(exitedTickets, 0, 'Exited tickets should be 0 for non-existent position'); + assertEq(exitedAssets, 0, 'Exited assets should be 0 for non-existent position'); + } + + function test_claimExitedAssets_invalidCheckpoint() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + + // 3. Enter exit queue + uint256 shares = vault.getShares(sender); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + + // 4. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 5. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 6. Try to claim with an invalid checkpoint index + vm.prank(receiver); + _startSnapshotGas('VaultEnterExitTest_test_claimExitedAssets_invalidCheckpoint'); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + vault.claimExitedAssets( + positionTicket, + timestamp, + 999 // Invalid checkpoint index + ); + _stopSnapshotGas(); + } + + function test_enterExitQueue_multiUser() public { + // 1. Both users deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + _depositToVault(address(vault), depositAmount * 2, sender2, sender2); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + + // 3. Both users enter exit queue + uint256 shares1 = vault.getShares(sender); + uint256 shares2 = vault.getShares(sender2); + uint256 queuedSharesBefore = vault.queuedShares(); + + vm.prank(sender); + uint256 timestamp1 = vm.getBlockTimestamp(); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_multiUser_user1'); + uint256 positionTicket1 = vault.enterExitQueue(shares1, receiver); + _stopSnapshotGas(); + + vm.prank(sender2); + uint256 timestamp2 = vm.getBlockTimestamp(); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_multiUser_sender2'); + uint256 positionTicket2 = vault.enterExitQueue(shares2, sender2); + _stopSnapshotGas(); + + // 4. Verify the queued shares + assertEq( + vault.queuedShares(), + queuedSharesBefore + shares1 + shares2, + 'Queued shares should equal the sum of all shares in exit queue' + ); + + // 5. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp2 + _exitingAssetsClaimDelay + 1); + + // 7. Both users claim their assets + int256 exitQueueIndex1 = vault.getExitQueueIndex(positionTicket1); + int256 exitQueueIndex2 = vault.getExitQueueIndex(positionTicket2); + + assertGt(exitQueueIndex1, -1, 'Exit queue index 1 should be valid'); + assertGt(exitQueueIndex2, -1, 'Exit queue index 2 should be valid'); + + (, , uint256 exitedAssets1) = vault.calculateExitedAssets( + receiver, + positionTicket1, + timestamp1, + uint256(exitQueueIndex1) + ); + + (, , uint256 exitedAssets2) = vault.calculateExitedAssets( + sender2, + positionTicket2, + timestamp2, + uint256(exitQueueIndex2) + ); + + // push down the stack + uint256 timestamp1_ = timestamp1; + uint256 timestamp2_ = timestamp2; + uint256 positionTicket1_ = positionTicket1; + uint256 positionTicket2_ = positionTicket2; + uint256 exitQueueIndex1_ = uint256(exitQueueIndex1); + uint256 exitQueueIndex2_ = uint256(exitQueueIndex2); + + uint256 receiverBalanceBefore = address(receiver).balance; + uint256 sender2BalanceBefore = address(sender2).balance; + + vm.prank(receiver); + vault.claimExitedAssets(positionTicket1_, timestamp1_, exitQueueIndex1_); + + vm.prank(sender2); + vault.claimExitedAssets(positionTicket2_, timestamp2_, exitQueueIndex2_); + + // 8. Verify assets were transferred to the respective receivers + uint256 receiverBalanceAfter = address(receiver).balance; + uint256 sender2BalanceAfter = address(sender2).balance; + + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets1, + 'Receiver should have received the correct exited assets' + ); + assertEq( + sender2BalanceAfter - sender2BalanceBefore, + exitedAssets2, + 'Sender2 should have received the correct exited assets' + ); + } + + function test_enterExitQueue_partialExit() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount * 2, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + uint256 queuedSharesBefore = vault.queuedShares(); + + // 3. Enter exit queue with half of the shares + uint256 totalShares = vault.getShares(sender); + uint256 halfShares = totalShares / 2; + + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_partialExit'); + uint256 positionTicket = vault.enterExitQueue(halfShares, receiver); + _stopSnapshotGas(); + + // 4. Verify the position ticket and remaining shares + assertEq( + vault.queuedShares(), + queuedSharesBefore + halfShares, + 'Queued shares should equal the half shares sent to exit queue' + ); + assertEq( + vault.getShares(sender), + halfShares, + 'Sender should have half of the original shares left' + ); + + // 5. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 7. Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); + + // 8. Calculate exited assets + (, , uint256 exitedAssets) = vault.calculateExitedAssets( + receiver, + positionTicket, + timestamp, + uint256(exitQueueIndex) + ); + + // 9. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + uint256 receiverBalanceAfter = address(receiver).balance; + + // 10. Verify assets were transferred to the receiver + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets, + 'Receiver should have received the exited assets' + ); + + // 11. Verify sender still has the remaining shares + assertEq( + vault.getShares(sender), + halfShares, + 'Sender should still have half of the original shares' + ); + } + + function test_enterExitQueue_afterValidatorExit() public { + // 1. Deposit ETH + _depositToVault(address(vault), 40 ether, sender, sender); + + // 2. Register a validator with 32 ETH + _registerEthValidator(address(vault), 32 ether, true); + + // 3. Simulate validator exit + vm.deal(address(vault), address(vault).balance + 32 ether); + + // 4. Enter exit queue + uint256 shares = vault.getShares(sender); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_afterValidatorExit'); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + // 5. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 7. Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); + + // 8. Calculate exited assets + (, , uint256 exitedAssets) = vault.calculateExitedAssets( + receiver, + positionTicket, + timestamp, + uint256(exitQueueIndex) + ); + + // 9. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + uint256 receiverBalanceAfter = address(receiver).balance; + + // 10. Verify assets were transferred to the receiver + assertApproxEqAbs( + exitedAssets, + 40 ether, + 1, + 'Receiver should have received at least the initial deposit' + ); + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets, + 'Receiver should have received the exited assets' + ); + } + + function test_enterExitQueue_multipleUpdates() public { + address _newVault = _createVault( + VaultType.EthVault, + admin, + abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ), + false + ); + IEthVault newVault = IEthVault(_newVault); + + // 1. Deposit a large amount of ETH + _depositToVault(_newVault, 100 ether, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(_newVault); + + // 3. Enter exit queue with all shares + uint256 shares = newVault.getShares(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + vm.prank(sender); + _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_multipleUpdates'); + uint256 positionTicket = newVault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + uint256 vaultBalanceBefore = _newVault.balance; + vm.deal(_newVault, 0); + + // 4. Process the exit queue in multiple updates + // First update with a penalty (to reduce the available assets) + IKeeperRewards.HarvestParams memory harvestParams1 = _setEthVaultReward( + _newVault, + int160(-30 ether), + 0 + ); + newVault.updateState(harvestParams1); + + // Second update with a reward + IKeeperRewards.HarvestParams memory harvestParams2 = _setEthVaultReward( + _newVault, + int160(15 ether), + 0 + ); + newVault.updateState(harvestParams2); + + // Final update with remaining balance + vm.deal(_newVault, vaultBalanceBefore); + IKeeperRewards.HarvestParams memory harvestParams3 = _setEthVaultReward( + _newVault, + int160(15 ether), + 0 + ); + newVault.updateState(harvestParams3); + + // 5. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 6. Get exit queue index + int256 exitQueueIndex = newVault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); + + // 7. Calculate exited assets + (, , uint256 exitedAssets) = newVault.calculateExitedAssets( + receiver, + positionTicket, + timestamp, + uint256(exitQueueIndex) + ); + + // 8. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + vm.prank(receiver); + newVault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + uint256 receiverBalanceAfter = address(receiver).balance; + + // 9. Verify assets were transferred to the receiver + uint256 receivedAssets = receiverBalanceAfter - receiverBalanceBefore; + assertEq(receivedAssets, exitedAssets, 'Receiver should have received the exited assets'); + + // The final amount should reflect the penalties and rewards, so approximately: + // 100 ETH (initial) - 30 ETH (penalty) + 15 ETH (reward) + 15 ETH (reward) = 100 ETH + // But there might be some precision loss or fees, so we use an approximate comparison. + assertApproxEqAbs( + receivedAssets, + 100 ether, + 1 ether, + 'Receiver should have received about 100 ETH' + ); + } +} diff --git a/test/VaultEthStaking.t.sol b/test/VaultEthStaking.t.sol new file mode 100644 index 00000000..a662e2cc --- /dev/null +++ b/test/VaultEthStaking.t.sol @@ -0,0 +1,571 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; +import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVaultFactory} from '../contracts/vaults/ethereum/EthVaultFactory.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; + +contract VaultEthStakingTest is Test, EthHelpers { + ForkContracts public contracts; + EthVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + + uint256 public depositAmount = 1 ether; + + function setUp() public { + // Get fork contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + referrer = makeAddr('referrer'); + validatorsManager = makeAddr('validatorsManager'); + + // Fund accounts for testing + vm.deal(sender, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(receiver, 1 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Set validators manager + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + vm.deal(validatorsManager, 1 ether); + } + + // Test initializing vault with insufficient security deposit + function test_invalidSecurityDeposit() public { + // Security deposit amount is defined as 1e9 (1 Gwei) in the EthHelpers contract + // Create a new admin address for this test + address newAdmin = makeAddr('newAdmin'); + vm.deal(newAdmin, 1 ether); + + // Get the factory for creating vaults + EthVaultFactory factory = _getOrCreateFactory(VaultType.EthVault); + + // Prepare initialization parameters + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + // Set value to less than required security deposit (1e9 wei) + uint256 insufficientDeposit = 0.1 gwei; + + // Try to create vault with insufficient security deposit + vm.prank(newAdmin); + _startSnapshotGas('VaultEthStakingTest_test_invalidSecurityDeposit'); + vm.expectRevert(Errors.InvalidSecurityDeposit.selector); + factory.createVault{value: insufficientDeposit}(initParams, false); + _stopSnapshotGas(); + + // Also test with zero deposit + vm.prank(newAdmin); + vm.expectRevert(Errors.InvalidSecurityDeposit.selector); + factory.createVault{value: 0}(initParams, false); + + // Verify that it works with correct security deposit + vm.prank(newAdmin); + address newVault = factory.createVault{value: 1 gwei}(initParams, false); + + // Verify vault was created + assertTrue( + address(newVault) != address(0), + 'Vault should be created with valid security deposit' + ); + } + + // Test basic deposit functionality + function test_deposit() public { + // Initial balances + uint256 senderInitialBalance = sender.balance; + uint256 vaultInitialBalance = address(vault).balance; + uint256 vaultTotalSharesBefore = vault.totalShares(); + uint256 vaultTotalAssetsBefore = vault.totalAssets(); + + // Deposit + vm.prank(sender); + _startSnapshotGas('VaultEthStakingTest_test_deposit'); + uint256 shares = vault.deposit{value: depositAmount}(receiver, referrer); + _stopSnapshotGas(); + + // Verify balances changed correctly + assertEq( + sender.balance, + senderInitialBalance - depositAmount, + 'Sender balance should decrease' + ); + assertEq( + address(vault).balance, + vaultInitialBalance + depositAmount, + 'Vault balance should increase' + ); + + // Verify shares minted correctly + assertEq(vault.getShares(receiver), shares, 'Receiver should get correct shares'); + + uint256 expectedShares = vault.convertToShares(depositAmount); + assertApproxEqAbs( + shares, + expectedShares, + 1, + 'Shares should match the expected conversion rate' + ); + + // Verify totalAssets and totalShares updated + assertEq( + vault.totalAssets(), + vaultTotalAssetsBefore + depositAmount, + 'Total assets should increase' + ); + assertEq(vault.totalShares(), vaultTotalSharesBefore + shares, 'Total shares should increase'); + } + + // Test withdrawable assets + function test_withdrawableAssets() public { + uint256 withdrawableBefore = vault.withdrawableAssets(); + + // Deposit some ETH + _depositToVault(address(vault), depositAmount, sender, receiver); + + // Check withdrawable assets + uint256 withdrawable = vault.withdrawableAssets(); + assertGe( + withdrawable, + withdrawableBefore + depositAmount, + 'Withdrawable assets should include deposited amount' + ); + } + + // Test vault assets reporting + function test_vaultAssets() public { + // Initial check + uint256 initialAssets = vault.totalAssets(); + uint256 initialBalance = address(vault).balance; + + // Deposit ETH + _depositToVault(address(vault), depositAmount, sender, receiver); + + // Check assets increased + assertEq( + vault.totalAssets(), + initialAssets + depositAmount, + 'Total assets should increase by deposit amount' + ); + + // Check that vault balance (internal _vaultAssets) reflects the deposit + assertEq( + address(vault).balance, + initialBalance + depositAmount, + 'Vault ETH balance should increase by deposit amount' + ); + } + + // Test validator registration + function test_registerValidators_succeeds() public { + // Setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Test successful registration with 0x01 prefix (32 ETH) + _depositToVault(address(vault), 32 ether, sender, sender); + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + 32 ether, + 'ipfsHash', + true + ); + + vm.prank(validatorsManager); + _startSnapshotGas('VaultEthStakingTest_test_registerValidators_01prefix'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Test successful registration with 0x02 prefix and valid amount (32 ETH) + _depositToVault(address(vault), 32 ether, sender, sender); + approvalParams = _getEthValidatorApproval(address(vault), 32 ether, 'ipfsHash', false); + + vm.prank(validatorsManager); + _startSnapshotGas('VaultEthStakingTest_test_registerValidators_02prefix'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // revert previous state + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test validator minimum and maximum effective balance limits + function test_validatorMinMaxEffectiveBalance() public { + // We need to simulate a registration attempt with invalid ETH amount + // For Ethereum, validators require exactly 32 ETH + + // Setup oracle for validator registration + _startOracleImpersonate(address(contracts.keeper)); + + // Prepare approval params + _depositToVault(address(vault), 32 ether, sender, sender); + + uint256[] memory deposits = new uint256[](1); + deposits[0] = 16 ether / 1 gwei; + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + 'ipfsHash', + deposits, + false + ); + + // This should fail because the deposit amount is not 32 ETH + vm.prank(validatorsManager); + _startSnapshotGas('VaultEthStakingTest_test_validatorMinMaxEffectiveBalance'); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test receive function for ETH + function test_receive() public { + // Send ETH directly to the vault + uint256 sendAmount = 0.5 ether; + vm.deal(sender, sendAmount); + + uint256 depositShares = vault.convertToShares(sendAmount); + uint256 userSharesBefore = vault.getShares(sender); + uint256 balanceBefore = address(vault).balance; + uint256 totalAssetsBefore = vault.totalAssets(); + + vm.prank(sender); + _startSnapshotGas('VaultEthStakingTest_test_receive'); + (bool success, ) = address(vault).call{value: sendAmount}(''); + _stopSnapshotGas(); + + assertTrue(success, 'Failed to send ETH to vault'); + assertEq( + address(vault).balance, + balanceBefore + sendAmount, + "Vault balance didn't increase correctly" + ); + assertEq( + vault.totalAssets(), + totalAssetsBefore + sendAmount, + "Vault total assets didn't increase correctly" + ); + assertApproxEqAbs( + vault.getShares(sender), + depositShares + userSharesBefore, + 1, + 'User should have deposit amount' + ); + } + + // Test update state and deposit + function test_updateStateAndDeposit() public { + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + uint256 initialBalance = address(vault).balance; + uint256 initialShares = vault.totalShares(); + + // Call updateStateAndDeposit + vm.prank(sender); + _startSnapshotGas('VaultEthStakingTest_test_updateStateAndDeposit'); + uint256 shares = vault.updateStateAndDeposit{value: depositAmount}( + receiver, + referrer, + harvestParams + ); + _stopSnapshotGas(); + + // Verify the deposit was successful and state was updated + assertGt(shares, 0, 'Should have minted shares'); + assertEq( + address(vault).balance, + initialBalance + depositAmount, + 'Vault balance should increase by deposit amount' + ); + assertGt(vault.totalShares(), initialShares, 'Total shares should increase'); + } + + // Test receiving from MEV escrow + function test_receiveFromMevEscrow() public { + // Get MEV escrow address + address mevEscrow = vault.mevEscrow(); + uint256 initialBalance = address(vault).balance; + uint256 mevAmount = 0.5 ether; + + vm.deal(mevEscrow, mevAmount); + + // Can only be called by the MEV escrow + vm.prank(sender); + _startSnapshotGas('VaultEthStakingTest_test_receiveFromMevEscrow_fail'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.receiveFromMevEscrow{value: 0.1 ether}(); + _stopSnapshotGas(); + + // Call from MEV escrow succeeds + vm.prank(mevEscrow); + _startSnapshotGas('VaultEthStakingTest_test_receiveFromMevEscrow_success'); + vault.receiveFromMevEscrow{value: mevAmount}(); + _stopSnapshotGas(); + + assertEq( + address(vault).balance, + initialBalance + mevAmount, + 'Vault balance should increase by MEV amount' + ); + } + + // Test deposit and mint OsToken + function test_depositAndMintOsToken() public { + // Collateralize vault for OsToken minting + _collateralizeEthVault(address(vault)); + + uint256 initialBalance = address(vault).balance; + + // Deposit and mint maximum possible OsToken shares + vm.prank(sender); + _startSnapshotGas('VaultEthStakingTest_test_depositAndMintOsToken'); + uint256 assets = vault.depositAndMintOsToken{value: depositAmount}( + sender, + type(uint256).max, + referrer + ); + _stopSnapshotGas(); + + // Verify deposit + assertEq( + address(vault).balance, + initialBalance + depositAmount, + 'Vault balance should increase by deposit amount' + ); + + // Verify OsToken minting + assertGt(assets, 0, 'Should have minted OsToken assets'); + assertGt(vault.osTokenPositions(sender), 0, 'Should have OsToken position'); + } + + // Test update state, deposit and mint OsToken + function test_updateStateAndDepositAndMintOsToken() public { + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + uint256 initialBalance = address(vault).balance; + + // Call updateStateAndDepositAndMintOsToken + vm.prank(sender); + _startSnapshotGas('VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken'); + uint256 assets = vault.updateStateAndDepositAndMintOsToken{value: depositAmount}( + sender, + type(uint256).max, + referrer, + harvestParams + ); + _stopSnapshotGas(); + + // Verify the deposit was successful and state was updated + assertGt(assets, 0, 'Should have minted OsToken assets'); + assertEq( + address(vault).balance, + initialBalance + depositAmount, + 'Vault balance should increase by deposit amount' + ); + assertGt(vault.osTokenPositions(sender), 0, 'Should have OsToken position'); + } + + // Test transferVaultAssets functionality through the exit queue + function test_transferVaultAssets() public { + // Collateralize vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to the vault + uint256 senderDeposit = vault.convertToAssets(vault.queuedShares()) + + vault.totalExitingAssets() + + depositAmount; + _depositToVault(address(vault), senderDeposit, sender, sender); + + // Record initial balances + uint256 receiverInitialBalance = receiver.balance; + + // Enter exit queue + uint256 withdrawalAmount = vault.convertToShares(depositAmount); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(withdrawalAmount, receiver); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Claim exited assets which will trigger _transferVaultAssets + vm.prank(receiver); + _startSnapshotGas('VaultEthStakingTest_test_transferVaultAssets'); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify the transfer occurred + uint256 receiverFinalBalance = receiver.balance; + assertGt(receiverFinalBalance, receiverInitialBalance, 'Receiver balance should increase'); + } + + // Test mev rewards processing through _harvestAssets + function test_harvestAssets() public { + // Collateralize vault + _collateralizeEthVault(address(vault)); + + // Set up a reward with MEV component + uint160 mevReward = 0.2 ether; + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.3 ether)), + mevReward + ); + + // Setup MEV escrow with some ETH + address mevEscrow = vault.mevEscrow(); + vm.deal(mevEscrow, mevReward); + + // Record initial balances + uint256 vaultInitialBalance = address(vault).balance; + + // Update state which will trigger _harvestAssets + _startSnapshotGas('VaultEthStakingTest_test_harvestAssets'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify the vault received MEV rewards + assertGt( + address(vault).balance, + vaultInitialBalance, + 'Vault balance should increase from MEV rewards' + ); + } + + // Test adding validator then withdrawing (full flow) + function test_withdrawValidator_fullFlow() public { + // 1. Deposit and register a validator + _depositToVault(address(vault), 32 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 2. Fund validators manager for the withdrawal fee + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas('VaultEthStakingTest_test_withdrawValidator_fullFlow'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + // Test funding existing validators + function test_fundValidators() public { + // 1. Deposit enough ETH for multiple validator operations + _depositToVault(address(vault), 64 ether, sender, sender); + + // Setup oracle for validator registration + _startOracleImpersonate(address(contracts.keeper)); + + // 2. Register a validator first to make it tracked + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Try to top up a non-existing validator (should fail) + bytes memory nonExistingPublicKey = vm.randomBytes(48); + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + nonExistingPublicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create top-up data for non-existing validator + bytes memory invalidTopUpData = bytes.concat( + nonExistingPublicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + vm.prank(validatorsManager); + _startSnapshotGas('VaultEthStakingTest_test_fundValidators_invalid'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(invalidTopUpData, ''); + _stopSnapshotGas(); + + // 4. Successfully top up the registered validator + // Create valid top-up data using the same public key as the registered validator + topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + vm.prank(validatorsManager); + _startSnapshotGas('VaultEthStakingTest_test_fundValidators_valid'); + vault.fundValidators(validTopUpData, ''); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } +} diff --git a/test/VaultExitQueueClaim.t.sol b/test/VaultExitQueueClaim.t.sol deleted file mode 100644 index 535beb48..00000000 --- a/test/VaultExitQueueClaim.t.sol +++ /dev/null @@ -1,436 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IEthVaultFactory} from '../contracts/interfaces/IEthVaultFactory.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IValidatorsRegistry} from '../contracts/interfaces/IValidatorsRegistry.sol'; -import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; -import {Keeper} from '../contracts/keeper/Keeper.sol'; -import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; -import {EthGenesisVault} from '../contracts/vaults/ethereum/EthGenesisVault.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {CommonBase} from '../lib/forge-std/src/Base.sol'; -import {StdAssertions} from '../lib/forge-std/src/StdAssertions.sol'; -import {StdChains} from '../lib/forge-std/src/StdChains.sol'; -import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; -import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; -import {Test} from '../lib/forge-std/src/Test.sol'; -import {UUPSUpgradeable} from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {RewardsTest} from './Rewards.t.sol'; -import {MainnetForkTest} from './MainnetFork.t.sol'; - - -contract VaultExitQueueClaimTest is Test, MainnetForkTest, RewardsTest { - struct ExitRequest { - uint256 totalTickets; - uint256 positionTicket; - uint256 exitQueueIndex; - address receiver; - uint256 timestamp; - } - - address public constant user1 = address(0x1); - address public constant user2 = address(0x2); - - address public vault; - - function setUp() public override(MainnetForkTest, RewardsTest) { - MainnetForkTest.setUp(); - - RewardsTest.setUp(); - - vm.prank(VaultsRegistry(vaultsRegistry).owner()); - VaultsRegistry(vaultsRegistry).addFactory(v2VaultFactory); - - // create V2 vault - IEthVault.EthVaultInitParams memory params = IEthVault.EthVaultInitParams({ - capacity: type(uint256).max, - feePercent: 500, - metadataIpfsHash: '' - }); - vault = IEthVaultFactory(v2VaultFactory).createVault{value: 1 gwei}(abi.encode(params), false); - - // collateralize vault (imitate validator creation) - _collateralizeVault(vault); - } - - function test_failsToClaimAfterV3Upgrade() public { - // user 1 stakes 1 ether - vm.deal(user1, 2 ether); - vm.prank(user1); - uint256 shares1 = IEthVault(vault).deposit{value: 1 ether}(user1, address(0)); - - // user 2 stakes 1 ether - vm.deal(user2, 2 ether); - vm.prank(user2); - uint256 shares2 = IEthVault(vault).deposit{value: 1 ether}(user2, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - - // user 1 enters exit queue - vm.prank(user1); - uint256 positionTicket1 = IEthVault(vault).enterExitQueue(shares1, user1); - - // user 2 enters exit queue - vm.prank(user2); - uint256 positionTicket2 = IEthVault(vault).enterExitQueue(shares2, user2); - - assertGt(positionTicket2, positionTicket1); - - // 25 hours time delay passes - vm.warp(timestamp + 25 hours); - - // user 2 claims exited assets - int256 exitQueueIndex2 = IEthVault(vault).getExitQueueIndex(positionTicket2); - vm.prank(user2); - IEthVault(vault).claimExitedAssets(positionTicket2, timestamp, uint256(exitQueueIndex2)); - - // check user 1 position - int256 exitQueueIndex1 = IEthVault(vault).getExitQueueIndex(positionTicket1); - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = IEthVault(vault) - .calculateExitedAssets(user1, positionTicket1, timestamp, uint256(exitQueueIndex1)); - assertEq(leftTickets, 0); - assertEq(exitedTickets, shares1); - // NB! Assets are waiting to be claimed - assertEq(exitedAssets, 1 ether); - - // upgrade vault to V3 - UUPSUpgradeable(vault).upgradeToAndCall(vaultV3Impl, ''); - - (leftTickets, exitedTickets, exitedAssets) = IEthVault(vault).calculateExitedAssets( - user1, - positionTicket1, - timestamp, - uint256(exitQueueIndex1) - ); - assertEq(leftTickets, 0); - assertEq(exitedTickets, shares1); - // NB! Assets are gone - assertEq(exitedAssets, 0); - } - - function test_claimsExitedAssetsForV2Positions() public { - // user 1 stakes 1 ether - vm.deal(user1, 2 ether); - vm.prank(user1); - uint256 shares1 = IEthVault(vault).deposit{value: 1 ether}(user1, address(0)); - - // user 2 stakes 1 ether - vm.deal(user2, 2 ether); - vm.prank(user2); - uint256 shares2 = IEthVault(vault).deposit{value: 1 ether}(user2, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - - // user 1 enters exit queue - vm.prank(user1); - uint256 positionTicket1 = IEthVault(vault).enterExitQueue(shares1, user1); - - // user 2 enters exit queue - vm.prank(user2); - uint256 positionTicket2 = IEthVault(vault).enterExitQueue(shares2, user2); - - assertGt(positionTicket2, positionTicket1); - - // 25 hours time delay passes - vm.warp(timestamp + 25 hours); - - // user 2 claims exited assets - int256 exitQueueIndex2 = IEthVault(vault).getExitQueueIndex(positionTicket2); - vm.prank(user2); - IEthVault(vault).claimExitedAssets(positionTicket2, timestamp, uint256(exitQueueIndex2)); - - // check user 1 position - int256 exitQueueIndex1 = IEthVault(vault).getExitQueueIndex(positionTicket1); - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = IEthVault(vault) - .calculateExitedAssets(user1, positionTicket1, timestamp, uint256(exitQueueIndex1)); - assertEq(leftTickets, 0); - assertEq(exitedTickets, shares1); - assertEq(exitedAssets, 1 ether); - - // upgrade vault to V3 - UUPSUpgradeable(vault).upgradeToAndCall(vaultV3Impl, ''); - - address vaultV4Impl = address( - new EthVault( - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - exitingAssetsClaimDelay - ) - ); - - // add implementation to vaults registry - vm.prank(VaultsRegistry(vaultsRegistry).owner()); - VaultsRegistry(vaultsRegistry).addVaultImpl(vaultV4Impl); - - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards(vault, 0, 0, 0); - - // upgrade vault to V4 - UUPSUpgradeable(vault).upgradeToAndCall(vaultV4Impl, ''); - - // checkpoint created - IEthVault(vault).updateState(harvestParams); - - (leftTickets, exitedTickets, exitedAssets) = IEthVault(vault).calculateExitedAssets( - user1, - positionTicket1, - timestamp, - uint256(exitQueueIndex1) - ); - assertEq(leftTickets, 0); - assertEq(exitedTickets, shares1); - assertEq(exitedAssets, 1 ether); - } - - function test_genesisVaultUserCanClaim() public { - ExitRequest[12] memory exitRequests; - exitRequests[0] = ExitRequest({ - totalTickets: 499999999999999999, - positionTicket: 44327091523045298757621, - exitQueueIndex: 621, - receiver: 0x4a0f354c187C02f512Cca537fD525DBD9d24Ed23, - timestamp: 1733356271 - }); - - exitRequests[1] = ExitRequest({ - totalTickets: 43525488879545944, - positionTicket: 44395279374806722809184, - exitQueueIndex: 621, - receiver: 0x7415B5674Fa52b3F0233535Dd2328445957F2dde, - timestamp: 1733433779 - }); - - exitRequests[2] = ExitRequest({ - totalTickets: 1031408907039568342, - positionTicket: 44395322900295602355128, - exitQueueIndex: 621, - receiver: 0x7bB7E752Ce21a46C85586f48e18175027c0fF889, - timestamp: 1733507435 - }); - - exitRequests[3] = ExitRequest({ - totalTickets: 121707545706725680, - positionTicket: 44396737851159051273849, - exitQueueIndex: 621, - receiver: 0x09988E9AEb8c0B835619305Abfe2cE68FEa17722, - timestamp: 1733515079 - }); - - exitRequests[4] = ExitRequest({ - totalTickets: 9999999999999999999, - positionTicket: 44460020813470431995667, - exitQueueIndex: 621, - receiver: 0xcd7Ca6d370B08dBb2cf1CB050869810643ab0F29, - timestamp: 1733675219 - }); - - exitRequests[5] = ExitRequest({ - totalTickets: 38220753247637935, - positionTicket: 44472679655185076065149, - exitQueueIndex: 621, - receiver: 0x5c414269b4457F44E6Add5B1fB4D10f388222B38, - timestamp: 1733716475 - }); - - exitRequests[6] = ExitRequest({ - totalTickets: 1744907540449843296, - positionTicket: 44472717875938323703084, - exitQueueIndex: 621, - receiver: 0x01f26d7f195A37D368cB772ed75eF70Dd29700f5, - timestamp: 1733738411 - }); - - exitRequests[7] = ExitRequest({ - totalTickets: 25478387752573320, - positionTicket: 44474462783478773546380, - exitQueueIndex: 621, - receiver: 0x650836845682bA49a7Fe08d31212606ed6950841, - timestamp: 1733807231 - }); - - exitRequests[8] = ExitRequest({ - totalTickets: 2265098543333097054, - positionTicket: 44577280909916261787066, - exitQueueIndex: 621, - receiver: 0xF8950d7f6819579DfFdD41ae851C9AB5dd3e860F, - timestamp: 1733995643 - }); - - exitRequests[9] = ExitRequest({ - totalTickets: 60251517847154136, - positionTicket: 44586822012269740893518, - exitQueueIndex: 621, - receiver: 0xFEE0aE045159FCe306Eba14E79A19056521A4639, - timestamp: 1734124775 - }); - - exitRequests[10] = ExitRequest({ - totalTickets: 10390397572279663, - positionTicket: 44587046593396866580520, - exitQueueIndex: 621, - receiver: 0x48f7D45FA696Dc89fF4f2233B25490455AE19DC2, - timestamp: 1734162935 - }); - - exitRequests[11] = ExitRequest({ - totalTickets: 820674938574018694, - positionTicket: 44644422443067695690880, - exitQueueIndex: 621, - receiver: 0xBFd2523059d5CfC4a966D58958597a9226926d32, - timestamp: 1734359759 - }); - - // user 1 stakes 1 ether - vm.deal(user1, 2 ether); - vm.prank(user1); - uint256 shares1 = IEthVault(genesisVault).deposit{value: 1 ether}(user1, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - - // user 1 enters exit queue - vm.prank(user1); - uint256 positionTicket1 = IEthVault(genesisVault).enterExitQueue(shares1, user1); - - // 25 hours time delay passes - vm.warp(timestamp + 25 hours); - - // check user 1 position - int256 exitQueueIndex1 = IEthVault(genesisVault).getExitQueueIndex(positionTicket1); - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = IEthVault(genesisVault) - .calculateExitedAssets(user1, positionTicket1, timestamp, uint256(exitQueueIndex1)); - assertEq(leftTickets, shares1); - assertEq(exitedTickets, 0); - assertEq(exitedAssets, 0); - - // check issue reproduces for all the stuck users - for (uint256 i = 0; i < exitRequests.length; i++) { - ExitRequest memory exitRequest = exitRequests[i]; - (leftTickets, exitedTickets, exitedAssets) = IEthVault(genesisVault).calculateExitedAssets( - exitRequest.receiver, - exitRequest.positionTicket, - exitRequest.timestamp, - exitRequest.exitQueueIndex - ); - assertEq(leftTickets, 0); - assertEq(exitedTickets, exitRequest.totalTickets); - assertEq(exitedAssets, 0); - } - - // deploy upgrade - address vaultV4Impl = address( - new EthGenesisVault( - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - poolEscrow, - rewardEthToken, - exitingAssetsClaimDelay - ) - ); - - // add implementation to vaults registry - vm.prank(VaultsRegistry(vaultsRegistry).owner()); - VaultsRegistry(vaultsRegistry).addVaultImpl(vaultV4Impl); - - // upgrade vault to V4 - vm.prank(IEthVault(genesisVault).admin()); - UUPSUpgradeable(genesisVault).upgradeToAndCall(vaultV4Impl, ''); - - // check user 1 position - exitQueueIndex1 = IEthVault(genesisVault).getExitQueueIndex(positionTicket1); - (leftTickets, exitedTickets, exitedAssets) = IEthVault(genesisVault).calculateExitedAssets( - user1, - positionTicket1, - timestamp, - uint256(exitQueueIndex1) - ); - assertEq(leftTickets, shares1); - assertEq(exitedTickets, 0); - assertEq(exitedAssets, 0); - - (int192 assets1, ) = IKeeperRewards(keeper).rewards(genesisVault); - (uint192 assets2, ) = IKeeperRewards(keeper).unlockedMevRewards(genesisVault); - - // update state to create checkpoint - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - genesisVault, - assets1, - assets2, - IOsTokenVaultController(osTokenVaultController).avgRewardPerSecond() - ); - IEthVault(genesisVault).updateState(harvestParams); - - // check claim works for normal user - exitQueueIndex1 = IEthVault(genesisVault).getExitQueueIndex(positionTicket1); - (leftTickets, exitedTickets, exitedAssets) = IEthVault(genesisVault).calculateExitedAssets( - user1, - positionTicket1, - timestamp, - uint256(exitQueueIndex1) - ); - assertEq(leftTickets, 1); // rounding error - assertEq(exitedTickets, shares1 - 1); // rounding error - assertEq(exitedAssets, 1 ether - 1); // rounding error - - vm.prank(user1); - IEthVault(genesisVault).claimExitedAssets(positionTicket1, timestamp, uint256(exitQueueIndex1)); - - (leftTickets, exitedTickets, exitedAssets) = IEthVault(genesisVault).calculateExitedAssets( - user1, - positionTicket1, - timestamp, - uint256(exitQueueIndex1) - ); - assertEq(leftTickets, 0); - assertEq(exitedTickets, 0); - assertEq(exitedAssets, 0); - - // check claim works for all the stuck users - for (uint256 i = 0; i < exitRequests.length; i++) { - ExitRequest memory exitRequest = exitRequests[i]; - int256 exitQueueIndex = IEthVault(genesisVault).getExitQueueIndex(exitRequest.positionTicket); - (leftTickets, exitedTickets, exitedAssets) = IEthVault(genesisVault).calculateExitedAssets( - exitRequest.receiver, - exitRequest.positionTicket, - exitRequest.timestamp, - uint256(exitQueueIndex) - ); - assertEq(leftTickets, 0); - assertEq(exitedTickets, exitRequest.totalTickets); - assertEq(exitedAssets, exitRequest.totalTickets); - - vm.prank(exitRequest.receiver); - IEthVault(genesisVault).claimExitedAssets( - exitRequest.positionTicket, - exitRequest.timestamp, - uint256(exitQueueIndex) - ); - - (leftTickets, exitedTickets, exitedAssets) = IEthVault(genesisVault).calculateExitedAssets( - exitRequest.receiver, - exitRequest.positionTicket, - exitRequest.timestamp, - uint256(exitQueueIndex) - ); - assertEq(leftTickets, 0); - assertEq(exitedTickets, 0); - assertEq(exitedAssets, 0); - } - } -} diff --git a/test/VaultFee.t.sol b/test/VaultFee.t.sol new file mode 100644 index 00000000..2e941c67 --- /dev/null +++ b/test/VaultFee.t.sol @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract VaultFeeTest is Test, EthHelpers { + ForkContracts public contracts; + EthVault public vault; + + address public admin; + address public user; + address public feeRecipient; + address public newFeeRecipient; + address public referrer = address(0); + + uint16 public initialFeePercent; + uint256 public depositAmount = 10 ether; + uint256 public rewardAmount = 1 ether; + uint256 public feeChangeDelay = 7 days; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + feeRecipient = makeAddr('feeRecipient'); + newFeeRecipient = makeAddr('newFeeRecipient'); + + // Fund accounts with ETH for testing + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + initialFeePercent = vault.feePercent(); + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + + vm.prank(admin); + vault.setFeeRecipient(admin); + } + + function test_initialFeeRecipient() public view { + // The fee recipient should initially be set to the admin as per the vault initialization + assertEq(vault.feeRecipient(), admin, 'Initial fee recipient should be the admin'); + assertEq(vault.feePercent(), initialFeePercent, 'Initial fee percent should match parameter'); + } + + function test_setFeeRecipient_success() public { + // Test setting a new fee recipient as admin + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_success'); + vault.setFeeRecipient(newFeeRecipient); + _stopSnapshotGas(); + + // Verify the new fee recipient + assertEq(vault.feeRecipient(), newFeeRecipient, 'Fee recipient should be updated'); + } + + function test_setFeeRecipient_notAdmin() public { + // Test setting fee recipient as non-admin + vm.prank(user); + _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_notAdmin'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setFeeRecipient(newFeeRecipient); + _stopSnapshotGas(); + + // Fee recipient should remain unchanged + assertEq(vault.feeRecipient(), admin, 'Fee recipient should not change'); + } + + function test_setFeeRecipient_zeroAddress() public { + // Test setting fee recipient to zero address + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_zeroAddress'); + vm.expectRevert(Errors.InvalidFeeRecipient.selector); + vault.setFeeRecipient(address(0)); + _stopSnapshotGas(); + + // Fee recipient should remain unchanged + assertEq(vault.feeRecipient(), admin, 'Fee recipient should not change'); + } + + function test_setFeeRecipient_requiresHarvest() public { + // Make sure vault needs to be harvested + _collateralizeEthVault(address(vault)); + + // update state twice to require harvesting + _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(rewardAmount)), + 0 + ); + + // Test setting fee recipient without harvesting + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_requiresHarvest'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.setFeeRecipient(newFeeRecipient); + _stopSnapshotGas(); + + // First update state + vault.updateState(harvestParams); + + // Then try setting fee recipient again + vm.prank(admin); + vault.setFeeRecipient(newFeeRecipient); + assertEq( + vault.feeRecipient(), + newFeeRecipient, + 'Fee recipient should be updated after harvest' + ); + } + + function test_setFeePercent_success() public { + // Test setting a new fee percentage as admin + uint16 newFeePercent = vault.feePercent() + 1; + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_success'); + vault.setFeePercent(newFeePercent); + _stopSnapshotGas(); + + // Verify the new fee percentage + assertEq(vault.feePercent(), newFeePercent, 'Fee percent should be updated'); + } + + function test_setFeePercent_notAdmin() public { + // Test setting fee percentage as non-admin + uint16 newFeePercent = 500; // 5% + vm.prank(user); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_notAdmin'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setFeePercent(newFeePercent); + _stopSnapshotGas(); + + // Fee percentage should remain unchanged + assertEq(vault.feePercent(), initialFeePercent, 'Fee percent should not change'); + } + + function test_setFeePercent_aboveMaximum() public { + // Test setting fee percentage above maximum (10000 = 100%) + uint16 invalidFeePercent = 10001; // 100.01% + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_aboveMaximum'); + vm.expectRevert(Errors.InvalidFeePercent.selector); + vault.setFeePercent(invalidFeePercent); + _stopSnapshotGas(); + + // Fee percentage should remain unchanged + assertEq(vault.feePercent(), initialFeePercent, 'Fee percent should not change'); + } + + function test_setFeePercent_tooSoon() public { + // First set fee percentage + uint16 firstFeePercent = 500; // 5% + vm.prank(admin); + vault.setFeePercent(firstFeePercent); + + // Then try to set again too soon (before feeChangeDelay have passed) + uint16 secondFeePercent = 600; // 6% + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_tooSoon'); + vm.expectRevert(Errors.TooEarlyUpdate.selector); + vault.setFeePercent(secondFeePercent); + _stopSnapshotGas(); + + // Fee percentage should remain at the first update + assertEq(vault.feePercent(), firstFeePercent, 'Fee percent should not change'); + + // Try again after the delay period + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + vm.prank(admin); + vault.setFeePercent(secondFeePercent); + assertEq(vault.feePercent(), secondFeePercent, 'Fee percent should update after delay'); + } + + function test_setFeePercent_maxIncrease() public { + // First set fee percentage + uint16 firstFeePercent = 500; // 5% + vm.prank(admin); + vault.setFeePercent(firstFeePercent); + + // Wait for delay period + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + + // Try to increase fee by more than 20% + uint16 invalidIncrease = 700; // 7% (more than 20% increase from 5%) + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_maxIncrease'); + vm.expectRevert(Errors.InvalidFeePercent.selector); + vault.setFeePercent(invalidIncrease); + _stopSnapshotGas(); + + // Fee percentage should remain at the first update + assertEq(vault.feePercent(), firstFeePercent, 'Fee percent should not change'); + + // Try a valid increase (below 20%) + uint16 validIncrease = 600; // 6% (20% increase from 5%) + vm.prank(admin); + vault.setFeePercent(validIncrease); + assertEq(vault.feePercent(), validIncrease, 'Fee percent should update with valid increase'); + } + + function test_setFeePercent_requiresHarvest() public { + // Make sure vault needs to be harvested + _collateralizeEthVault(address(vault)); + _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(rewardAmount)), + 0 + ); + + // Test setting fee percentage without harvesting + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + uint16 newFeePercent = 500; // 5% + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_requiresHarvest'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.setFeePercent(newFeePercent); + _stopSnapshotGas(); + + // First update state + vault.updateState(harvestParams); + + // Then try setting fee percentage again + vm.prank(admin); + vault.setFeePercent(newFeePercent); + assertEq(vault.feePercent(), newFeePercent, 'Fee percent should be updated after harvest'); + } + + function test_setFeePercent_initialZeroToOne() public { + // Create a new vault with 0% fee + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 0, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address zeroFeeVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault zeroFeeVault = EthVault(payable(zeroFeeVaultAddr)); + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + + // Ensure the initial fee percent is 0 + assertEq(zeroFeeVault.feePercent(), 0, 'Initial fee percent should be 0'); + + // Test increasing from 0% to 1% + vm.prank(admin); + _startSnapshotGas('VaultFeeTest_test_setFeePercent_initialZeroToOne'); + zeroFeeVault.setFeePercent(100); // 1% + _stopSnapshotGas(); + + // Verify the fee percentage was set to 1% + assertEq(zeroFeeVault.feePercent(), 100, 'Fee percent should be updated to 1%'); + + // Try to set fee to more than 1% immediately + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + vm.prank(admin); + vm.expectRevert(Errors.InvalidFeePercent.selector); + zeroFeeVault.setFeePercent(200); // 2% (more than allowed increase from 1%) + + // Fee percentage should remain at 1% + assertEq(zeroFeeVault.feePercent(), 100, 'Fee percent should remain at 1%'); + } + + function test_feeCollection() public { + // Setup: deposit ETH and make vault active + _depositToVault(address(vault), depositAmount, user, user); + _collateralizeEthVault(address(vault)); + + // Set a different fee recipient to track fee minting + vm.prank(admin); + vault.setFeeRecipient(feeRecipient); + + // Record initial shares of fee recipient + uint256 feeRecipientInitialShares = vault.getShares(feeRecipient); + + // Add a reward to the vault + int160 rewardValue = int160(int256(rewardAmount)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + rewardValue, + 0 + ); + + // Update state to process rewards + _startSnapshotGas('VaultFeeTest_test_feeCollection'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify fee recipient received shares + uint256 feeRecipientFinalShares = vault.getShares(feeRecipient); + uint256 feeShares = feeRecipientFinalShares - feeRecipientInitialShares; + + // Check that the fee recipient got shares + assertGt(feeShares, 0, 'Fee recipient should receive shares'); + + // Convert shares to assets to verify percentage + uint256 feeAssets = vault.convertToAssets(feeShares); + + // Calculate expected fees with a small tolerance for rounding + uint256 expectedFeeAssets = (rewardAmount * initialFeePercent) / 10000; + assertApproxEqAbs( + feeAssets, + expectedFeeAssets, + 1e9, // 1 Gwei tolerance + 'Invalid fee assets minted' + ); + } + + function test_feePercent_changeAffectsFutureRewards() public { + // Setup: deposit ETH and make vault active + _depositToVault(address(vault), depositAmount, user, user); + _collateralizeEthVault(address(vault)); + + // Set a different fee recipient to track fee minting + vm.startPrank(admin); + vault.setFeeRecipient(feeRecipient); + while (vault.feePercent() != 1000) { + // increment by 20% until fee percent is 10% + uint256 newFeePercent = (uint256(vault.feePercent()) * 120) / 100; + if (newFeePercent > 1000) { + newFeePercent = 1000; + } + vault.setFeePercent(uint16(newFeePercent)); + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + } + vm.stopPrank(); + assertEq(vault.feePercent(), 1000, 'Fee percent should be updated to 10%'); + + // Record initial shares of fee recipient + uint256 feeRecipientInitialShares = vault.getShares(feeRecipient); + + // First reward with 10% fee + int160 firstRewardValue = int160(int256(rewardAmount)); + IKeeperRewards.HarvestParams memory firstHarvestParams = _setEthVaultReward( + address(vault), + firstRewardValue, + 0 + ); + vault.updateState(firstHarvestParams); + + // Record intermediate shares + uint256 feeRecipientMidShares = vault.getShares(feeRecipient); + uint256 firstFeeShares = feeRecipientMidShares - feeRecipientInitialShares; + uint256 firstFeeAssets = vault.convertToAssets(firstFeeShares); + + // Change fee percentage to 5% + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + vm.prank(admin); + vault.setFeePercent(500); + assertEq(vault.feePercent(), 500, 'Fee percent should be updated to 5%'); + + // Second reward with 5% fee + int160 secondRewardValue = firstRewardValue + int160(int256(rewardAmount)); + IKeeperRewards.HarvestParams memory secondHarvestParams = _setEthVaultReward( + address(vault), + secondRewardValue, + 0 + ); + + _startSnapshotGas('VaultFeeTest_test_feePercent_changeAffectsFutureRewards'); + vault.updateState(secondHarvestParams); + _stopSnapshotGas(); + + // Record final shares + uint256 feeRecipientFinalShares = vault.getShares(feeRecipient); + uint256 secondFeeShares = feeRecipientFinalShares - feeRecipientMidShares; + uint256 secondFeeAssets = vault.convertToAssets(secondFeeShares); + + // Calculate expected fees with a small tolerance for rounding + uint256 expectedFirstFeeAssets = (rewardAmount * 1000) / 10000; // 10% + uint256 expectedSecondFeeAssets = (rewardAmount * 500) / 10000; // 5% + + assertApproxEqAbs( + firstFeeAssets, + expectedFirstFeeAssets, + 1e9, // 1 Gwei tolerance + 'First fee assets should be approximately 10% of reward' + ); + + assertApproxEqAbs( + secondFeeAssets, + expectedSecondFeeAssets, + 1e9, // 1 Gwei tolerance + 'Second fee assets should be approximately 5% of reward' + ); + + // The ratio of second fee to first fee should be about 1:2 (5% vs 10%) + assertApproxEqRel( + secondFeeAssets * 2, + firstFeeAssets, + 0.05e18, // 5% tolerance + 'Second fee should be about half of first fee' + ); + } +} diff --git a/test/VaultOsToken.t.sol b/test/VaultOsToken.t.sol new file mode 100644 index 00000000..b5fe1239 --- /dev/null +++ b/test/VaultOsToken.t.sol @@ -0,0 +1,1470 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; +import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; +import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; +import {IVaultOsToken} from '../contracts/interfaces/IVaultOsToken.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; + +interface IStrategiesRegistry { + function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; + function setStrategy(address strategy, bool enabled) external; + + function owner() external view returns (address); +} + +contract VaultOsTokenTest is Test, EthHelpers { + IStrategiesRegistry private constant _strategiesRegistry = + IStrategiesRegistry(0x90b82E4b3aa385B4A02B7EBc1892a4BeD6B5c465); + + ForkContracts public contracts; + EthVault public vault; + IOsTokenVaultController public osTokenVaultController; + IOsTokenConfig public osTokenConfig; + + address public owner; + address public receiver; + address public admin; + address public referrer; + + uint256 public depositAmount = 5 ether; + + function setUp() public { + // Get fork contracts + contracts = _activateEthereumFork(); + osTokenVaultController = contracts.osTokenVaultController; + osTokenConfig = contracts.osTokenConfig; + + // Set up test accounts + owner = makeAddr('owner'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + referrer = makeAddr('referrer'); + + // Fund accounts for testing + vm.deal(owner, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(receiver, 1 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deposit to vault + _depositToVault(address(vault), depositAmount, owner, owner); + + // Collateralize vault (required for minting OsToken) + _collateralizeEthVault(address(vault)); + + vm.warp(vm.getBlockTimestamp() + 7 days + 1); + } + + // Test basic minting functionality + function test_mintOsToken_basic() public { + // Start with clean slate + uint256 initialOsTokenShares = vault.osTokenPositions(owner); + + // Calculate a portion of max mintable amount to use + uint256 osTokenSharesToMint = contracts.osTokenVaultController.convertToShares(1 ether); + + // Expect the OsTokenMinted event to be emitted + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, osTokenSharesToMint, referrer); + + // Mint OsToken + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_basic'); + uint256 assets = vault.mintOsToken(receiver, osTokenSharesToMint, referrer); + _stopSnapshotGas(); + + // Verify minting was successful + assertGt(assets, 0, 'Should have minted assets'); + assertEq( + vault.osTokenPositions(owner), + initialOsTokenShares + osTokenSharesToMint, + "Owner's OsToken position should increase" + ); + } + + // Test minting maximum amount using type(uint256).max + function test_mintOsToken_maxAmount() public { + // Start with clean slate + uint256 initialOsTokenShares = vault.osTokenPositions(owner); + + // Expect the OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, 0, referrer); // We don't know exact share amount, just verify caller + + // Mint max OsToken + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_maxAmount'); + uint256 assets = vault.mintOsToken(receiver, type(uint256).max, referrer); + _stopSnapshotGas(); + + // Verify minting was successful and minted the max available + assertGt(assets, 0, 'Should have minted assets'); + assertGt( + vault.osTokenPositions(owner), + initialOsTokenShares, + "Owner's OsToken position should increase" + ); + + // Try minting max again - should mint 0 as already at max + vm.prank(owner); + uint256 assetsRetry = vault.mintOsToken(receiver, type(uint256).max, referrer); + + assertEq(assetsRetry, 0, 'Should not mint additional shares when at max'); + } + + // Test LTV validation + function test_mintOsToken_ltvValidation() public { + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate an amount that would exceed LTV + uint256 userAssets = vault.convertToAssets(vault.getShares(owner)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Try to mint slightly more than max allowed + uint256 excessShares = maxOsTokenShares + 1; + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_ltvValidation'); + vm.expectRevert(Errors.LowLtv.selector); + vault.mintOsToken(receiver, excessShares, referrer); + _stopSnapshotGas(); + } + + // Test that entering exit queue fails when it would violate LTV + function test_enterExitQueue_ltvViolation() public { + // First mint maximum OsToken shares + uint256 userShares = vault.getShares(owner); + uint256 userAssets = vault.convertToAssets(userShares); + + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Expect OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, owner, 0, maxOsTokenShares, referrer); + + // Mint maximum OsToken shares + vm.prank(owner); + vault.mintOsToken(owner, maxOsTokenShares, referrer); + + // Now try to enter exit queue with some shares + // Even a small amount should fail because it would reduce collateral and violate LTV + uint256 exitAmount = userShares / 10; // Try to exit 10% of shares + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_enterExitQueue_ltvViolation'); + vm.expectRevert(Errors.LowLtv.selector); + vault.enterExitQueue(exitAmount, owner); + _stopSnapshotGas(); + + // Verify that burning some OsToken shares first would allow entering exit queue + uint128 burnAmount = uint128(maxOsTokenShares / 5); // Burn 20% of OsToken position + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + vault.burnOsToken(burnAmount); + + // Now should be able to enter exit queue + vm.prank(owner); + vault.enterExitQueue(exitAmount, owner); + } + + // Test fee syncing for existing positions + function test_mintOsToken_feeSync() public { + // First mint to create position + uint256 firstMintShares = contracts.osTokenVaultController.convertToShares(1 ether); + + // Expect OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, owner, 0, firstMintShares, referrer); + + vm.prank(owner); + vault.mintOsToken(owner, firstMintShares, referrer); + + // Simulate time passing and reward accumulation to change cumulativeFeePerShare + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + vm.roll(block.number + 1000); + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Update controller state to change cumulativeFeePerShare + vault.updateState(harvestParams); + osTokenVaultController.updateState(); + + // Record position before second mint + uint256 positionBefore = vault.osTokenPositions(owner); + + // Expect OsTokenMinted event for second mint + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, owner, 0, firstMintShares / 2, referrer); + + // Mint more OsToken shares + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_feeSync'); + vault.mintOsToken(owner, firstMintShares / 2, referrer); + _stopSnapshotGas(); + + // Position should increase by more than the mint amount due to fee sync + vm.warp(vm.getBlockTimestamp() + 1 days); + uint256 positionAfter = vault.osTokenPositions(owner); + assertGt( + positionAfter, + positionBefore + firstMintShares / 2, + 'Position should increase more than mint amount due to fee sync' + ); + } + + // Test zero shares + function test_mintOsToken_zeroShares() public { + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_zeroShares'); + vm.expectRevert(Errors.InvalidShares.selector); + vault.mintOsToken(receiver, 0, referrer); + _stopSnapshotGas(); + } + + function test_mintOsToken_zeroAddressReceiver() public { + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + + // Try to mint to the zero address + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_zeroAddressReceiver'); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.mintOsToken(address(0), mintAmount, referrer); + _stopSnapshotGas(); + } + + // Test when vault is not collateralized + function test_mintOsToken_notCollateralized() public { + // Create a new vault that is not collateralized + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'test' + }) + ); + address newVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault newVault = EthVault(payable(newVaultAddr)); + + // Deposit to vault + _depositToVault(address(newVault), depositAmount, owner, owner); + + // Try to mint OsToken with uncollateralized vault + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_notCollateralized'); + vm.expectRevert(Errors.NotCollateralized.selector); + newVault.mintOsToken(receiver, mintAmount, referrer); + _stopSnapshotGas(); + } + + // Test when vault is not harvested + function test_mintOsToken_notHarvested() public { + // Set up reward parameters but don't harvest + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.5 ether)), + 0 + ); + + // Force vault to need harvesting + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Try to mint OsToken when vault needs harvesting + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_notHarvested'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.mintOsToken(receiver, mintAmount, referrer); + _stopSnapshotGas(); + + // Update state and try again - should work + vault.updateState(harvestParams); + + // Expect OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, mintAmount, referrer); + + vm.prank(owner); + uint256 assets = vault.mintOsToken(receiver, mintAmount, referrer); + assertGt(assets, 0, 'Should mint after harvesting'); + } + + // Test repeated minting until max + function test_mintOsToken_repeatedMinting() public { + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate max OsToken shares + uint256 userAssets = vault.convertToAssets(vault.getShares(owner)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Mint in small increments until approaching max + uint256 incrementAmount = maxOsTokenShares / 10; + uint256 totalMinted = 0; + + for (uint i = 0; i < 9; i++) { + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_repeatedMinting'); + uint256 assets = vault.mintOsToken(receiver, incrementAmount, referrer); + _stopSnapshotGas(); + + assertGt(assets, 0, 'Should be able to mint'); + totalMinted += incrementAmount; + } + + // Try to mint more than remaining max + uint256 remaining = maxOsTokenShares - totalMinted; + vm.prank(owner); + vm.expectRevert(Errors.LowLtv.selector); + vault.mintOsToken(receiver, remaining + 1, referrer); + + // Mint exactly the remaining amount - should succeed + vm.prank(owner); + uint256 finalAssets = vault.mintOsToken(receiver, remaining, referrer); + assertGt(finalAssets, 0, 'Should be able to mint exact remaining amount'); + } + + // Test minting to different receivers + function test_mintOsToken_multipleReceivers() public { + address receiver1 = makeAddr('receiver1'); + address receiver2 = makeAddr('receiver2'); + + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + + // Mint to first receiver + vm.prank(owner); + uint256 assets1 = vault.mintOsToken(receiver1, mintAmount, referrer); + assertGt(assets1, 0, 'Should mint to first receiver'); + + // Mint to second receiver + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_multipleReceivers'); + uint256 assets2 = vault.mintOsToken(receiver2, mintAmount, referrer); + _stopSnapshotGas(); + assertGt(assets2, 0, 'Should mint to second receiver'); + + // Verify position is tracked against owner regardless of receiver + uint256 ownerPosition = vault.osTokenPositions(owner); + assertEq(ownerPosition, mintAmount * 2, 'Owner position should track all minting'); + } + + // Test basic burn functionality + function test_burnOsToken_basic() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Verify initial position + uint256 initialPosition = vault.osTokenPositions(owner); + assertEq(initialPosition, mintAmount, 'Initial position should equal minted amount'); + + // Burn a portion of shares + uint128 burnAmount = uint128(mintAmount / 2); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_basic'); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq( + remainingPosition, + initialPosition - burnAmount, + 'Position should be reduced by burn amount' + ); + + // Verify assets were returned + assertGt(burnedAssets, 0, 'Should return positive asset amount'); + } + + // Test burning all shares + function test_burnOsToken_allShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Verify initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Burn all shares + uint128 burnAmount = uint128(initialPosition); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_allShares'); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, 0, 'Position should be zero after burning all shares'); + + // Verify assets were returned + assertGt(burnedAssets, 0, 'Should return positive asset amount'); + } + + // Test attempting to burn zero shares + function test_burnOsToken_zeroShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to burn zero shares + uint128 burnAmount = 0; + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_zeroShares'); + vm.expectRevert(Errors.InvalidShares.selector); + vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + } + + // Test attempting to burn more shares than owned + function test_burnOsToken_exceedingShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to burn more than owned + uint128 burnAmount = uint128(mintAmount * 2); + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_exceedingShares'); + vm.expectRevert(); // Should revert, possibly with an arithmetic underflow + vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + } + + // Test burning with non-existent position + function test_burnOsToken_invalidPosition() public { + // Use a different address that has no position + address nonPositionHolder = makeAddr('nonPositionHolder'); + + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(nonPositionHolder, mintAmount, referrer); + + uint128 burnAmount = 1000; + vm.prank(nonPositionHolder); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_invalidPosition'); + vm.expectRevert(Errors.InvalidPosition.selector); + vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + } + + // Test burning after fee sync + function test_burnOsToken_afterFeeSync() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Simulate time passing and reward accumulation + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + vm.roll(block.number + 1000); + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Update states to trigger fee sync + vault.updateState(harvestParams); + osTokenVaultController.updateState(); + + // Position should have grown due to fee sync + uint256 positionAfterFeeSync = vault.osTokenPositions(owner); + assertGt(positionAfterFeeSync, initialPosition, 'Position should increase after fee sync'); + + // Burn a portion of shares + uint128 burnAmount = uint128(mintAmount / 2); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_afterFeeSync'); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertLt(remainingPosition, positionAfterFeeSync, 'Position should decrease after burning'); + assertGt(burnedAssets, 0, 'Should return positive asset amount'); + } + + // Test multiple burn operations + function test_burnOsToken_multipleBurns() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(2 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Verify initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Burn in multiple steps + uint128 burnAmount1 = uint128(mintAmount / 4); + uint128 burnAmount2 = uint128(mintAmount / 4); + + // Expect OsTokenBurned event for first burn + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount1); + + // First burn + vm.prank(owner); + uint256 burnedAssets1 = vault.burnOsToken(burnAmount1); + + // Verify position after first burn + uint256 positionAfterFirstBurn = vault.osTokenPositions(owner); + assertEq( + positionAfterFirstBurn, + initialPosition - burnAmount1, + 'Position incorrect after first burn' + ); + + // Expect OsTokenBurned event for second burn + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount2); + + // Second burn + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_multipleBurns'); + uint256 burnedAssets2 = vault.burnOsToken(burnAmount2); + _stopSnapshotGas(); + + // Verify position after second burn + uint256 positionAfterSecondBurn = vault.osTokenPositions(owner); + assertEq( + positionAfterSecondBurn, + initialPosition - burnAmount1 - burnAmount2, + 'Position incorrect after second burn' + ); + + assertGt(burnedAssets1, 0, 'First burn should return positive assets'); + assertGt(burnedAssets2, 0, 'Second burn should return positive assets'); + } + + // Test that burn succeeds when it would have previously violated LTV + function test_burnOsToken_improvesLTV() public { + // First mint maximum OsToken shares + uint256 userShares = vault.getShares(owner); + uint256 userAssets = vault.convertToAssets(userShares); + + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Mint maximum OsToken shares + vm.prank(owner); + vault.mintOsToken(owner, maxOsTokenShares, referrer); + + // Try to enter exit queue with some shares - should fail due to LTV + uint256 exitAmount = userShares / 10; + vm.prank(owner); + vm.expectRevert(Errors.LowLtv.selector); + vault.enterExitQueue(exitAmount, owner); + + // Now burn some OsToken shares + uint128 burnAmount = uint128(maxOsTokenShares / 5); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_improvesLTV'); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + assertGt(burnedAssets, 0, 'Should return positive asset amount'); + + // Now should be able to enter exit queue + vm.prank(owner); + vault.enterExitQueue(exitAmount, owner); + } + + // Test that only the redeemer can call redeemOsToken + function test_redeemOsToken_onlyRedeemer() public { + // Create a position first + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem as non-redeemer + address nonRedeemer = makeAddr('nonRedeemer'); + vm.prank(nonRedeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_onlyRedeemer'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.redeemOsToken(mintAmount, owner, receiver); + _stopSnapshotGas(); + + // Get current redeemer + address redeemer = osTokenConfig.redeemer(); + vm.prank(redeemer); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + + // Verify position was reduced + assertLt( + vault.osTokenPositions(owner), + mintAmount, + 'Position should be reduced after redemption' + ); + } + + // Test basic redemption functionality + function test_redeemOsToken_basic() public { + // Create a position first + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Initial position + uint256 initialPosition = vault.osTokenPositions(owner); + uint256 initialReceiverBalance = receiver.balance; + + // Get current redeemer and perform redemption + address redeemer = osTokenConfig.redeemer(); + uint256 redeemAmount = mintAmount / 2; + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, redeemAmount, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_basic'); + vault.redeemOsToken(redeemAmount, owner, receiver); + _stopSnapshotGas(); + + // Verify position was updated correctly + uint256 finalPosition = vault.osTokenPositions(owner); + assertEq( + finalPosition, + initialPosition - redeemAmount, + 'Position should be reduced by redemption amount' + ); + + // Verify receiver got the assets + assertGt(receiver.balance, initialReceiverBalance, 'Receiver should receive assets'); + } + + // Test redemption with non-existent position + function test_redeemOsToken_nonExistentPosition() public { + // Try to redeem from an address with no position + address noPositionAddr = makeAddr('noPosition'); + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_nonExistentPosition'); + vm.expectRevert(Errors.InvalidPosition.selector); + vault.redeemOsToken(1 ether, noPositionAddr, receiver); + _stopSnapshotGas(); + } + + // Test redemption with insufficient shares + function test_redeemOsToken_insufficientShares() public { + // Create a small position + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem more than available + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_insufficientShares'); + vm.expectRevert(); // Should revert due to arithmetic underflow + vault.redeemOsToken(mintAmount * 2, owner, receiver); + _stopSnapshotGas(); + } + + // Test redemption after fee sync occurs + function test_redeemOsToken_afterFeeSync() public { + // Create a position first + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Simulate time passing and reward accumulation + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + vm.roll(block.number + 1000); + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Update states to trigger fee sync + vault.updateState(harvestParams); + osTokenVaultController.updateState(); + + // Position should have grown due to fee sync + uint256 positionAfterFeeSync = vault.osTokenPositions(owner); + assertGt(positionAfterFeeSync, initialPosition, 'Position should increase after fee sync'); + + // Redeem a portion of shares + uint256 redeemAmount = mintAmount / 2; + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, redeemAmount, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_afterFeeSync'); + vault.redeemOsToken(redeemAmount, owner, receiver); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertLt(remainingPosition, positionAfterFeeSync, 'Position should decrease after redemption'); + } + + // Test redemption with health factor above liquidation threshold + function test_redeemOsToken_goodHealthFactor() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Health factor is good at this point + + // Redemption should work even with good health factor + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount / 2, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_goodHealthFactor'); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + _stopSnapshotGas(); + + // Verify position was updated + assertLt( + vault.osTokenPositions(owner), + mintAmount, + 'Position should be reduced after redemption' + ); + } + + // Test redemption with zero address receiver + function test_redeemOsToken_zeroAddressReceiver() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem to zero address + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_zeroAddressReceiver'); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.redeemOsToken(mintAmount / 2, owner, address(0)); + _stopSnapshotGas(); + } + + // Test redemption with zero shares + function test_redeemOsToken_zeroShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem zero shares + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_zeroShares'); + vm.expectRevert(); // Will revert but not with Errors.InvalidShares since validation happens at different point + vault.redeemOsToken(0, owner, receiver); + _stopSnapshotGas(); + } + + // Test full redemption of position + function test_redeemOsToken_fullPosition() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Redeem entire position + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_fullPosition'); + vault.redeemOsToken(mintAmount, owner, receiver); + _stopSnapshotGas(); + + // Verify position is zero + uint256 finalPosition = vault.osTokenPositions(owner); + assertEq(finalPosition, 0, 'Position should be zero after full redemption'); + } + + // Test redemption after state update + function test_redeemOsToken_afterStateUpdate() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Force state update required + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Vault needs harvesting at this point + assertTrue(contracts.keeper.isHarvestRequired(address(vault)), 'Vault should need harvesting'); + + // Try to redeem - should fail due to not harvested + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + _stopSnapshotGas(); + + // Update state + vault.updateState(harvestParams); + + // Now redemption should work + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount / 2, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success'); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + _stopSnapshotGas(); + + // Verify position was updated + assertLt( + vault.osTokenPositions(owner), + mintAmount, + 'Position should be reduced after redemption' + ); + } + + // Test comparison between liquidation and redemption + function test_redeemVsLiquidate() public { + // First mint maximum OsToken shares + uint256 userShares = vault.getShares(owner); + uint256 userAssets = vault.convertToAssets(userShares); + + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Mint maximum OsToken shares + vm.prank(owner); + vault.mintOsToken(owner, maxOsTokenShares, referrer); + + // Enter exit queue with almost all vault shares to create poor health factor + uint256 exitAmount = (userShares * 90) / 100; // Exit 90% of shares + vm.prank(owner); + vm.expectRevert(Errors.LowLtv.selector); // Should fail due to poor health factor + vault.enterExitQueue(exitAmount, owner); + + // Try to liquidate - will fail because health factor not below threshold yet + address liquidator = makeAddr('liquidator'); + vm.prank(liquidator); + vm.expectRevert(Errors.InvalidHealthFactor.selector); + vault.liquidateOsToken(maxOsTokenShares / 2, owner, liquidator); + + // But redeemer can redeem regardless of health factor + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, maxOsTokenShares / 2, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas('VaultOsTokenTest_test_redeemVsLiquidate'); + vault.redeemOsToken(maxOsTokenShares / 2, owner, receiver); + _stopSnapshotGas(); + + // Verify redemption worked + assertLt( + vault.osTokenPositions(owner), + maxOsTokenShares, + 'Position should be reduced after redemption' + ); + } + + // Test basic liquidation functionality + function test_liquidateOsToken_basic() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get vault state and configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + int256 requiredPenalty = int256(vault.totalAssets()) - + int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + // Apply the penalty + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(requiredPenalty), + 0 + ); + vault.updateState(harvestParams); + + // Verify the position is now liquidatable + address liquidator = makeAddr('liquidator'); + uint256 liquidatorInitialBalance = liquidator.balance; + _mintOsToken(liquidator, osTokenShares); + + // Expect OsTokenLiquidated event + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + osTokenShares, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Perform liquidation + vm.prank(liquidator); + _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_basic'); + vault.liquidateOsToken(osTokenShares, owner, liquidator); + _stopSnapshotGas(); + + // Verify liquidation results + assertApproxEqAbs( + vault.osTokenPositions(owner), + 0, + 0.0001 ether, + 'Position should be reduced after liquidation' + ); + assertGt(liquidator.balance, liquidatorInitialBalance, 'Liquidator should receive assets'); + } + + // Test liquidation bonus calculation + function test_liquidateOsToken_bonus() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate and apply penalty to make position liquidatable + int256 requiredPenalty = int256(vault.totalAssets()) - + int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(requiredPenalty), + 0 + ); + vault.updateState(harvestParams); + + // Calculate expected bonus + uint256 liquidationAmount = osTokenShares / 4; + uint256 normalAssets = osTokenVaultController.convertToAssets(liquidationAmount); + uint256 expectedAssets = (normalAssets * config.liqBonusPercent) / 1e18; + + // Prepare liquidator + address liquidator = makeAddr('liquidator'); + uint256 liquidatorInitialBalance = liquidator.balance; + _mintOsToken(liquidator, liquidationAmount); + + // Expect OsTokenLiquidated event + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + liquidationAmount, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Perform liquidation + vm.prank(liquidator); + _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_bonus'); + vault.liquidateOsToken(liquidationAmount, owner, liquidator); + _stopSnapshotGas(); + + // Verify liquidator received a bonus + uint256 receivedAssets = liquidator.balance - liquidatorInitialBalance; + assertGt(receivedAssets, normalAssets, 'Liquidator should receive bonus'); + + // Check the bonus is approximately as expected (with some tolerance for gas costs) + uint256 tolerance = expectedAssets / 20; // 5% tolerance + assertApproxEqAbs( + receivedAssets, + expectedAssets, + tolerance, + 'Received assets should match expected bonus calculation' + ); + } + + // Test that liquidation is disabled when configured + function test_liquidateOsToken_liquidationDisabled() public { + // Create a vault with disabled liquidations + address adminWithDisabledLiq = makeAddr('adminWithDisabledLiq'); + vm.deal(adminWithDisabledLiq, 100 ether); + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'test' + }) + ); + + address vaultAddr = _getOrCreateVault( + VaultType.EthVault, + adminWithDisabledLiq, + initParams, + false + ); + EthVault vaultWithDisabledLiq = EthVault(payable(vaultAddr)); + + // Disable liquidations + vm.startPrank(Ownable(address(osTokenConfig)).owner()); + IOsTokenConfig.Config memory disabledLiqConfig = IOsTokenConfig.Config({ + ltvPercent: 0.9999 ether, + liqThresholdPercent: type(uint64).max, // Disable liquidations + liqBonusPercent: 0 + }); + osTokenConfig.updateConfig(address(vaultWithDisabledLiq), disabledLiqConfig); + vm.stopPrank(); + + // Deposit to vault and collateralize + address vaultOwner = makeAddr('vaultOwner'); + vm.deal(vaultOwner, 100 ether); + _depositToVault(address(vaultWithDisabledLiq), 50 ether, vaultOwner, vaultOwner); + _collateralizeEthVault(address(vaultWithDisabledLiq)); + + // Create a position + vm.prank(vaultOwner); + uint256 osTokenAssets = vaultWithDisabledLiq.mintOsToken( + vaultOwner, + type(uint256).max, + referrer + ); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Apply severe penalty + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vaultWithDisabledLiq), + int160(int256(-10 ether)), + 0 + ); + vaultWithDisabledLiq.updateState(harvestParams); + + // Prepare liquidator + address liquidator = makeAddr('liquidator'); + uint256 liquidationAmount = osTokenShares / 4; + _mintOsToken(liquidator, liquidationAmount); + + // Try to liquidate - should fail because liquidations are disabled + vm.prank(liquidator); + _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_liquidationDisabled'); + vm.expectRevert(Errors.LiquidationDisabled.selector); + vaultWithDisabledLiq.liquidateOsToken(liquidationAmount, vaultOwner, liquidator); + _stopSnapshotGas(); + } + + // Test that liquidation fails if vault is not harvested + function test_liquidateOsToken_notHarvested() public { + _setEthVaultReward(address(vault), 0, 0); + _setEthVaultReward(address(vault), 0, 0); + + _startSnapshotGas('VaultOsTokenTest_test_test_liquidateOsToken_notHarvested'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.liquidateOsToken(1 ether, owner, owner); + _stopSnapshotGas(); + } + + // Test partial liquidation + function test_liquidateOsToken_partialLiquidation() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate and apply penalty to make position liquidatable + int256 requiredPenalty = int256(vault.totalAssets()) - + int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(requiredPenalty), + 0 + ); + vault.updateState(harvestParams); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Prepare for partial liquidation + address liquidator = makeAddr('liquidator'); + uint256 liquidationAmount = osTokenShares / 3; + _mintOsToken(liquidator, liquidationAmount); + + // Expect OsTokenLiquidated event for first liquidation + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + liquidationAmount, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Perform first liquidation + vm.prank(liquidator); + _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_partialLiquidation'); + vault.liquidateOsToken(liquidationAmount, owner, liquidator); + _stopSnapshotGas(); + + // Verify position is reduced correctly + uint256 positionAfterLiquidation = vault.osTokenPositions(owner); + assertEq( + positionAfterLiquidation, + initialPosition - liquidationAmount, + 'Position should be reduced by liquidation amount' + ); + + // Prepare for second liquidation + uint256 remainingAmount = osTokenShares - liquidationAmount; + _mintOsToken(liquidator, remainingAmount); + + // Expect OsTokenLiquidated event for second liquidation + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + remainingAmount, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Liquidate remainder and verify position becomes zero + vm.prank(liquidator); + vault.liquidateOsToken(remainingAmount, owner, liquidator); + + assertApproxEqAbs( + vault.osTokenPositions(owner), + 0, + 0.0001 ether, + 'Position should be zero after complete liquidation' + ); + } + + function test_liquidateOsToken_invalidReceivedAssets() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get vault state and configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + int256 requiredPenalty = int256(vault.totalAssets()) - + int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + // Apply the penalty + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(requiredPenalty), + 0 + ); + vault.updateState(harvestParams); + + // Verify the position is now liquidatable + address liquidator = makeAddr('liquidator'); + _mintOsToken(liquidator, osTokenShares); + + // remove withdrawable assets + vm.deal(address(vault), address(vault).balance - vault.withdrawableAssets()); + + // Perform liquidation + vm.prank(liquidator); + _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_invalidReceivedAssets'); + vm.expectRevert(Errors.InvalidReceivedAssets.selector); + vault.liquidateOsToken(osTokenShares, owner, liquidator); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_basic() public { + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); + + // First mint some osToken shares + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + assertEq(initialPosition, osTokenShares, 'Initial position incorrect'); + + // Transfer osToken position to escrow + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_basic'); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + + // Verify osToken position is transferred (should be zero) + uint256 afterTransferPosition = vault.osTokenPositions(owner); + assertEq(afterTransferPosition, 0, 'osToken position was not fully transferred'); + + // Verify position in escrow + (address escrowOwner, uint256 exitedAssets, uint256 escrowOsTokenShares) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + assertEq(escrowOwner, owner, 'Incorrect owner in escrow position'); + assertEq(exitedAssets, 0, 'Exited assets should be zero initially'); + assertEq(escrowOsTokenShares, osTokenShares, 'Incorrect osToken shares in escrow'); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Ensure enough time has passed for claiming + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Process the exited assets + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process'); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + uint256(vault.getExitQueueIndex(exitPositionTicket)) + ); + _stopSnapshotGas(); + + // Record user's ETH balance before claiming + uint256 ownerBalanceBefore = owner.balance; + + // Claim exited assets + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_claim'); + uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares + ); + _stopSnapshotGas(); + + // Verify assets were received + uint256 ownerBalanceAfter = owner.balance; + assertEq( + ownerBalanceAfter - ownerBalanceBefore, + claimedAssets, + 'Incorrect amount of assets transferred' + ); + assertGt(claimedAssets, 0, 'No assets were claimed'); + } + + function test_transferOsTokenPositionToEscrow_zeroShares() public { + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Try to transfer zero shares + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares'); + vm.expectRevert(Errors.InvalidShares.selector); + vault.transferOsTokenPositionToEscrow(0); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_moreThanOwned() public { + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Try to transfer more shares than owned + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_moreThanOwned'); + vm.expectRevert(Errors.InvalidShares.selector); + vault.transferOsTokenPositionToEscrow(osTokenShares * 2); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_notHarvested() public { + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Force vault to need harvesting + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Try to transfer when vault needs harvesting + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_noPosition() public { + // Try to transfer with no position + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_noPosition'); + vm.expectRevert(Errors.InvalidPosition.selector); + vault.transferOsTokenPositionToEscrow(1 ether); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_partialTransfer() public { + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); + + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(2 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Transfer half of the position + uint256 transferAmount = osTokenShares / 2; + + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer'); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(transferAmount); + _stopSnapshotGas(); + + // Verify remaining position + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, osTokenShares - transferAmount, 'Remaining position incorrect'); + + // Verify position in escrow + (address escrowOwner, , uint256 escrowOsTokenShares) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + + assertEq(escrowOwner, owner, 'Incorrect owner in escrow position'); + assertEq(escrowOsTokenShares, transferAmount, 'Incorrect osToken shares in escrow'); + } + + function test_transferOsTokenPositionToEscrow_maxAmount() public { + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); + + // Mint maximum osToken shares + vm.prank(owner); + vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 mintedShares = vault.osTokenPositions(owner); + + // Transfer all minted shares + vm.prank(owner); + _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_maxAmount'); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(mintedShares); + _stopSnapshotGas(); + + // Verify position in escrow + (address escrowOwner, , uint256 escrowOsTokenShares) = contracts.osTokenVaultEscrow.getPosition( + address(vault), + exitPositionTicket + ); + + assertEq(escrowOwner, owner, 'Incorrect owner in escrow position'); + assertEq(escrowOsTokenShares, mintedShares, 'Incorrect osToken shares in escrow'); + + // Verify position is fully transferred + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, 0, 'Position should be fully transferred'); + } +} diff --git a/test/VaultState.t.sol b/test/VaultState.t.sol new file mode 100644 index 00000000..562c0e2c --- /dev/null +++ b/test/VaultState.t.sol @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; +import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract VaultStateTest is Test, EthHelpers { + ForkContracts public contracts; + EthVault public vault; + + address public owner; + address public user1; + address public user2; + address public admin; + + uint256 public initialDeposit = 10 ether; + + function setUp() public { + // Set up the test environment + contracts = _activateEthereumFork(); + + // Setup test accounts + owner = makeAddr('owner'); + user1 = makeAddr('user1'); + user2 = makeAddr('user2'); + admin = makeAddr('admin'); + + // Fund accounts + vm.deal(owner, 100 ether); + vm.deal(user1, 100 ether); + vm.deal(user2, 100 ether); + vm.deal(admin, 100 ether); + + // Create a vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + vm.deal(vaultAddr, vault.totalExitingAssets() + vault.convertToAssets(vault.queuedShares())); + + // Initial deposit to the vault + _depositToVault(address(vault), initialDeposit, owner, owner); + + // Collateralize the vault + _collateralizeEthVault(address(vault)); + } + + // Test conversion functions + function test_conversion() public view { + // Test convertToShares() + uint256 assetAmount = 1 ether; + uint256 shares = vault.convertToShares(assetAmount); + assertGt(shares, 0, 'Shares converted from assets should be greater than 0'); + + // Test convertToAssets() + uint256 shareAmount = 1 ether; + uint256 assets = vault.convertToAssets(shareAmount); + assertGt(assets, 0, 'Assets converted from shares should be greater than 0'); + + // Test round-trip conversion + uint256 originalAssets = 2 ether; + uint256 convertedShares = vault.convertToShares(originalAssets); + uint256 convertedBackAssets = vault.convertToAssets(convertedShares); + assertApproxEqAbs( + convertedBackAssets, + originalAssets, + 1, + 'Round-trip conversion should approximately preserve value' + ); + } + + // Test withdrawable assets + function test_withdrawableAssets() public { + // Test withdrawableAssets() before exit queue + uint256 withdrawableBefore = vault.withdrawableAssets(); + + // Enter exit queue with half of owner's shares + uint256 ownerShares = vault.getShares(owner); + uint256 exitShares = ownerShares / 2; + + vm.prank(owner); + vault.enterExitQueue(exitShares, owner); + + // Test withdrawableAssets() after exit queue + uint256 withdrawableAfter = vault.withdrawableAssets(); + uint256 exitingAssets = vault.convertToAssets(exitShares); + assertEq( + withdrawableAfter, + withdrawableBefore - exitingAssets, + 'Exiting assets should reduce withdrawable assets' + ); + } + + // Test state update + function test_stateUpdate() public { + // Force state update required + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(0.1 ether)), + 0 + ); + + // Test isStateUpdateRequired() + bool needsUpdate = contracts.keeper.isHarvestRequired(address(vault)); + assertTrue(needsUpdate, 'Vault should need state update'); + + // Test updateState() + uint256 totalAssetsBefore = vault.totalAssets(); + vault.updateState(harvestParams); + uint256 totalAssetsAfter = vault.totalAssets(); + assertGt( + totalAssetsAfter, + totalAssetsBefore, + 'Total assets should increase after positive reward' + ); + } + + // Test update state called multiple times without new rewards + function test_updateState_multiple_calls() public { + // Apply a reward + int160 rewardAmount = int160(int256(0.5 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + rewardAmount, + 0 + ); + + // First update + vault.updateState(harvestParams); + uint256 totalAssetsAfterFirstUpdate = vault.totalAssets(); + + // Second update with same params (should be no-op) + vault.updateState(harvestParams); + uint256 totalAssetsAfterSecondUpdate = vault.totalAssets(); + + // Verify assets didn't change after second update + assertEq( + totalAssetsAfterSecondUpdate, + totalAssetsAfterFirstUpdate, + "Assets shouldn't change on second update with same params" + ); + } + + // Test process total assets delta with positive reward + function test_processTotalAssetsDelta_positiveReward() public { + // Apply positive reward + int160 rewardAmount = int160(int256(0.5 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + rewardAmount, + 0 + ); + + // Get initial values + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + address feeRecipient = vault.feeRecipient(); + + // Update state to process reward + vm.expectEmit(true, true, true, false); + emit IVaultState.FeeSharesMinted(feeRecipient, 0, 0); + vault.updateState(harvestParams); + + // Verify total assets increased + uint256 finalTotalAssets = vault.totalAssets(); + assertGt(finalTotalAssets, initialTotalAssets, 'Total assets should increase after reward'); + + // Verify fee recipient received shares + uint256 feeRecipientShares = vault.getShares(feeRecipient); + assertGt(feeRecipientShares, 0, 'Fee recipient should receive shares'); + + // Verify total shares increased + uint256 finalTotalShares = vault.totalShares(); + assertGt(finalTotalShares, initialTotalShares, 'Total shares should increase after reward'); + } + + // Test process total assets delta with negative reward (penalty) + function test_processTotalAssetsDelta_negativeReward() public { + // Apply negative reward (penalty) + int160 penaltyAmount = -int160(int256(0.2 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + penaltyAmount, + 0 + ); + + // Get initial values + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + + // Update state to process penalty + vault.updateState(harvestParams); + + // Verify total assets decreased + uint256 finalTotalAssets = vault.totalAssets(); + assertLt(finalTotalAssets, initialTotalAssets, 'Total assets should decrease after penalty'); + + // Verify total shares remained the same (penalties don't affect shares) + uint256 finalTotalShares = vault.totalShares(); + assertEq( + finalTotalShares, + initialTotalShares, + 'Total shares should remain unchanged after penalty' + ); + } + + // Test penalty handling for exiting assets + function test_exiting_assets_penalty() public { + // Enter exit queue with half of owner's shares + uint256 ownerShares = vault.getShares(owner); + uint256 exitShares = ownerShares / 2; + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); + + vm.prank(owner); + uint256 positionTicket = vault.enterExitQueue(exitShares, owner); + uint256 timestamp = vm.getBlockTimestamp(); + + // Record expected exit assets before penalty + uint256 expectedExitAssets = vault.convertToAssets(exitShares); + + // Apply a penalty + int160 penaltyAmount = -int160(int256(0.2 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + penaltyAmount, + 0 + ); + + // Update state to process penalty and exit queue + vault.updateState(harvestParams); + + // Fast forward time + vm.warp(vm.getBlockTimestamp() + 1 days + 1); + + // Record owner's balance before claiming + uint256 ownerBalanceBefore = owner.balance; + + // Claim exited assets + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket)); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(owner, positionTicket, 0, 0); + vm.prank(owner); + vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + + // Verify the received assets are less than expected due to penalty + uint256 receivedAssets = owner.balance - ownerBalanceBefore; + assertLt( + receivedAssets, + expectedExitAssets, + 'Received assets should be less than expected due to penalty' + ); + } + + // Test exit queue processing + function test_exitQueue() public { + // Enter exit queue with half of owner's shares + uint256 ownerShares = vault.getShares(owner); + uint256 exitShares = ownerShares / 2; + + // Record owner's ETH balance before + uint256 ownerBalanceBefore = owner.balance; + uint256 queuedSharesBefore = vault.queuedShares(); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); + + // Enter exit queue + vm.prank(owner); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(exitShares, owner); + + // Verify share reduction + uint256 ownerSharesAfter = vault.getShares(owner); + assertEq( + ownerSharesAfter, + ownerShares - exitShares, + 'Owner shares should be reduced by exit amount' + ); + + // Verify queued shares increased + assertEq( + vault.queuedShares(), + queuedSharesBefore + exitShares, + 'Queued shares should match exit amount' + ); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams); + + // Fast forward time past the claiming delay + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Claim exited assets + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket)); + vm.prank(owner); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(owner, positionTicket, 0, 0); + vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + + // Verify owner received assets + uint256 ownerBalanceAfter = owner.balance; + assertGt(ownerBalanceAfter, ownerBalanceBefore, 'Owner should receive assets after claiming'); + } + + // Test minting and burning shares through deposit and exit + function test_mintBurnShares() public { + // Get initial total shares + uint256 initialTotalShares = vault.totalShares(); + + // Deposit more to mint shares + uint256 depositAmount = 5 ether; + _depositToVault(address(vault), depositAmount, user1, user1); + + // Verify total shares increased + uint256 totalSharesAfterMint = vault.totalShares(); + assertGt( + totalSharesAfterMint, + initialTotalShares, + 'Total shares should increase after deposit' + ); + + // Enter exit queue to burn shares + uint256 user1Shares = vault.getShares(user1); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); + + vm.prank(user1); + vault.enterExitQueue(user1Shares, user1); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams); + + // Verify total shares decreased after exit queue is processed + uint256 totalSharesAfterBurn = vault.totalShares(); + assertLt(totalSharesAfterBurn, totalSharesAfterMint, 'Total shares should decrease after exit'); + } + + // Test handling of multiple exit requests + function test_multipleExitRequests() public { + uint256 totalAssetsBefore = vault.totalAssets(); + + // Multiple users deposit + _depositToVault(address(vault), 5 ether, user1, user1); + _depositToVault(address(vault), 5 ether, user2, user2); + + // Users enter exit queue + uint256 user1Shares = vault.getShares(user1); + uint256 user2Shares = vault.getShares(user2); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); + + vm.prank(user1); + uint256 positionTicket1 = vault.enterExitQueue(user1Shares, user1); + uint256 timestamp1 = vm.getBlockTimestamp(); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user2, user2, 0, user2Shares); + + vm.prank(user2); + uint256 positionTicket2 = vault.enterExitQueue(user2Shares, user2); + uint256 timestamp2 = vm.getBlockTimestamp(); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams); + + // Fast forward time + vm.warp(vm.getBlockTimestamp() + 1 days + 1); + + // Both users claim exited assets + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket1)); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(user1, positionTicket1, 0, 0); + vm.prank(user1); + vault.claimExitedAssets(positionTicket1, timestamp1, exitQueueIndex); + + exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket2)); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(user2, positionTicket2, 0, 0); + vm.prank(user2); + vault.claimExitedAssets(positionTicket2, timestamp2, exitQueueIndex); + + // Verify withdrawable assets are restored + assertApproxEqAbs( + vault.totalAssets(), + totalAssetsBefore, + 2, + 'Total assets should be restored after all claims' + ); + } + + // Test entering exit queue when not collateralized + function test_exitQueue_notCollateralized() public { + // Create a new vault that is not collateralized + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'test' + }) + ); + address newVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault newVault = EthVault(payable(newVaultAddr)); + + // Deposit to vault + _depositToVault(address(newVault), 5 ether, user1, user1); + + // Enter exit queue in non-collateralized vault + uint256 user1Shares = newVault.getShares(user1); + + uint256 user1BalanceBefore = user1.balance; + + vm.expectEmit(true, true, true, true); + emit IVaultEnterExit.Redeemed(user1, user1, user1Shares, user1Shares); + + vm.prank(user1); + uint256 positionTicket = newVault.enterExitQueue(user1Shares, user1); + + // Verify immediate redemption + uint256 user1BalanceAfter = user1.balance; + assertGt(user1BalanceAfter, user1BalanceBefore, 'User should immediately receive assets'); + assertEq( + positionTicket, + type(uint256).max, + 'Position ticket should be max uint256 for immediate redemption' + ); + } + + // Test update exit queue with no queued shares + function test_updateExitQueue_noQueuedShares() public { + // No one has entered exit queue + + // Update state + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Should not revert and should be a no-op + vault.updateState(harvestParams); + } + + // Test an exit position processed across multiple checkpoints + function test_exitQueue_multipleCheckpoints() public { + // Step 1: User deposits a large amount + _depositToVault(address(vault), 20 ether, user1, user1); + + // Step 2: User enters exit queue with all shares + uint256 user1Shares = vault.getShares(user1); + + uint256 vaultBalance = vault.totalExitingAssets() + + vault.convertToAssets(vault.queuedShares()) + + address(vault).balance - + vault.withdrawableAssets(); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); + + vm.prank(user1); + uint256 positionTicket = vault.enterExitQueue(user1Shares, user1); + uint256 timestamp = vm.getBlockTimestamp(); + + // Step 3: Artificially limit vault assets by moving ETH out + uint256 exitAssetsNeeded = vault.convertToAssets(user1Shares); + + // Move ETH out to simulate limited availability (leave only 30% of what's needed) + uint256 partialAmount = (exitAssetsNeeded * 30) / 100; + vm.deal(address(vault), vaultBalance + partialAmount); + + // Step 4: Process first checkpoint with limited assets + IKeeperRewards.HarvestParams memory harvestParams1 = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + + vault.updateState(harvestParams1); + + // Step 5: Restore full assets for second checkpoint + vm.deal(address(vault), vaultBalance + exitAssetsNeeded); + + // Step 6: Process second checkpoint + IKeeperRewards.HarvestParams memory harvestParams2 = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams2); + + // Step 7: Fast forward time past the claiming delay + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Step 8: Claim exited assets + uint256 user1BalanceBefore = user1.balance; + + // Get the exit queue index + int256 exitQueueIndexInt = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndexInt, -1, 'Exit queue index should be valid'); + uint256 exitQueueIndex = uint256(exitQueueIndexInt); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(user1, positionTicket, 0, exitAssetsNeeded); + + vm.prank(user1); + vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + + // Step 9: Verify user received all expected assets despite multiple checkpoints + uint256 user1BalanceAfter = user1.balance; + uint256 receivedAssets = user1BalanceAfter - user1BalanceBefore; + + // The user should receive approximately what they put in, minor differences due to fees/rounding + assertApproxEqRel( + receivedAssets, + exitAssetsNeeded, + 0.01e18, // 1% tolerance + 'User should receive all expected assets across multiple checkpoints' + ); + } +} diff --git a/test/VaultToken.t.sol b/test/VaultToken.t.sol new file mode 100644 index 00000000..32407ae2 --- /dev/null +++ b/test/VaultToken.t.sol @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; +import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; +import {EthVaultFactory} from '../contracts/vaults/ethereum/EthVaultFactory.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; + +contract VaultTokenTest is Test, EthHelpers { + ForkContracts public contracts; + EthErc20Vault public vault; + + address public owner; + address public user1; + address public user2; + address public admin; + + uint256 public depositAmount = 5 ether; + + function setUp() public { + // Set up the test environment + contracts = _activateEthereumFork(); + + // Setup test accounts + owner = makeAddr('owner'); + user1 = makeAddr('user1'); + user2 = makeAddr('user2'); + admin = makeAddr('admin'); + + // Fund accounts + vm.deal(owner, 100 ether); + vm.deal(user1, 100 ether); + vm.deal(user2, 100 ether); + vm.deal(admin, 100 ether); + + // Create an EthErc20Vault which implements VaultToken module + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(vaultAddr)); + + // Initial deposit to the vault + _depositToVault(address(vault), depositAmount, owner, owner); + + // Collateralize the vault + _collateralizeEthVault(address(vault)); + } + + // Test basic metadata like name, symbol, decimals + function test_tokenMetadata() public { + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: 'SW ETH Vault', + symbol: 'SW-ETH-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(vaultAddr)); + assertEq(vault.name(), 'SW ETH Vault', 'Name should match initialization parameters'); + assertEq(vault.symbol(), 'SW-ETH-1', 'Symbol should match initialization parameters'); + assertEq(vault.decimals(), 18, 'Decimals should be 18'); + } + + // Test totalSupply and balanceOf functions + function test_totalSupplyAndBalanceOf() public { + // Initial values + uint256 initialTotalSupply = vault.totalSupply(); + uint256 initialBalance = vault.balanceOf(owner); + + // Should have positive values after initial deposit + assertGt(initialTotalSupply, 0, 'Total supply should be greater than 0'); + assertGt(initialBalance, 0, 'Owner balance should be greater than 0'); + + // Make another deposit to increase supply + _depositToVault(address(vault), depositAmount, user1, user1); + + // Verify total supply increased + uint256 newTotalSupply = vault.totalSupply(); + assertGt(newTotalSupply, initialTotalSupply, 'Total supply should increase after deposit'); + + // Verify user1's balance + uint256 user1Balance = vault.balanceOf(user1); + assertGt(user1Balance, 0, 'User1 balance should be greater than 0'); + } + + // Test transfer function + function test_transfer() public { + // Get initial balances + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 user1InitialBalance = vault.balanceOf(user1); + + // Transfer some tokens from owner to user1 + uint256 transferAmount = ownerInitialBalance / 2; + + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_transfer'); + bool success = vault.transfer(user1, transferAmount); + _stopSnapshotGas(); + + assertTrue(success, 'Transfer should succeed'); + + // Verify balances after transfer + uint256 ownerFinalBalance = vault.balanceOf(owner); + uint256 user1FinalBalance = vault.balanceOf(user1); + + assertEq( + ownerFinalBalance, + ownerInitialBalance - transferAmount, + 'Owner balance should decrease' + ); + assertEq( + user1FinalBalance, + user1InitialBalance + transferAmount, + 'User1 balance should increase' + ); + } + + // Test transferFrom function + function test_transferFrom() public { + // Get initial balances + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 user1InitialBalance = vault.balanceOf(user1); + + // Approve user1 to spend owner's tokens + uint256 approvalAmount = ownerInitialBalance / 2; + + vm.prank(owner); + vault.approve(user1, approvalAmount); + + // Check allowance + assertEq(vault.allowance(owner, user1), approvalAmount, 'Allowance should be set correctly'); + + // User1 transfers tokens from owner to themselves + vm.prank(user1); + _startSnapshotGas('VaultTokenTest_test_transferFrom'); + bool success = vault.transferFrom(owner, user1, approvalAmount); + _stopSnapshotGas(); + + assertTrue(success, 'TransferFrom should succeed'); + + // Verify balances after transfer + uint256 ownerFinalBalance = vault.balanceOf(owner); + uint256 user1FinalBalance = vault.balanceOf(user1); + + assertEq( + ownerFinalBalance, + ownerInitialBalance - approvalAmount, + 'Owner balance should decrease' + ); + assertEq( + user1FinalBalance, + user1InitialBalance + approvalAmount, + 'User1 balance should increase' + ); + + // Verify allowance was reduced + assertEq(vault.allowance(owner, user1), 0, 'Allowance should be reduced'); + } + + // Test approve function + function test_approve() public { + // Initial allowance should be 0 + assertEq(vault.allowance(owner, user1), 0, 'Initial allowance should be 0'); + + // Approve user1 to spend owner's tokens + uint256 approvalAmount = 100 ether; + + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_approve'); + bool success = vault.approve(user1, approvalAmount); + _stopSnapshotGas(); + + assertTrue(success, 'Approve should succeed'); + + // Verify allowance + assertEq(vault.allowance(owner, user1), approvalAmount, 'Allowance should be set correctly'); + + // Change approval + uint256 newApprovalAmount = 50 ether; + + vm.prank(owner); + success = vault.approve(user1, newApprovalAmount); + + assertTrue(success, 'Approve should succeed'); + + // Verify new allowance + assertEq(vault.allowance(owner, user1), newApprovalAmount, 'Allowance should be updated'); + } + + // Test unlimited allowance (MAX_UINT256) + function test_unlimitedAllowance() public { + // Approve user1 to spend unlimited tokens + uint256 maxUint = type(uint256).max; + + vm.prank(owner); + vault.approve(user1, maxUint); + + // Verify allowance + assertEq(vault.allowance(owner, user1), maxUint, 'Allowance should be set to max'); + + // Get initial balances + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 user1InitialBalance = vault.balanceOf(user1); + + // Transfer some tokens + uint256 transferAmount = ownerInitialBalance / 2; + + vm.prank(user1); + _startSnapshotGas('VaultTokenTest_test_unlimitedAllowance'); + vault.transferFrom(owner, user1, transferAmount); + _stopSnapshotGas(); + + // Verify allowance remains unchanged with unlimited approval + assertEq(vault.allowance(owner, user1), maxUint, 'Allowance should remain unchanged'); + + // Verify balances after transfer + uint256 ownerFinalBalance = vault.balanceOf(owner); + uint256 user1FinalBalance = vault.balanceOf(user1); + + assertEq( + ownerFinalBalance, + ownerInitialBalance - transferAmount, + 'Owner balance should decrease' + ); + assertEq( + user1FinalBalance, + user1InitialBalance + transferAmount, + 'User1 balance should increase' + ); + } + + // Test transfer to zero address + function test_transferToZeroAddress() public { + // Try to transfer to zero address + uint256 transferAmount = vault.balanceOf(owner) / 2; + + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_transferToZeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.transfer(address(0), transferAmount); + _stopSnapshotGas(); + } + + // Test transfer from zero address + function test_transferFromZeroAddress() public { + // Try to transfer from zero address (should be unreachable in practice) + uint256 transferAmount = 1 ether; + + // When transferring from address(0), the function will revert with an arithmetic error + // when checking allowances before it even gets to the zero address check + _startSnapshotGas('VaultTokenTest_test_transferFromZeroAddress'); + vm.expectRevert(); // Expect any revert, which will be an arithmetic underflow + vault.transferFrom(address(0), user1, transferAmount); + _stopSnapshotGas(); + } + + // Test approve zero address + function test_approveZeroAddress() public { + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_approveZeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.approve(address(0), 1 ether); + _stopSnapshotGas(); + } + + // Test transfer more than balance + function test_transferMoreThanBalance() public { + uint256 ownerBalance = vault.balanceOf(owner); + + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_transferMoreThanBalance'); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.transfer(user1, ownerBalance + 1); + _stopSnapshotGas(); + } + + // Test transferFrom more than balance + function test_transferFromMoreThanBalance() public { + uint256 ownerBalance = vault.balanceOf(owner); + + // Approve user1 to spend more than owner's balance + vm.prank(owner); + vault.approve(user1, ownerBalance * 2); + + vm.prank(user1); + _startSnapshotGas('VaultTokenTest_test_transferFromMoreThanBalance'); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.transferFrom(owner, user1, ownerBalance + 1); + _stopSnapshotGas(); + } + + // Test transferFrom more than allowance + function test_transferFromMoreThanAllowance() public { + uint256 ownerBalance = vault.balanceOf(owner); + uint256 allowanceAmount = ownerBalance / 2; + + // Approve user1 to spend half of owner's balance + vm.prank(owner); + vault.approve(user1, allowanceAmount); + + vm.prank(user1); + _startSnapshotGas('VaultTokenTest_test_transferFromMoreThanAllowance'); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.transferFrom(owner, user1, allowanceAmount + 1); + _stopSnapshotGas(); + } + + // Test enterExitQueue emits Transfer event + function test_enterExitQueueEmitsTransferEvent() public { + uint256 exitShares = vault.balanceOf(owner) / 2; + + // Expect a Transfer event from owner to vault + vm.expectEmit(true, true, true, true); + emit IERC20.Transfer(owner, address(vault), exitShares); + + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_enterExitQueueEmitsTransferEvent'); + vault.enterExitQueue(exitShares, owner); + _stopSnapshotGas(); + } + + // Test vault transfers shares to vault when entering exit queue + function test_enterExitQueueTransfersToVault() public { + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 exitShares = ownerInitialBalance / 2; + + vm.prank(owner); + vault.enterExitQueue(exitShares, owner); + + // Verify owner's balance decreased + uint256 ownerFinalBalance = vault.balanceOf(owner); + assertEq(ownerFinalBalance, ownerInitialBalance - exitShares, 'Owner balance should decrease'); + + // Verify queued shares + assertEq(vault.queuedShares(), exitShares, 'Queued shares should match exit amount'); + } + + // Test _updateExitQueue burns shares and emits Transfer + function test_updateExitQueueBurnsShares() public { + // First, enter exit queue + uint256 exitShares = vault.balanceOf(owner) / 2; + + vm.prank(owner); + vault.enterExitQueue(exitShares, owner); + + // Record total supply before update + uint256 totalSupplyBefore = vault.totalSupply(); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Expect a Transfer event to zero address for burned shares + vm.expectEmit(true, true, true, false); + emit IERC20.Transfer(address(vault), address(0), exitShares); + + // Update state to process exit queue + _startSnapshotGas('VaultTokenTest_test_updateExitQueueBurnsShares'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify total supply decreased + uint256 totalSupplyAfter = vault.totalSupply(); + assertLt(totalSupplyAfter, totalSupplyBefore, 'Total supply should decrease'); + assertApproxEqAbs( + totalSupplyBefore - totalSupplyAfter, + exitShares, + 2, // small tolerance for rounding + 'Decrease should match exit shares' + ); + } + + // Test transfers are blocked for osToken positions + function test_transferWithOsTokenPosition() public { + // First mint osToken to create a position + vm.prank(owner); + vault.mintOsToken(owner, type(uint256).max, address(0)); + + // Try to transfer more shares than allowed by LTV + uint256 transferAmount = vault.balanceOf(owner) / 2; + + vm.prank(owner); + _startSnapshotGas('VaultTokenTest_test_transferWithOsTokenPosition'); + vm.expectRevert(Errors.LowLtv.selector); + vault.transfer(user1, transferAmount); + _stopSnapshotGas(); + } + + // Test mint shares emits Transfer event + function test_depositEmitsTransferEvent() public { + // Expect Transfer event from zero address to user1 + uint256 depositTokens = 2 ether; + uint256 expectedShares = vault.convertToShares(depositTokens); + + vm.expectEmit(true, true, true, false); + emit IERC20.Transfer(address(0), user1, expectedShares); + + _startSnapshotGas('VaultTokenTest_test_depositEmitsTransferEvent'); + _depositToVault(address(vault), depositTokens, user1, user1); + _stopSnapshotGas(); + } + + // Test permit functionality (ERC-20 permit) + function test_permit() public { + uint256 privateKey = 0x1234; // Demo private key (never use in production) + address signer = vm.addr(privateKey); + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + assertEq(nonce, 0, 'Initial nonce should be 0'); + + // Create permit parameters + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp + 1 days; + + // Create signature + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = keccak256( + 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' + ); + + bytes32 structHash = keccak256( + abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline) + ); + + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + // Execute permit + _startSnapshotGas('VaultTokenTest_test_permit'); + vault.permit(signer, user1, permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + + // Verify allowance was set + assertEq(vault.allowance(signer, user1), permitAmount, 'Allowance should be set by permit'); + + // Verify nonce was incremented + assertEq(vault.nonces(signer), 1, 'Nonce should be incremented'); + } + + // Test using permit with invalid signer + function test_permitInvalidSigner() public { + uint256 privateKey = 0x1234; + address signer = vm.addr(privateKey); + uint256 wrongPrivateKey = 0x5678; + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + + // Create permit parameters + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp + 1 days; + + // Create signature with wrong key + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = keccak256( + 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' + ); + + bytes32 structHash = keccak256( + abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline) + ); + + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, digest); + + // Execute permit with invalid signature + _startSnapshotGas('VaultTokenTest_test_permitInvalidSigner'); + vm.expectRevert(Errors.PermitInvalidSigner.selector); + vault.permit(signer, user1, permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with expired deadline + function test_permitExpiredDeadline() public { + uint256 privateKey = 0x1234; + address signer = vm.addr(privateKey); + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + + // Create permit parameters with expired deadline + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp - 1; // Expired + + // Create signature + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = keccak256( + 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' + ); + + bytes32 structHash = keccak256( + abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline) + ); + + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + // Execute permit with expired deadline + _startSnapshotGas('VaultTokenTest_test_permitExpiredDeadline'); + vm.expectRevert(Errors.DeadlineExpired.selector); + vault.permit(signer, user1, permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with zero address spender + function test_permitZeroAddressSpender() public { + uint256 privateKey = 0x1234; + address signer = vm.addr(privateKey); + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + + // Create permit parameters with zero address spender + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp + 1 days; + + // Create signature + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = keccak256( + 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' + ); + + bytes32 structHash = keccak256( + abi.encode( + permitTypehash, + signer, + address(0), // Zero address + permitAmount, + nonce, + deadline + ) + ); + + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + // Execute permit with zero address spender + _startSnapshotGas('VaultTokenTest_test_permitZeroAddressSpender'); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.permit(signer, address(0), permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test InvalidTokenMeta error for token name too long + function test_invalidTokenMetaNameTooLong() public { + // Create a new admin for this test + address newAdmin = makeAddr('newAdmin'); + vm.deal(newAdmin, 10 ether); + + // Try to create vault with name longer than 30 characters + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: 'This is a very long name that exceeds thirty characters limit for ERC20 tokens', + symbol: 'LONG', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + EthVaultFactory factory = _getOrCreateFactory(VaultType.EthErc20Vault); + vm.deal(admin, admin.balance + _securityDeposit); + + _startSnapshotGas('VaultTokenTest_test_invalidTokenMetaNameTooLong'); + vm.expectRevert(Errors.InvalidTokenMeta.selector); + vm.prank(admin); + factory.createVault{value: _securityDeposit}(initParams, true); + _stopSnapshotGas(); + } + + // Test InvalidTokenMeta error for token symbol too long + function test_invalidTokenMetaSymbolTooLong() public { + // Create a new admin for this test + address newAdmin = makeAddr('newAdmin'); + vm.deal(newAdmin, 10 ether); + + // Try to create vault with symbol longer than 10 characters + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: 'Valid Name', + symbol: 'VERYLONGSYMBOL', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + EthVaultFactory factory = _getOrCreateFactory(VaultType.EthErc20Vault); + vm.deal(admin, admin.balance + _securityDeposit); + + _startSnapshotGas('VaultTokenTest_test_invalidTokenMetaSymbolTooLong'); + vm.expectRevert(Errors.InvalidTokenMeta.selector); + vm.prank(admin); + factory.createVault{value: _securityDeposit}(initParams, false); + _stopSnapshotGas(); + } +} diff --git a/test/VaultValidators.t.sol b/test/VaultValidators.t.sol new file mode 100644 index 00000000..5769e9f3 --- /dev/null +++ b/test/VaultValidators.t.sol @@ -0,0 +1,1510 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; +import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; + +contract VaultValidatorsTest is Test, EthHelpers { + // Declare events we're testing for + event ValidatorRegistered(bytes publicKey); + event ValidatorRegistered(bytes publicKey, uint256 depositAmount); + ForkContracts public contracts; + EthVault public vault; + + address public admin; + address public user; + address public validatorsManager; + address public nonManager; + uint256 public validatorsManagerPrivateKey; + + uint256 public validatorDeposit = 32 ether; + string public exitSignatureIpfsHash = 'ipfsHash'; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + nonManager = makeAddr('nonManager'); + (validatorsManager, validatorsManagerPrivateKey) = makeAddrAndKey('validatorsManager'); + + // Fund accounts with ETH for testing + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + vm.deal(validatorsManager, 100 ether); + vm.deal(nonManager, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Set validators manager + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + // Deposit ETH to the vault for registration + _depositToVault(address(vault), validatorDeposit, user, user); + } + + // Test successful validator registration by validator manager + function test_registerValidators_byManager() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Extract the public key from validators data (first 48 bytes) + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + + // Expect ValidatorRegistered event emission + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + + // Call registerValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_byManager'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test validator registration with manager signature + function test_registerValidators_withSignature() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + approvalParams.validatorsRegistryRoot, + approvalParams.validators + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Expect ValidatorRegistered event emission + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + + // Call registerValidators from a non-manager address but with valid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_withSignature'); + vault.registerValidators(approvalParams, signature); + _stopSnapshotGas(); + + // Verify nonce was incremented + assertEq(vault.validatorsManagerNonce(), 1, 'Validators manager nonce should be incremented'); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when called by non-manager without signature + function test_registerValidators_notManager() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Call registerValidators from non-manager without signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_notManager'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure with invalid signature + function test_registerValidators_invalidSignature() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + approvalParams.validatorsRegistryRoot, + approvalParams.validators + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Call registerValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidSignature'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.registerValidators(approvalParams, signature); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure with invalid validators data + function test_registerValidators_invalidValidators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters but create empty validators data + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + approvalParams.validators = new bytes(0); // Make validators empty + + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' + ), + approvalParams.validatorsRegistryRoot, + address(vault), + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); + + // Call registerValidators with empty validators + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidValidators'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure with invalid validator length + function test_registerValidators_invalidValidatorLength() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters but modify validators length + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Cut validators data to create invalid length + approvalParams.validators = _extractBytes(approvalParams.validators, 0, 100); + + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' + ), + approvalParams.validatorsRegistryRoot, + address(vault), + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); + + // Call registerValidators with invalid validator length + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidValidatorLength'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when deposit amount is too small + function test_registerValidators_insufficientAssets() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Withdraw all assets from vault to make it insufficient + uint256 userShares = vault.getShares(user); + vm.prank(user); + vault.enterExitQueue(userShares, user); + + // Process exit queue to remove assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay); // Fast forward time to process exit + vault.updateState(_setEthVaultReward(address(vault), 0, 0)); + + // Call registerValidators with insufficient assets + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_insufficientAssets'); + vm.expectRevert(); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when vault not harvested + function test_registerValidators_notHarvested() public { + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Force vault to need harvesting by updating rewards twice + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Verify the vault needs harvesting + assertTrue(contracts.keeper.isHarvestRequired(address(vault)), 'Vault should need harvesting'); + + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Call registerValidators when vault needs harvesting + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_notHarvested'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test multiple validators registration + function test_registerValidators_multipleValidators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Deposit enough for multiple validators + _depositToVault(address(vault), validatorDeposit * 2, user, user); + + // Prepare approval params for multiple validators + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + exitSignatureIpfsHash, + deposits, + false + ); + + // Calculate validator length for each validator + uint256 validatorLength = 184; // Length for V2 validator + + // Extract first validator's public key and expect its event + bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorRegistered(publicKey1, validatorDeposit); + + // Extract second validator's public key and expect its event + bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorRegistered(publicKey2, validatorDeposit); + + // Call registerValidators with multiple validators + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_multipleValidators'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test V1 validator registration (with 0x01 prefix) + function test_registerValidators_v1Validators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters for V1 validator + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + true // Use V1 validator + ); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + vm.assertFalse( + vault.v2Validators(keccak256(publicKey)), + 'Validator should not be tracked' + ); + + // For V1 validators, the event is emitted without deposit amount + vm.expectEmit(true, true, true, false); + emit IVaultValidators.ValidatorRegistered(publicKey); + + // Call registerValidators with V1 validator + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_v1Validators'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + + vm.assertFalse( + vault.v2Validators(keccak256(publicKey)), + 'Validator should not be tracked' + ); + } + + // Test V2 validator registration (with 0x02 prefix) + function test_registerValidators_v2Validators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters for V2 validator + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false // Use V2 validator + ); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + vm.assertFalse( + vault.v2Validators(keccak256(publicKey)), + 'Validator should not be tracked' + ); + + // For V2 validators, the event includes deposit amount + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + + // Call registerValidators with V2 validator + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_v2Validators'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + vm.assertTrue(vault.v2Validators(keccak256(publicKey)), 'Validator should be tracked'); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test same signature can't be reused (nonce verification) + function test_registerValidators_nonceIncrement() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false + ); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + approvalParams.validatorsRegistryRoot, + approvalParams.validators + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Expect event for first use + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + + // Use the signature once + vm.prank(nonManager); + vault.registerValidators(approvalParams, signature); + + // Record nonce after first use + uint256 nonceAfterFirstUse = vault.validatorsManagerNonce(); + + // Try to use the same signature again + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_registerValidators_nonceIncrement'); + vm.expectRevert(Errors.InvalidValidatorsRegistryRoot.selector); + vault.registerValidators(approvalParams, signature); + _stopSnapshotGas(); + + // Verify nonce wasn't incremented on failed attempt + assertEq( + vault.validatorsManagerNonce(), + nonceAfterFirstUse, + 'Nonce should not increment on failed attempt' + ); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Helper function to get the message that would be signed by the validators manager + function _getValidatorsManagerSigningMessage( + address _vault, + bytes32 validatorsRegistryRoot, + bytes memory validators + ) internal view returns (bytes32) { + bytes32 domainSeparator = keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256(bytes('VaultValidators')), + keccak256('1'), + block.chainid, + _vault + ) + ); + + bytes32 structHash = keccak256( + abi.encode( + keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'), + validatorsRegistryRoot, + keccak256(validators) + ) + ); + + return MessageHashUtils.toTypedDataHash(domainSeparator, structHash); + } + + // Test successful validator funding by validator manager + function test_fundValidators_byManager() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + // Call fundValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_byManager'); + vault.fundValidators(validTopUpData, ''); + _stopSnapshotGas(); + } + + // Test validator funding with manager signature + function test_fundValidators_withSignature() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + bytes32(vault.validatorsManagerNonce()), + validTopUpData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory validatorManagerSignature = abi.encodePacked(r, s, v); + + // Record current nonce + uint256 currentNonce = vault.validatorsManagerNonce(); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + // Call fundValidators from non-manager with valid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_withSignature'); + vault.fundValidators(validTopUpData, validatorManagerSignature); + _stopSnapshotGas(); + + // Verify nonce was incremented + assertEq( + vault.validatorsManagerNonce(), + currentNonce + 1, + 'Validators manager nonce should be incremented' + ); + } + + // Test failure when trying to fund a non-existing validator + function test_fundValidators_nonExistingValidator() public { + _collateralizeEthVault(address(vault)); + + // Deposit enough ETH for funding + _depositToVault(address(vault), validatorDeposit, user, user); + + // Create a non-existing validator public key + bytes memory nonExistingPublicKey = vm.randomBytes(48); + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + nonExistingPublicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create top-up data for non-existing validator + bytes memory invalidTopUpData = bytes.concat( + nonExistingPublicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Call fundValidators with non-existing validator - should fail + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_nonExistingValidator'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(invalidTopUpData, ''); + _stopSnapshotGas(); + } + + // Test failure when called by non-manager without signature + function test_fundValidators_notManager() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Call fundValidators from non-manager without signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_notManager'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.fundValidators(validTopUpData, ''); + _stopSnapshotGas(); + } + + // Test failure with invalid signature + function test_fundValidators_invalidSignature() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + bytes32(vault.validatorsManagerNonce()), + validTopUpData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory invalidSignature = abi.encodePacked(r, s, v); + + // Call fundValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_invalidSignature'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.fundValidators(validTopUpData, invalidSignature); + _stopSnapshotGas(); + } + + // Test failure with invalid validators data + function test_fundValidators_invalidValidators() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + _registerEthValidator(address(vault), validatorDeposit, false); + + // Create empty validators data + bytes memory emptyValidatorsData = new bytes(0); + + // Call fundValidators with empty validators data + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_invalidValidators'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(emptyValidatorsData, ''); + _stopSnapshotGas(); + } + + // Test failure with insufficient assets + function test_fundValidators_insufficientAssets() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit + 0.5 ether, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data with more ETH than available in the vault + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Drain most of the vault's funds to make it insufficient + uint256 exitShares = vault.getShares(user) - vault.convertToShares(0.1 ether); + vm.prank(user); + vault.enterExitQueue(exitShares, user); + + // Process exit queue to remove assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay); + vault.updateState(_setEthVaultReward(address(vault), 0, 0)); + + // Call fundValidators with insufficient assets + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_insufficientAssets'); + vm.expectRevert(); + vault.fundValidators(validTopUpData, ''); + _stopSnapshotGas(); + } + + // Test failure when vault not harvested + function test_fundValidators_notHarvested() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Force vault to need harvesting by updating rewards twice + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Verify the vault needs harvesting + assertTrue(contracts.keeper.isHarvestRequired(address(vault)), 'Vault should need harvesting'); + + // Prepare top-up data + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Call fundValidators when vault needs harvesting + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_notHarvested'); + vm.expectRevert(Errors.NotHarvested.selector); + vault.fundValidators(validTopUpData, ''); + _stopSnapshotGas(); + } + + // Test that V1 validators can't be topped up + function test_fundValidators_v1Validators() public { + // First register a V1 validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, true); // V1 validator + + // Prepare top-up data for V1 validator + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x01), bytes11(0x0), vault); // V1 prefix + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create top-up data for V1 validator - actual validator format needs to be V1 + bytes memory invalidTopUpData = bytes.concat(publicKey, signature, depositDataRoot); + + // Call fundValidators with V1 validator - should fail + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_v1Validators'); + vm.expectRevert(Errors.CannotTopUpV1Validators.selector); + vault.fundValidators(invalidTopUpData, ''); + _stopSnapshotGas(); + } + + // Test funding multiple validators in one call + function test_fundValidators_multipleValidators() public { + vm.deal(user, 200 ether); + + // Register multiple validators to make them tracked + _depositToVault(address(vault), validatorDeposit * 4, user, user); + + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Register two validators + uint256[] memory initialDeposits = new uint256[](2); + initialDeposits[0] = 32 ether / 1 gwei; + initialDeposits[1] = 32 ether / 1 gwei; + + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + exitSignatureIpfsHash, + initialDeposits, + false + ); + + vm.prank(validatorsManager); + vault.registerValidators(approvalParams, ''); + + // Calculate validator length for each validator + uint256 validatorLength = 184; // Length for V2 validator + + // Extract validator public keys + bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); + bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); + + // Prepare top-up data for both validators + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + + // Create deposit data for first validator + bytes32 depositDataRoot1 = _getDepositDataRoot( + publicKey1, + signature, + withdrawalCredentials, + topUpAmount + ); + bytes memory validatorData1 = bytes.concat( + publicKey1, + signature, + depositDataRoot1, + bytes8(uint64(topUpAmount)) + ); + + // Create deposit data for second validator + bytes32 depositDataRoot2 = _getDepositDataRoot( + publicKey2, + signature, + withdrawalCredentials, + topUpAmount + ); + bytes memory validatorData2 = bytes.concat( + publicKey2, + signature, + depositDataRoot2, + bytes8(uint64(topUpAmount)) + ); + + // Combine data for both validators + bytes memory combinedValidatorsData = bytes.concat(validatorData1, validatorData2); + + // Expect validator funded events + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey1, 1 ether); + + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey2, 1 ether); + + // Call fundValidators with multiple validators + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_fundValidators_multipleValidators'); + vault.fundValidators(combinedValidatorsData, ''); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test successful validator withdrawal by validator manager + function test_withdrawValidators_byManager() public { + // 1. First register a validator to track it and provide funds to withdraw + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data - for Ethereum validators, + // _validatorWithdrawalLength is 56 (48 bytes publicKey + 8 bytes amount) + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Mock the withdrawal fee + uint256 withdrawalFee = 0.1 ether; + vm.deal(validatorsManager, withdrawalFee); + + // 4. Expect ValidatorWithdrawalSubmitted event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, withdrawalFee); + + // 5. Call withdrawValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_byManager'); + vault.withdrawValidators{value: withdrawalFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + // Test validator withdrawal with manager signature + function test_withdrawValidators_withSignature() public { + // 1. First register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + bytes32(vault.validatorsManagerNonce()), + withdrawalData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // 4. Record current nonce + uint256 currentNonce = vault.validatorsManagerNonce(); + + // 5. Fund non-manager for withdrawal fee + uint256 withdrawalFee = 0.1 ether; + vm.deal(nonManager, withdrawalFee); + + // 6. Expect ValidatorWithdrawalSubmitted event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, withdrawalFee); + + // 7. Call withdrawValidators from non-manager with valid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_withSignature'); + vault.withdrawValidators{value: withdrawalFee}(withdrawalData, signature); + _stopSnapshotGas(); + + // 8. Verify nonce was incremented + assertEq( + vault.validatorsManagerNonce(), + currentNonce + 1, + 'Validators manager nonce should be incremented' + ); + } + + // Test withdrawal by osToken redeemer + function test_withdrawValidators_byRedeemer() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Get the redeemer from osTokenConfig + address redeemer = contracts.osTokenConfig.redeemer(); + vm.deal(redeemer, 0.1 ether); + + // 4. Expect ValidatorWithdrawalSubmitted event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, 0.1 ether); + + // 5. Call withdrawValidators from redeemer + vm.prank(redeemer); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_byRedeemer'); + vault.withdrawValidators{value: 0.1 ether}(withdrawalData, ''); + _stopSnapshotGas(); + } + + // Test failed withdrawal by unauthorized user + function test_withdrawValidators_notAuthorized() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Fund unauthorized user + vm.deal(nonManager, 0.1 ether); + + // 4. Call withdrawValidators from unauthorized user without signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_notAuthorized'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: 0.1 ether}(withdrawalData, ''); + _stopSnapshotGas(); + } + + // Test failed withdrawal with invalid signature + function test_withdrawValidators_invalidSignature() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + bytes32(vault.validatorsManagerNonce()), + withdrawalData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory invalidSignature = abi.encodePacked(r, s, v); + + // 4. Fund unauthorized user + vm.deal(nonManager, 0.1 ether); + + // 5. Call withdrawValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidSignature'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: 0.1 ether}(withdrawalData, invalidSignature); + _stopSnapshotGas(); + } + + // Test failed withdrawal with invalid validator data + function test_withdrawValidators_invalidValidators() public { + _collateralizeEthVault(address(vault)); + + // 1. Prepare invalid withdrawal data (zero length) + bytes memory invalidWithdrawalData = new bytes(0); + + // 2. Fund validator manager + vm.deal(validatorsManager, 0.1 ether); + + // 3. Call withdrawValidators with empty data + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.withdrawValidators{value: 0.1 ether}(invalidWithdrawalData, ''); + _stopSnapshotGas(); + + // 4. Test with invalid length (not a multiple of _validatorWithdrawalLength) + // For Ethereum validators, _validatorWithdrawalLength is 56 (48 bytes publicKey + 8 bytes amount) + bytes memory invalidLengthData = new bytes(30); // Not a multiple of 56 + + // 5. Call withdrawValidators with invalid length data + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidValidatorsLength'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.withdrawValidators{value: 0.1 ether}(invalidLengthData, ''); + _stopSnapshotGas(); + } + + // Test fee handling and refunds + function test_withdrawValidators_feeHandling() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Set excess fee (more than needed) + uint256 actualFee = 0.1 ether; + uint256 excessFee = 0.5 ether; // Overpay + vm.deal(validatorsManager, excessFee); + + // 4. Record initial balance + uint256 initialBalance = validatorsManager.balance; + + // 5. Call withdrawValidators with excess fee + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_feeHandling'); + vault.withdrawValidators{value: excessFee}(withdrawalData, ''); + _stopSnapshotGas(); + + // 6. Verify the correct fee was deducted and excess was refunded + uint256 finalBalance = validatorsManager.balance; + assertEq(finalBalance, initialBalance - actualFee, 'Excess fee should be refunded'); + } + + // Test withdrawing multiple validators in a single call + function test_withdrawValidators_multipleValidators() public { + // 1. First register multiple validators + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey1 = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory publicKey2 = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data for both validators + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData1 = abi.encodePacked(publicKey1, bytes8(uint64(withdrawalAmount))); + bytes memory withdrawalData2 = abi.encodePacked(publicKey2, bytes8(uint64(withdrawalAmount))); + bytes memory combinedData = bytes.concat(withdrawalData1, withdrawalData2); + + // 3. Set fee for two withdrawals + uint256 feePerValidator = 0.1 ether; + uint256 totalFee = feePerValidator * 2; + vm.deal(validatorsManager, totalFee); + + // 4. Expect events for both withdrawals + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey1, 1 ether, feePerValidator); + + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey2, 1 ether, feePerValidator); + + // 5. Call withdrawValidators with combined data + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_multipleValidators'); + vault.withdrawValidators{value: totalFee}(combinedData, ''); + _stopSnapshotGas(); + } + + // Test successful validator consolidation by validator manager + function test_consolidateValidators_byManager() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); + + // Register a second validator to use as destination (must be tracked to avoid oracle requirement) + bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // Call consolidateValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_byManager'); + vault.consolidateValidators{value: consolidationFee}(consolidationData, '', ''); + _stopSnapshotGas(); + } + + // Test validator consolidation with manager signature + function test_consolidateValidators_withSignature() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); + + // Register a second validator to use as destination (must be tracked) + bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + bytes32(vault.validatorsManagerNonce()), + consolidationData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Record current nonce + uint256 currentNonce = vault.validatorsManagerNonce(); + + // Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(nonManager, consolidationFee); + + // Call consolidateValidators from non-manager with valid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_withSignature'); + vault.consolidateValidators{value: consolidationFee}(consolidationData, signature, ''); + _stopSnapshotGas(); + + // Verify nonce was incremented + assertEq( + vault.validatorsManagerNonce(), + currentNonce + 1, + 'Validators manager nonce should be incremented' + ); + } + + // Test validator consolidation with oracle signatures + function test_consolidateValidators_withOracleSignatures() public { + // Register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); + + // Prepare consolidation data (to an untracked destination validator) + bytes memory destPublicKey = vm.randomBytes(48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create oracle signature using our known oracle private key + bytes32 digest = keccak256( + abi.encodePacked( + '\x19\x01', + keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256('ConsolidationsChecker'), + keccak256('1'), + block.chainid, + address(contracts.consolidationsChecker) + ) + ), + keccak256( + abi.encode( + keccak256('ConsolidationsChecker(address vault,bytes validators)'), + address(vault), + keccak256(consolidationData) + ) + ) + ) + ); + + // setup oracles + _startOracleImpersonate(address(contracts.keeper)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory oracleSignatures = abi.encodePacked(r, s, v); + + // Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // Verify the destination validator is not tracked initially + assertFalse( + vault.v2Validators(keccak256(destPublicKey)), + 'Destination validator should not be tracked initially' + ); + + // Call consolidateValidators with oracle signatures + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_withOracleSignatures'); + vault.consolidateValidators{value: consolidationFee}(consolidationData, '', oracleSignatures); + _stopSnapshotGas(); + + // Verify the destination validator is now tracked + assertTrue( + vault.v2Validators(keccak256(destPublicKey)), + 'Destination validator should be tracked after consolidation with oracle approval' + ); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when called by non-manager without signature + function test_consolidateValidators_notManager() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data + bytes memory destPublicKey = vm.randomBytes(48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(nonManager, consolidationFee); + + // 4. Call consolidateValidators from non-manager without signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_notManager'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.consolidateValidators{value: consolidationFee}(consolidationData, '', ''); + _stopSnapshotGas(); + } + + // Test failure with invalid signature + function test_consolidateValidators_invalidSignature() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data + bytes memory destPublicKey = vm.randomBytes(48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), + bytes32(vault.validatorsManagerNonce()), + consolidationData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory invalidSignature = abi.encodePacked(r, s, v); + + // 4. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(nonManager, consolidationFee); + + // 5. Call consolidateValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidSignature'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.consolidateValidators{value: consolidationFee}(consolidationData, invalidSignature, ''); + _stopSnapshotGas(); + } + + // Test failure with invalid validators data + function test_consolidateValidators_invalidValidators() public { + _collateralizeEthVault(address(vault)); + + // 1. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // 2. Create empty validators data + bytes memory emptyValidatorsData = new bytes(0); + + // 3. Call consolidateValidators with empty validators data + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.consolidateValidators{value: consolidationFee}(emptyValidatorsData, '', ''); + _stopSnapshotGas(); + + // 4. Test with invalid length (not a multiple of _validatorConsolidationLength) + // For consolidation, _validatorConsolidationLength is 96 (48 bytes sourcePublicKey + 48 bytes destPublicKey) + bytes memory invalidLengthData = new bytes(50); // Not a multiple of 96 + + // 5. Call consolidateValidators with invalid length data + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidValidatorsLength'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.consolidateValidators{value: consolidationFee}(invalidLengthData, '', ''); + _stopSnapshotGas(); + } + + // Test failure for untracked destination without oracle approval + function test_consolidateValidators_untrackedDestination() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data with untracked destination + bytes memory destPublicKey = vm.randomBytes(48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Verify destination is not tracked + assertFalse( + vault.v2Validators(keccak256(destPublicKey)), + 'Destination validator should not be tracked initially' + ); + + // 4. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // 5. Attempt consolidation without oracle signatures + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_untrackedDestination'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.consolidateValidators{value: consolidationFee}(consolidationData, '', ''); + _stopSnapshotGas(); + } + + // Test fee handling and refunds + function test_consolidateValidators_feeHandling() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data (to another tracked validator) + bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Set excess fee (more than needed) + uint256 actualFee = 0.1 ether; + uint256 excessFee = 0.5 ether; // Overpay + vm.deal(validatorsManager, excessFee); + + // 4. Record initial balance + uint256 initialBalance = validatorsManager.balance; + + // 5. Call consolidateValidators with excess fee + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_feeHandling'); + vault.consolidateValidators{value: excessFee}(consolidationData, '', ''); + _stopSnapshotGas(); + + // 6. Verify the correct fee was deducted and excess was refunded + uint256 finalBalance = validatorsManager.balance; + assertEq(finalBalance, initialBalance - actualFee, 'Excess fee should be refunded'); + } + + // Test consolidating multiple validators in a single call + function test_consolidateValidators_multipleValidators() public { + vm.deal(user, 200 ether); + + // Register source validators + _depositToVault(address(vault), validatorDeposit * 3, user, user); + bytes memory sourcePublicKey1 = _registerEthValidator(address(vault), validatorDeposit, true); + bytes memory destPublicKey1 = _registerEthValidator(address(vault), validatorDeposit, false); + + // Consolidate the same validator + bytes memory sourcePublicKey2 = _registerEthValidator(address(vault), validatorDeposit, false); + + // Combine data for both consolidations + bytes memory consolidationData1 = bytes.concat(sourcePublicKey1, destPublicKey1); + bytes memory consolidationData2 = bytes.concat(sourcePublicKey2, sourcePublicKey2); + bytes memory combinedData = bytes.concat(consolidationData1, consolidationData2); + + // setup oracle + _stopOracleImpersonate(address(contracts.keeper)); + + // Set fee for two consolidations + uint256 feePerConsolidation = 0.1 ether; + uint256 totalFee = feePerConsolidation * 2; + vm.deal(validatorsManager, totalFee); + + // Call consolidateValidators with multiple validators + vm.prank(validatorsManager); + _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_multipleValidators'); + vault.consolidateValidators{value: totalFee}(combinedData, '', ''); + _stopSnapshotGas(); + + // remove oracle + _stopOracleImpersonate(address(contracts.keeper)); + } +} diff --git a/test/VaultVersion.t.sol b/test/VaultVersion.t.sol new file mode 100644 index 00000000..b666e4cf --- /dev/null +++ b/test/VaultVersion.t.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Test} from '../lib/forge-std/src/Test.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {EthVaultV6Mock} from '../contracts/mocks/EthVaultV6Mock.sol'; +import {EthVaultV7Mock} from '../contracts/mocks/EthVaultV7Mock.sol'; +import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; + +contract VaultVersionTest is Test, EthHelpers { + ForkContracts public contracts; + EthVault public vault; + VaultsRegistry public vaultsRegistry; + + address public admin; + address public user; + + bytes32 public ethVaultId; + bytes32 public ethPrivVaultId; + + address public mockImplV6; + address public mockImplV7; + address public ethPrivVaultImpl; + + function setUp() public { + // Set up contracts + contracts = _activateEthereumFork(); + vaultsRegistry = contracts.vaultsRegistry; + + // Set up accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deploy mock implementations for testing upgrades + IEthVault.EthVaultConstructorArgs memory args = IEthVault.EthVaultConstructorArgs( + address(contracts.keeper), + address(vaultsRegistry), + address(contracts.validatorsRegistry), + address(_validatorsWithdrawals), + address(_validatorsConsolidations), + address(contracts.consolidationsChecker), + address(contracts.osTokenVaultController), + address(contracts.osTokenConfig), + address(contracts.osTokenVaultEscrow), + address(contracts.sharedMevEscrow), + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + mockImplV6 = address(new EthVaultV6Mock(args)); + mockImplV7 = address(new EthVaultV7Mock(args)); + + // Get vault IDs + ethVaultId = vault.vaultId(); + ethPrivVaultId = keccak256('EthPrivVault'); + + // Deploy EthPrivVault implementation for testing vault ID checks + ethPrivVaultImpl = _getOrCreateVaultImpl(VaultType.EthPrivVault); + + // Add implementations to registry + vm.startPrank(vaultsRegistry.owner()); + vaultsRegistry.addVaultImpl(mockImplV6); + vaultsRegistry.addVaultImpl(mockImplV7); + vm.stopPrank(); + } + + function test_initialVersion() public view { + // Test that the initial version is correct + assertEq(vault.version(), 5, 'Initial version should be 5'); + } + + function test_implementation() public view { + // Test that the implementation address is correct + address impl = vault.implementation(); + assertTrue(impl != address(0), 'Implementation address should not be zero'); + assertEq(EthVault(payable(impl)).version(), 5, 'Implementation version should be 5'); + } + + function test_vaultId() public view { + // Test that vaultId returns the correct value + assertEq(vault.vaultId(), ethVaultId, 'Vault ID should be correct'); + assertEq(ethVaultId, keccak256('EthVault'), 'Vault ID should match expected value'); + } + + function test_upgradeToNextVersion() public { + // Test upgrading to the next version + bytes memory callData = abi.encode(uint128(100)); // Data for initializing V6 + + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeToNextVersion'); + vault.upgradeToAndCall(mockImplV6, callData); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify upgrade was successful + assertEq(vault.version(), 6, 'Version should be updated to 6'); + assertEq(vault.implementation(), mockImplV6, 'Implementation should be updated'); + + // Check that the new functionality is available + EthVaultV6Mock v6Vault = EthVaultV6Mock(payable(address(vault))); + assertEq(v6Vault.newVar(), 100, 'New variable should be initialized'); + assertTrue(v6Vault.somethingNew(), 'New function should be available'); + } + + function test_upgradeToSameVersionFails() public { + // Test that upgrading to the same version fails + address currentImpl = vault.implementation(); + + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeToSameVersionFails'); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(currentImpl, '0x'); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + assertEq(vault.implementation(), currentImpl, 'Implementation should remain unchanged'); + } + + function test_upgradeToSkipVersionFails() public { + // Test that skipping a version fails (going from V5 to V7) + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeToSkipVersionFails'); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(mockImplV7, '0x'); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + } + + function test_upgradeToDifferentVaultIdFails() public { + // Test that upgrading to an implementation with a different vault ID fails + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeToDifferentVaultIdFails'); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(ethPrivVaultImpl, '0x'); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + } + + function test_upgradeNonAdminFails() public { + // Test that non-admin cannot upgrade + vm.startPrank(user); + _startSnapshotGas('VaultVersionTest_test_upgradeNonAdminFails'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.upgradeToAndCall(mockImplV6, '0x'); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + } + + function test_upgradeToZeroAddressFails() public { + // Test that upgrading to zero address fails + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeToZeroAddressFails'); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(address(0), '0x'); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + } + + function test_upgradeToUnapprovedImplementationFails() public { + // Deploy a new implementation that's not in the registry + IEthVault.EthVaultConstructorArgs memory args = IEthVault.EthVaultConstructorArgs( + address(contracts.keeper), + address(vaultsRegistry), + address(contracts.validatorsRegistry), + address(_validatorsWithdrawals), + address(_validatorsConsolidations), + address(contracts.consolidationsChecker), + address(contracts.osTokenVaultController), + address(contracts.osTokenConfig), + address(contracts.osTokenVaultEscrow), + address(contracts.sharedMevEscrow), + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + address unapprovedImpl = address(new EthVaultV6Mock(args)); + + // Test that upgrading to an unapproved implementation fails + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeToUnapprovedImplementationFails'); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(unapprovedImpl, '0x'); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + } + + function test_vaultIdPreservedAfterUpgrade() public { + // Test that the vault ID is preserved after an upgrade + bytes memory callData = abi.encode(uint128(100)); + + vm.prank(admin); + vault.upgradeToAndCall(mockImplV6, callData); + + // Verify vault ID remains unchanged + assertEq(vault.vaultId(), ethVaultId, 'Vault ID should remain unchanged after upgrade'); + } + + function test_upgradeWithInvalidCallDataFails() public { + // Test that upgrading with invalid call data fails + bytes memory invalidCallData = abi.encode(type(uint256).max); // V6 expects uint128 + + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeWithInvalidCallDataFails'); + vm.expectRevert(); + vault.upgradeToAndCall(mockImplV6, invalidCallData); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, 'Version should remain 5'); + } + + function test_upgradeMultipleSteps() public { + // Test upgrading through multiple versions + bytes memory callDataV6 = abi.encode(uint128(100)); + + // First upgrade to V6 + vm.prank(admin); + vault.upgradeToAndCall(mockImplV6, callDataV6); + assertEq(vault.version(), 6, 'Version should be 6 after first upgrade'); + + // Now upgrade to V7 + vm.prank(admin); + _startSnapshotGas('VaultVersionTest_test_upgradeMultipleSteps'); + vault.upgradeToAndCall(mockImplV7, '0x'); + _stopSnapshotGas(); + + // Verify second upgrade + assertEq(vault.version(), 7, 'Version should be 7 after second upgrade'); + assertEq(vault.implementation(), mockImplV7, 'Implementation should be V7'); + } + + function test_reinitializeFails() public { + // Test that reinitializing fails after upgrade + bytes memory callData = abi.encode(uint128(100)); + + // Upgrade to V6 + vm.prank(admin); + vault.upgradeToAndCall(mockImplV6, callData); + + // Try to initialize again + vm.startPrank(admin); + _startSnapshotGas('VaultVersionTest_test_reinitializeFails'); + vm.expectRevert(Initializable.InvalidInitialization.selector); + EthVaultV6Mock(payable(address(vault))).initialize(callData); + _stopSnapshotGas(); + vm.stopPrank(); + } +} diff --git a/test/VaultsRegistry.spec.ts b/test/VaultsRegistry.spec.ts deleted file mode 100644 index eb604ca5..00000000 --- a/test/VaultsRegistry.spec.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthVaultFactory, VaultsRegistry } from '../typechain-types' -import { - deployEthVaultImplementation, - encodeEthVaultInitParams, - ethVaultFixture, -} from './shared/fixtures' -import { expect } from './shared/expect' -import snapshotGasCost from './shared/snapshotGasCost' -import { EXITING_ASSETS_MIN_DELAY, SECURITY_DEPOSIT, ZERO_ADDRESS } from './shared/constants' -import { extractVaultAddress } from './shared/utils' - -describe('VaultsRegistry', () => { - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - - let dao: Wallet, admin: Wallet - - let vaultsRegistry: VaultsRegistry - let ethVaultFactory: EthVaultFactory - let newVaultImpl: string - - beforeEach('deploy fixture', async () => { - ;[dao, admin] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - ethVaultFactory = fixture.ethVaultFactory - vaultsRegistry = fixture.vaultsRegistry - - newVaultImpl = await deployEthVaultImplementation( - 'EthVaultV5Mock', - fixture.keeper, - fixture.vaultsRegistry, - await fixture.validatorsRegistry.getAddress(), - fixture.osTokenVaultController, - fixture.osTokenConfig, - fixture.osTokenVaultEscrow, - fixture.sharedMevEscrow, - fixture.depositDataRegistry, - EXITING_ASSETS_MIN_DELAY - ) - }) - - it('fails to add a vault if not a factory or owner', async () => { - await expect(vaultsRegistry.connect(admin).addVault(admin.address)).revertedWithCustomError( - vaultsRegistry, - 'AccessDenied' - ) - }) - - it('factory can add vault', async () => { - const tx = await ethVaultFactory - .connect(admin) - .createVault(encodeEthVaultInitParams(vaultParams), false, { value: SECURITY_DEPOSIT }) - const vaultAddress = await extractVaultAddress(tx) - - await expect(tx) - .to.emit(vaultsRegistry, 'VaultAdded') - .withArgs(await ethVaultFactory.getAddress(), vaultAddress) - expect(await vaultsRegistry.vaults(vaultAddress)).to.be.eq(true) - await snapshotGasCost(tx) - }) - - it('owner can add vault', async () => { - // add zero address as newVaultImpl is implementation, not proxy - await vaultsRegistry.connect(dao).addVaultImpl(ZERO_ADDRESS) - const receipt = await vaultsRegistry.connect(dao).addVault(newVaultImpl) - await expect(receipt).to.emit(vaultsRegistry, 'VaultAdded').withArgs(dao.address, newVaultImpl) - expect(await vaultsRegistry.vaults(newVaultImpl)).to.be.eq(true) - await snapshotGasCost(receipt) - }) - - it('not owner cannot register vault implementation contract', async () => { - await expect(vaultsRegistry.connect(admin).addVaultImpl(newVaultImpl)).revertedWithCustomError( - vaultsRegistry, - 'OwnableUnauthorizedAccount' - ) - }) - - it('owner can register implementation contract', async () => { - const receipt = await vaultsRegistry.connect(dao).addVaultImpl(newVaultImpl) - await expect(receipt).to.emit(vaultsRegistry, 'VaultImplAdded').withArgs(newVaultImpl) - expect(await vaultsRegistry.vaultImpls(newVaultImpl)).to.be.eq(true) - await snapshotGasCost(receipt) - }) - - it('cannot add the same implementation contract', async () => { - await vaultsRegistry.connect(dao).addVaultImpl(newVaultImpl) - await expect(vaultsRegistry.connect(dao).addVaultImpl(newVaultImpl)).revertedWithCustomError( - vaultsRegistry, - 'AlreadyAdded' - ) - }) - - it('not owner cannot remove implementation', async () => { - await vaultsRegistry.connect(dao).addVaultImpl(newVaultImpl) - await expect( - vaultsRegistry.connect(admin).removeVaultImpl(newVaultImpl) - ).revertedWithCustomError(vaultsRegistry, 'OwnableUnauthorizedAccount') - }) - - it('owner can remove implementation', async () => { - await vaultsRegistry.connect(dao).addVaultImpl(newVaultImpl) - const receipt = await vaultsRegistry.connect(dao).removeVaultImpl(newVaultImpl) - await expect(receipt).to.emit(vaultsRegistry, 'VaultImplRemoved').withArgs(newVaultImpl) - expect(await vaultsRegistry.vaultImpls(newVaultImpl)).to.be.eq(false) - await snapshotGasCost(receipt) - }) - - it('cannot remove already removed implementation', async () => { - await expect(vaultsRegistry.connect(dao).removeVaultImpl(newVaultImpl)).revertedWithCustomError( - vaultsRegistry, - 'AlreadyRemoved' - ) - expect(await vaultsRegistry.vaults(newVaultImpl)).to.be.eq(false) - }) - - it('not owner cannot add factory', async () => { - await expect( - vaultsRegistry.connect(admin).addFactory(await ethVaultFactory.getAddress()) - ).revertedWithCustomError(vaultsRegistry, 'OwnableUnauthorizedAccount') - }) - - it('owner can add factory', async () => { - await vaultsRegistry.connect(dao).removeFactory(await ethVaultFactory.getAddress()) - const receipt = await vaultsRegistry.connect(dao).addFactory(await ethVaultFactory.getAddress()) - await expect(receipt) - .to.emit(vaultsRegistry, 'FactoryAdded') - .withArgs(await ethVaultFactory.getAddress()) - expect(await vaultsRegistry.factories(await ethVaultFactory.getAddress())).to.be.eq(true) - await snapshotGasCost(receipt) - }) - - it('cannot add already whitelisted factory', async () => { - await expect( - vaultsRegistry.connect(dao).addFactory(await ethVaultFactory.getAddress()) - ).revertedWithCustomError(vaultsRegistry, 'AlreadyAdded') - expect(await vaultsRegistry.factories(await ethVaultFactory.getAddress())).to.be.eq(true) - }) - - it('not owner cannot remove factory', async () => { - await expect( - vaultsRegistry.connect(admin).removeFactory(await ethVaultFactory.getAddress()) - ).revertedWithCustomError(vaultsRegistry, 'OwnableUnauthorizedAccount') - }) - - it('owner can remove factory', async () => { - const receipt = await vaultsRegistry - .connect(dao) - .removeFactory(await ethVaultFactory.getAddress()) - await expect(receipt) - .to.emit(vaultsRegistry, 'FactoryRemoved') - .withArgs(await ethVaultFactory.getAddress()) - expect(await vaultsRegistry.factories(await ethVaultFactory.getAddress())).to.be.eq(false) - await snapshotGasCost(receipt) - }) - - it('cannot remove already removed factory', async () => { - await vaultsRegistry.connect(dao).removeFactory(await ethVaultFactory.getAddress()) - await expect( - vaultsRegistry.connect(dao).removeFactory(await ethVaultFactory.getAddress()) - ).revertedWithCustomError(vaultsRegistry, 'AlreadyRemoved') - expect(await vaultsRegistry.factories(await ethVaultFactory.getAddress())).to.be.eq(false) - }) - - describe('initialize', () => { - it('cannot initialize twice', async () => { - await expect(vaultsRegistry.connect(dao).initialize(admin.address)).revertedWithCustomError( - vaultsRegistry, - 'AccessDenied' - ) - }) - - it('not owner cannot initialize', async () => { - await expect(vaultsRegistry.connect(admin).initialize(admin.address)).revertedWithCustomError( - vaultsRegistry, - 'OwnableUnauthorizedAccount' - ) - }) - - it('cannot initialize to zero address', async () => { - await expect(vaultsRegistry.connect(dao).initialize(ZERO_ADDRESS)).revertedWithCustomError( - vaultsRegistry, - 'ZeroAddress' - ) - }) - }) -}) diff --git a/test/VaultsRegistry.t.sol b/test/VaultsRegistry.t.sol new file mode 100644 index 00000000..0abf5446 --- /dev/null +++ b/test/VaultsRegistry.t.sol @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; +import {IVaultsRegistry} from '../contracts/interfaces/IVaultsRegistry.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; + +contract VaultsRegistryTest is Test, EthHelpers { + ForkContracts public contracts; + VaultsRegistry public registry; + + address public owner; + address public nonOwner; + address public mockFactory; + address public mockVaultImpl; + address public mockVault; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + registry = contracts.vaultsRegistry; + + // Set up test accounts + owner = makeAddr('owner'); + nonOwner = makeAddr('nonOwner'); + mockFactory = makeAddr('mockFactory'); + mockVaultImpl = makeAddr('mockVaultImpl'); + mockVault = makeAddr('mockVault'); + + // Since the registry is already deployed on the fork, we need to + // impersonate its owner to perform ownership-restricted actions + vm.startPrank(registry.owner()); + // Transfer ownership to our test owner + registry.transferOwnership(owner); + vm.stopPrank(); + + // Accept ownership + vm.prank(owner); + registry.acceptOwnership(); + } + + function test_initialState() public view { + // Verify the initial state of the registry + assertEq(registry.owner(), owner, 'Registry owner should be set'); + assertFalse(registry.factories(mockFactory), 'Mock factory should not be registered initially'); + assertFalse( + registry.vaultImpls(mockVaultImpl), + 'Mock vault impl should not be registered initially' + ); + assertFalse(registry.vaults(mockVault), 'Mock vault should not be registered initially'); + } + + function test_addFactory() public { + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_addFactory'); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.FactoryAdded(mockFactory); + registry.addFactory(mockFactory); + _stopSnapshotGas(); + + assertTrue(registry.factories(mockFactory), 'Factory should be registered'); + } + + function test_removeFactory() public { + // First, add the factory + vm.prank(owner); + registry.addFactory(mockFactory); + assertTrue(registry.factories(mockFactory), 'Factory should be registered'); + + // Now remove it + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_removeFactory'); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.FactoryRemoved(mockFactory); + registry.removeFactory(mockFactory); + _stopSnapshotGas(); + + assertFalse(registry.factories(mockFactory), 'Factory should be removed'); + } + + function test_addVaultImpl() public { + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_addVaultImpl'); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.VaultImplAdded(mockVaultImpl); + registry.addVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertTrue(registry.vaultImpls(mockVaultImpl), 'Vault implementation should be registered'); + } + + function test_removeVaultImpl() public { + // First, add the vault implementation + vm.prank(owner); + registry.addVaultImpl(mockVaultImpl); + assertTrue(registry.vaultImpls(mockVaultImpl), 'Vault implementation should be registered'); + + // Now remove it + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_removeVaultImpl'); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.VaultImplRemoved(mockVaultImpl); + registry.removeVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertFalse(registry.vaultImpls(mockVaultImpl), 'Vault implementation should be removed'); + } + + function test_addVault() public { + // First, add the factory + vm.prank(owner); + registry.addFactory(mockFactory); + + // Add vault as factory + vm.prank(mockFactory); + _startSnapshotGas('VaultsRegistryTest_test_addVault'); + vm.expectEmit(true, true, false, false); + emit IVaultsRegistry.VaultAdded(mockFactory, mockVault); + registry.addVault(mockVault); + _stopSnapshotGas(); + + assertTrue(registry.vaults(mockVault), 'Vault should be registered'); + } + + function test_addVault_asOwner() public { + // Add vault as owner + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_addVault_asOwner'); + vm.expectEmit(true, true, false, false); + emit IVaultsRegistry.VaultAdded(owner, mockVault); + registry.addVault(mockVault); + _stopSnapshotGas(); + + assertTrue(registry.vaults(mockVault), 'Vault should be registered'); + } + + function test_initialize() public { + // Deploy a new VaultsRegistry contract to test initialization + VaultsRegistry newRegistry = new VaultsRegistry(); + + address newOwner = makeAddr('newOwner'); + + vm.prank(newRegistry.owner()); + _startSnapshotGas('VaultsRegistryTest_test_initialize'); + newRegistry.initialize(newOwner); + _stopSnapshotGas(); + + assertEq(newRegistry.owner(), newOwner, 'Owner should be set after initialization'); + } + + // Access control tests + + function test_addFactory_notOwner() public { + vm.prank(nonOwner); + _startSnapshotGas('VaultsRegistryTest_test_addFactory_notOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + registry.addFactory(mockFactory); + _stopSnapshotGas(); + + assertFalse(registry.factories(mockFactory), 'Factory should not be registered'); + } + + function test_removeFactory_notOwner() public { + // First, add the factory + vm.prank(owner); + registry.addFactory(mockFactory); + + vm.prank(nonOwner); + _startSnapshotGas('VaultsRegistryTest_test_removeFactory_notOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + registry.removeFactory(mockFactory); + _stopSnapshotGas(); + + assertTrue(registry.factories(mockFactory), 'Factory should still be registered'); + } + + function test_addVaultImpl_notOwner() public { + vm.prank(nonOwner); + _startSnapshotGas('VaultsRegistryTest_test_addVaultImpl_notOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + registry.addVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertFalse( + registry.vaultImpls(mockVaultImpl), + 'Vault implementation should not be registered' + ); + } + + function test_removeVaultImpl_notOwner() public { + // First, add the vault implementation + vm.prank(owner); + registry.addVaultImpl(mockVaultImpl); + + vm.prank(nonOwner); + _startSnapshotGas('VaultsRegistryTest_test_removeVaultImpl_notOwner'); + vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); + registry.removeVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertTrue( + registry.vaultImpls(mockVaultImpl), + 'Vault implementation should still be registered' + ); + } + + function test_addVault_notFactoryOrOwner() public { + vm.prank(nonOwner); + _startSnapshotGas('VaultsRegistryTest_test_addVault_notFactoryOrOwner'); + vm.expectRevert(Errors.AccessDenied.selector); + registry.addVault(mockVault); + _stopSnapshotGas(); + + assertFalse(registry.vaults(mockVault), 'Vault should not be registered'); + } + + function test_initialize_alreadyInitialized() public { + // Create a new registry and initialize it once + VaultsRegistry newRegistry = new VaultsRegistry(); + + address newOwner = makeAddr('newOwner'); + address anotherOwner = makeAddr('anotherOwner'); + + vm.prank(newRegistry.owner()); + newRegistry.initialize(newOwner); + + // Try to initialize again, should fail + vm.prank(newOwner); + _startSnapshotGas('VaultsRegistryTest_test_initialize_alreadyInitialized'); + vm.expectRevert(Errors.AccessDenied.selector); + newRegistry.initialize(anotherOwner); + _stopSnapshotGas(); + + assertEq(newRegistry.owner(), newOwner, 'Owner should not have changed'); + } + + function test_initialize_zeroAddress() public { + VaultsRegistry newRegistry = new VaultsRegistry(); + + vm.prank(newRegistry.owner()); + _startSnapshotGas('VaultsRegistryTest_test_initialize_zeroAddress'); + vm.expectRevert(Errors.ZeroAddress.selector); + newRegistry.initialize(address(0)); + _stopSnapshotGas(); + } + + function test_addFactory_alreadyAdded() public { + // Add factory first time + vm.prank(owner); + registry.addFactory(mockFactory); + + // Try to add again + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_addFactory_alreadyAdded'); + vm.expectRevert(Errors.AlreadyAdded.selector); + registry.addFactory(mockFactory); + _stopSnapshotGas(); + } + + function test_removeFactory_alreadyRemoved() public { + // Try to remove factory that isn't registered + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_removeFactory_alreadyRemoved'); + vm.expectRevert(Errors.AlreadyRemoved.selector); + registry.removeFactory(mockFactory); + _stopSnapshotGas(); + } + + function test_addVaultImpl_alreadyAdded() public { + // Add vault implementation first time + vm.prank(owner); + registry.addVaultImpl(mockVaultImpl); + + // Try to add again + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_addVaultImpl_alreadyAdded'); + vm.expectRevert(Errors.AlreadyAdded.selector); + registry.addVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + } + + function test_removeVaultImpl_alreadyRemoved() public { + // Try to remove vault implementation that isn't registered + vm.prank(owner); + _startSnapshotGas('VaultsRegistryTest_test_removeVaultImpl_alreadyRemoved'); + vm.expectRevert(Errors.AlreadyRemoved.selector); + registry.removeVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + } +} diff --git a/test/gnosis/GnoBlocklistErc20Vault.spec.ts b/test/gnosis/GnoBlocklistErc20Vault.spec.ts deleted file mode 100644 index 3f8a7e7c..00000000 --- a/test/gnosis/GnoBlocklistErc20Vault.spec.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - ERC20Mock, - GnoBlocklistErc20Vault, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../../typechain-types' -import { collateralizeGnoVault, depositGno, gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' - -describe('GnoBlocklistErc20Vault', () => { - const name = 'SW GNO Vault' - const symbol = 'SW-GNO-1' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, blocklistManager: Wallet, receiver: Wallet - let vault: GnoBlocklistErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - gnoToken: ERC20Mock, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, blocklistManager] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - vault = await fixture.createGnoBlocklistErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - gnoToken = fixture.gnoToken - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('GnoBlocklistErc20Vault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('transfer', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - await depositGno(vault, gnoToken, amount, sender, sender, referrer) - }) - - it('cannot transfer to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot transfer from blocked user', async () => { - await depositGno(vault, gnoToken, amount, other, other, referrer) - await vault.connect(blocklistManager).updateBlocklist(sender.address, true) - await expect( - vault.connect(other).transfer(sender.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can transfer', async () => { - const receipt = await vault.connect(sender).transfer(other.address, amount) - expect(await vault.balanceOf(sender.address)).to.eq(0) - expect(await vault.balanceOf(other.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, other.address, amount) - await snapshotGasCost(receipt) - }) - }) - - describe('deposit', () => { - const assets = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be called by blocked sender', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - depositGno(vault, gnoToken, assets, other, receiver, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - depositGno(vault, gnoToken, assets, sender, other, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by not blocked user', async () => { - const receipt = await depositGno(vault, gnoToken, assets, sender, receiver, referrer) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, assets, shares, referrer) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from blocked user', async () => { - await vault.connect(admin).updateBlocklist(sender.address, true) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not blocked user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/gnosis/GnoBlocklistErc20Vault.t.sol b/test/gnosis/GnoBlocklistErc20Vault.t.sol new file mode 100644 index 00000000..6621fc6a --- /dev/null +++ b/test/gnosis/GnoBlocklistErc20Vault.t.sol @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; +import {GnoBlocklistErc20Vault} from '../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol'; + +contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoBlocklistErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + blocklistManager = makeAddr('blocklistManager'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, false); + vault = GnoBlocklistErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('GnoBlocklistErc20Vault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 3); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_transfer() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas('GnoBlocklistErc20VaultTest_test_transfer'); + vault.transfer(other, amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(sender), 0); + assertEq(vault.balanceOf(other), amount); + } + + function test_cannotTransferToBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Try to transfer to blocked user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferFromBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit GNO for both users + _depositGno(amount, sender, sender); + _depositGno(amount, other, other); + + // Block sender + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to transfer from blocked user to other + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit as non-blocked user + _startSnapshotGas('GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser'); + _depositGno(amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(receiver), amount); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('GnoBlocklistErc20VaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); + + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), 0); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(blocklistVault.totalExitingAssets(), 0); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.totalSupply(), _securityDeposit); + assertEq(blocklistVault.symbol(), 'SW-GNO-1'); + assertEq(blocklistVault.name(), 'SW GNO Vault'); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault( + VaultType.GnoBlocklistErc20Vault, + admin, + initParams, + true + ); + GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); + + _depositToVault(address(blocklistVault), 15 ether, sender, sender); + _registerGnoValidator(address(blocklistVault), 1 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); + uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 senderBalanceBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); + assertEq(blocklistVault.version(), 2); + assertEq( + contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), + 0 + ); + + _startSnapshotGas('GnoBlocklistErc20VaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoBlocklistErc20Vault, address(blocklistVault)); + _stopSnapshotGas(); + + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + assertEq(blocklistVault.totalSupply(), totalSharesBefore); + assertEq(blocklistVault.symbol(), 'SW-GNO-1'); + assertEq(blocklistVault.name(), 'SW GNO Vault'); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } +} diff --git a/test/gnosis/GnoBlocklistVault.spec.ts b/test/gnosis/GnoBlocklistVault.spec.ts deleted file mode 100644 index a9602124..00000000 --- a/test/gnosis/GnoBlocklistVault.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - ERC20Mock, - GnoBlocklistVault, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../../typechain-types' -import { collateralizeGnoVault, depositGno, gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' - -describe('GnoBlocklistVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, blocklistManager: Wallet, receiver: Wallet - let vault: GnoBlocklistVault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - gnoToken: ERC20Mock, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, blocklistManager] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - vault = await fixture.createGnoBlocklistVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - gnoToken = fixture.gnoToken - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('GnoBlocklistVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const assets = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setBlocklistManager(blocklistManager.address) - }) - - it('cannot be called by blocked sender', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - depositGno(vault, gnoToken, assets, other, receiver, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to blocked user', async () => { - await vault.connect(blocklistManager).updateBlocklist(other.address, true) - await expect( - depositGno(vault, gnoToken, assets, sender, other, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by not blocked user', async () => { - const receipt = await depositGno(vault, gnoToken, assets, sender, receiver, referrer) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, assets, shares, referrer) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from blocked user', async () => { - await vault.connect(admin).updateBlocklist(sender.address, true) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not blocked user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/gnosis/GnoBlocklistVault.t.sol b/test/gnosis/GnoBlocklistVault.t.sol new file mode 100644 index 00000000..382fd1f0 --- /dev/null +++ b/test/gnosis/GnoBlocklistVault.t.sol @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {GnoBlocklistVault} from '../../contracts/vaults/gnosis/GnoBlocklistVault.sol'; + +contract GnoBlocklistVaultTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoBlocklistVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + blocklistManager = makeAddr('blocklistManager'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoBlocklistVault, admin, initParams, false); + vault = GnoBlocklistVault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 assets = 1 ether; + uint256 shares = vault.convertToShares(assets); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit as non-blocked user + _startSnapshotGas('GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser'); + _depositGno(assets, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('GnoBlocklistVaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.GnoBlocklistVault, admin, initParams, false); + _stopSnapshotGas(); + GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); + + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), 0); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(blocklistVault.totalExitingAssets(), 0); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoBlocklistVault, admin, initParams, false); + GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); + + _depositToVault(address(blocklistVault), 15 ether, sender, sender); + _registerGnoValidator(address(blocklistVault), 1 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); + uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 senderBalanceBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); + assertEq(blocklistVault.version(), 2); + assertEq( + contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), + 0 + ); + + _startSnapshotGas('GnoBlocklistVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoBlocklistVault, address(blocklistVault)); + _stopSnapshotGas(); + + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } +} diff --git a/test/gnosis/GnoErc20Vault.spec.ts b/test/gnosis/GnoErc20Vault.spec.ts deleted file mode 100644 index f4ab31d6..00000000 --- a/test/gnosis/GnoErc20Vault.spec.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import keccak256 from 'keccak256' -import { - ERC20Mock, - GnoErc20Vault, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../../typechain-types' -import { collateralizeGnoVault, depositGno, gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import { extractExitPositionTicket } from '../shared/utils' -import { getHarvestParams, updateRewards } from '../shared/rewards' - -describe('GnoErc20Vault', () => { - const name = 'SW GNO Vault' - const symbol = 'SW-GNO-1' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, receiver: Wallet - let vault: GnoErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - gnoToken: ERC20Mock, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - vault = await fixture.createGnoErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - gnoToken = fixture.gnoToken - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('GnoErc20Vault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - it('deposit emits transfer event', async () => { - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - const receipt = await depositGno(vault, gnoToken, amount, sender, receiver, referrer) - expect(await vault.balanceOf(receiver.address)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, expectedShares, referrer) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(ZERO_ADDRESS, receiver.address, expectedShares) - await snapshotGasCost(receipt) - }) - - it('enter exit queue emits transfer event', async () => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - const queuedSharesBefore = await vault.queuedShares() - const totalAssetsBefore = await vault.totalAssets() - const totalSharesBefore = await vault.totalShares() - - const amount = ethers.parseEther('100') - const shares = await vault.convertToShares(amount) - await depositGno(vault, gnoToken, amount, sender, sender, referrer) - expect(await vault.balanceOf(sender.address)).to.be.eq(shares) - - const receipt = await vault.connect(sender).enterExitQueue(shares, receiver.address) - const positionTicket = await extractExitPositionTicket(receipt) - await expect(receipt) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(sender.address, receiver.address, positionTicket, shares) - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, await vault.getAddress(), shares) - expect(await vault.queuedShares()).to.be.eq(queuedSharesBefore + shares) - expect(await vault.totalAssets()).to.be.eq(totalAssetsBefore + amount) - expect(await vault.totalSupply()).to.be.eq(totalSharesBefore + shares) - expect(await vault.balanceOf(sender.address)).to.be.eq(0) - - await snapshotGasCost(receipt) - }) - - it('cannot transfer vault shares when unharvested and osToken minted', async () => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - const assets = ethers.parseEther('1') - const shares = await vault.convertToShares(assets) - const osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - - await updateRewards(keeper, [ - getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), ethers.parseEther('0')), - ]) - await updateRewards(keeper, [ - getHarvestParams(await vault.getAddress(), ethers.parseEther('1.2'), ethers.parseEther('0')), - ]) - await expect( - vault.connect(sender).transfer(receiver.address, shares) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('cannot transfer vault shares when LTV is violated', async () => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - const assets = ethers.parseEther('2') - const shares = await vault.convertToShares(assets) - const osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - await expect( - vault.connect(sender).transfer(receiver.address, shares) - ).to.be.revertedWithCustomError(vault, 'LowLtv') - await vault.connect(sender).approve(receiver.address, shares) - await expect( - vault.connect(receiver).transferFrom(sender.address, receiver.address, shares) - ).to.be.revertedWithCustomError(vault, 'LowLtv') - }) - - it('can transfer vault shares when LTV is not violated', async () => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - const assets = ethers.parseEther('2') - const osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - const transferShares = await vault.convertToShares(ethers.parseEther('0.1')) - - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - await expect(vault.connect(sender).transfer(receiver.address, transferShares)).to.emit( - vault, - 'Transfer' - ) - await vault.connect(sender).approve(receiver.address, transferShares) - await expect( - vault.connect(receiver).transferFrom(sender.address, receiver.address, transferShares) - ).to.emit(vault, 'Transfer') - }) -}) diff --git a/test/gnosis/GnoErc20Vault.t.sol b/test/gnosis/GnoErc20Vault.t.sol new file mode 100644 index 00000000..ffb19f84 --- /dev/null +++ b/test/gnosis/GnoErc20Vault.t.sol @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {GnoErc20Vault} from '../../contracts/vaults/gnosis/GnoErc20Vault.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; + +contract GnoErc20VaultTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoErc20Vault, admin, initParams, false); + vault = GnoErc20Vault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('GnoErc20VaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.GnoErc20Vault, admin, initParams, false); + _stopSnapshotGas(); + GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + + assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); + assertEq(erc20Vault.version(), 3); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.queuedShares(), 0); + assertEq(erc20Vault.totalShares(), _securityDeposit); + assertEq(erc20Vault.totalAssets(), _securityDeposit); + assertEq(erc20Vault.totalExitingAssets(), 0); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.totalSupply(), _securityDeposit); + assertEq(erc20Vault.symbol(), 'SW-GNO-1'); + assertEq(erc20Vault.name(), 'SW GNO Vault'); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoErc20Vault, admin, initParams, false); + GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + + _depositToVault(address(erc20Vault), 15 ether, sender, sender); + _registerGnoValidator(address(erc20Vault), 1 ether, true); + + vm.prank(sender); + erc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = erc20Vault.totalShares(); + uint256 totalAssetsBefore = erc20Vault.totalAssets(); + uint256 totalExitingAssetsBefore = erc20Vault.totalExitingAssets(); + uint256 queuedSharesBefore = erc20Vault.queuedShares(); + uint256 senderBalanceBefore = erc20Vault.getShares(sender); + + assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); + assertEq(erc20Vault.version(), 2); + assertEq( + contracts.gnoToken.allowance(address(erc20Vault), address(contracts.validatorsRegistry)), + 0 + ); + + _startSnapshotGas('GnoErc20VaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoErc20Vault, address(erc20Vault)); + _stopSnapshotGas(); + + assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); + assertEq(erc20Vault.version(), 3); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.queuedShares(), queuedSharesBefore); + assertEq(erc20Vault.totalShares(), totalSharesBefore); + assertEq(erc20Vault.totalAssets(), totalAssetsBefore); + assertEq(erc20Vault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(erc20Vault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + assertEq(erc20Vault.totalSupply(), totalSharesBefore); + assertEq(erc20Vault.symbol(), 'SW-GNO-1'); + assertEq(erc20Vault.name(), 'SW GNO Vault'); + } + + function test_deposit_emitsTransfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Approve GNO for the vault first + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + + // When depositing, the vault will mint shares to the receiver + // So we should expect a Transfer event from address(0) to the receiver + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Call deposit directly instead of the helper + _startSnapshotGas('GnoErc20VaultTest_test_deposit_emitsTransfer'); + vault.deposit(amount, sender, referrer); + _stopSnapshotGas(); + vm.stopPrank(); + } + + function test_enterExitQueue_emitsTransfer() public { + _collateralizeGnoVault(address(vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositGno(amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(sender, address(vault), shares); + + // Enter exit queue + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas('GnoErc20VaultTest_test_enterExitQueue_emitsTransfer'); + uint256 positionTicket = vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Claim exited assets + vm.prank(sender); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_redeem_emitsEvent() public { + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createVault(VaultType.GnoErc20Vault, admin, initParams, false); + GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositToVault(_vault, amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, _vault); + emit IERC20.Transfer(sender, address(0), shares); + + // Redeem + vm.prank(sender); + _startSnapshotGas('GnoErc20VaultTest_test_redeem_emitsEvent'); + uint256 positionTicket = erc20Vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + assertEq(positionTicket, type(uint256).max); + } + + function test_cannotTransferFromSharesWithLowLtv() public { + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + uint256 depositAmount = 10 ether; + + // Deposit GNO + _depositGno(depositAmount, sender, sender); + + // First mint the maximum amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, type(uint256).max, referrer); + + // Approve other to transfer a significant amount + vm.prank(sender); + vault.approve(other, depositAmount / 4); + + // Try to transferFrom a significant amount + vm.prank(other); + _startSnapshotGas('GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv'); + vm.expectRevert(Errors.LowLtv.selector); + vault.transferFrom(sender, other, depositAmount / 4); // 25% of collateral + _stopSnapshotGas(); + } + + function test_canTransferFromSharesWithHighLtv() public { + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + uint256 depositAmount = 10 ether; + uint256 depositShares = vault.convertToShares(depositAmount); + + // Deposit GNO + _depositGno(depositAmount, sender, sender); + + // Mint a very small amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, depositShares / 100, referrer); // Just 1% of deposit + + // Approve other to transfer shares + vm.prank(sender); + vault.approve(other, depositShares / 2); + + // Should be able to transferFrom most shares + vm.prank(other); + _startSnapshotGas('GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv'); + vault.transferFrom(sender, other, depositShares / 2); + _stopSnapshotGas(); + + // Verify the transfer succeeded + assertApproxEqAbs(vault.balanceOf(sender), depositShares - depositShares / 2, 1); + assertApproxEqAbs(vault.balanceOf(other), depositShares / 2, 1); + } + + function test_withdrawValidator_validatorsManager() public { + // 1. Set validators manager + address validatorsManager = makeAddr('validatorsManager'); + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 2. First deposit and register a validator + _depositGno(10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas('VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_withdrawValidator_osTokenRedeemer() public { + // 1. Set osToken redeemer + address osTokenRedeemer = makeAddr('osTokenRedeemer'); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // 2. First deposit and mint osToken + _depositGno(10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(osTokenRedeemer); + _startSnapshotGas('VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_withdrawValidator_unknown() public { + // 1. Set unknown address + address unknown = makeAddr('unknown'); + + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // 2. First deposit and mint osToken + _depositGno(10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(unknown); + _startSnapshotGas('VaultGnoErc20VaultTest_test_withdrawValidator_unknown'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } +} diff --git a/test/gnosis/GnoGenesisVault.spec.ts b/test/gnosis/GnoGenesisVault.spec.ts deleted file mode 100644 index feea3f4b..00000000 --- a/test/gnosis/GnoGenesisVault.spec.ts +++ /dev/null @@ -1,405 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - ERC20Mock, - GnoGenesisVault, - Keeper, - LegacyRewardTokenMock, - PoolEscrowMock, - DepositDataRegistry, -} from '../../typechain-types' -import { expect } from '../shared/expect' -import keccak256 from 'keccak256' -import { - EXITING_ASSETS_MIN_DELAY, - SECURITY_DEPOSIT, - ZERO_ADDRESS, - ZERO_BYTES32, -} from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import { registerEthValidator } from '../shared/validators' -import { getHarvestParams, getRewardsRootProof, updateRewards } from '../shared/rewards' -import { - extractDepositShares, - extractExitPositionTicket, - getBlockTimestamp, - increaseTime, -} from '../shared/utils' -import { ThenArg } from '../../helpers/types' -import { - collateralizeGnoVault, - depositGno, - gnoVaultFixture, - setGnoWithdrawals, -} from '../shared/gnoFixtures' - -describe('GnoGenesisVault', () => { - const capacity = ethers.parseEther('1000000') - const feePercent = 500 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let admin: Wallet, other: Wallet - let vault: GnoGenesisVault, keeper: Keeper, validatorsRegistry: Contract, gnoToken: ERC20Mock - let poolEscrow: PoolEscrowMock - let rewardToken: LegacyRewardTokenMock, depositDataRegistry: DepositDataRegistry - - let createGenesisVault: ThenArg>['createGnoGenesisVault'] - - async function acceptPoolEscrowOwnership() { - await vault.connect(admin).acceptPoolEscrowOwnership() - } - - async function collatGnoVault() { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - } - - beforeEach('deploy fixtures', async () => { - ;[admin, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - gnoToken = fixture.gnoToken - depositDataRegistry = fixture.depositDataRegistry - ;[vault, rewardToken, poolEscrow] = await fixture.createGnoGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - createGenesisVault = fixture.createGnoGenesisVault - }) - - it('initializes correctly', async () => { - await expect(vault.connect(admin).initialize(ZERO_BYTES32)).to.revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - expect(await vault.capacity()).to.be.eq(capacity) - - // VaultAdmin - const adminAddr = await admin.getAddress() - - // VaultVersion - expect(await vault.version()).to.be.eq(4) - expect(await vault.vaultId()).to.be.eq(`0x${keccak256('GnoGenesisVault').toString('hex')}`) - - // VaultFee - expect(await vault.admin()).to.be.eq(adminAddr) - expect(await vault.feeRecipient()).to.be.eq(adminAddr) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(4) - }) - - describe('migrate', () => { - it('fails from not rewardToken', async () => { - await expect( - vault.connect(admin).migrate(await admin.getAddress(), ethers.parseEther('1')) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails when pool escrow ownership is not accepted', async () => { - const [vault, rewardToken] = await createGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - const assets = ethers.parseEther('10') - await expect( - rewardToken.connect(other).migrate(other.address, assets, 0) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails with zero receiver', async () => { - await acceptPoolEscrowOwnership() - await collatGnoVault() - const assets = ethers.parseEther('1') - await expect( - rewardToken.connect(other).migrate(ZERO_ADDRESS, assets, assets) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('fails with zero assets', async () => { - await acceptPoolEscrowOwnership() - await collatGnoVault() - await expect( - rewardToken.connect(other).migrate(other.address, 0, 0) - ).to.be.revertedWithCustomError(vault, 'InvalidAssets') - }) - - it('fails when not collateralized', async () => { - const [vault, rewardToken] = await createGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - await vault.connect(admin).acceptPoolEscrowOwnership() - const assets = ethers.parseEther('1') - await expect( - rewardToken.connect(other).migrate(other.address, assets, assets) - ).to.be.revertedWithCustomError(vault, 'NotCollateralized') - }) - - it('fails when not harvested', async () => { - await acceptPoolEscrowOwnership() - await collatGnoVault() - const reward = ethers.parseEther('5') - const unlockedMevReward = 0n - const vaultAddr = await vault.getAddress() - const vaultReward = getHarvestParams(vaultAddr, reward, unlockedMevReward) - await updateRewards(keeper, [vaultReward]) - await updateRewards(keeper, [ - getHarvestParams(vaultAddr, reward + ethers.parseEther('5'), unlockedMevReward), - ]) - - const holder = other - const assets = ethers.parseEther('1') - await expect( - rewardToken.connect(holder).migrate(await holder.getAddress(), assets, assets) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('migrates from rewardToken', async () => { - await acceptPoolEscrowOwnership() - await collatGnoVault() - const assets = ethers.parseEther('10') - const expectedShares = await vault.convertToShares(assets) - - const holder = other - const holderAddr = await holder.getAddress() - - const receipt = await rewardToken.connect(holder).migrate(holderAddr, assets, 0) - expect(await vault.getShares(holderAddr)).to.eq(expectedShares) - - await expect(receipt).to.emit(vault, 'Migrated').withArgs(holderAddr, assets, expectedShares) - await snapshotGasCost(receipt) - }) - }) - - it('pulls withdrawals on claim exited assets', async () => { - await acceptPoolEscrowOwnership() - const assets = ethers.parseEther('1') - SECURITY_DEPOSIT - let tx = await depositGno(vault, gnoToken, assets, other, other, ZERO_ADDRESS) - const shares = await extractDepositShares(tx) - expect(await vault.getShares(other.address)).to.eq(shares) - - // register validator - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - expect(await gnoToken.balanceOf(await vault.getAddress())).to.eq(0n) - - // enter exit queue - tx = await vault.connect(other).enterExitQueue(shares, other.address) - const positionTicket = await extractExitPositionTicket(tx) - const timestamp = await getBlockTimestamp(tx) - expect(await vault.getExitQueueIndex(positionTicket)).to.eq(-1) - - // withdrawals arrives - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await setGnoWithdrawals(validatorsRegistry, gnoToken, poolEscrow, assets) - await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - const exitQueueIndex = await vault.getExitQueueIndex(positionTicket) - expect(exitQueueIndex).to.eq(0) - expect(await vault.withdrawableAssets()).to.eq(0n) - - // claim exited assets - await increaseTime(EXITING_ASSETS_MIN_DELAY) - tx = await vault.connect(other).claimExitedAssets(positionTicket, timestamp, exitQueueIndex) - await expect(tx) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(other.address, positionTicket, 0, assets) - await snapshotGasCost(tx) - }) - - describe('update state', () => { - let totalVaultAssets: bigint - let totalLegacyAssets: bigint - - beforeEach(async () => { - totalVaultAssets = ethers.parseEther('10') - totalLegacyAssets = ethers.parseEther('5') - await depositGno( - vault, - gnoToken, - totalVaultAssets - SECURITY_DEPOSIT, - other, - other, - ZERO_ADDRESS - ) - await rewardToken.connect(other).setTotalStaked(totalLegacyAssets) - }) - - it('splits reward between rewardToken and vault', async () => { - await acceptPoolEscrowOwnership() - const reward = ethers.parseEther('30') - const unlockedMevReward = 0n - const expectedVaultDelta = - (reward * totalVaultAssets) / (totalLegacyAssets + totalVaultAssets) - const expectedLegacyDelta = reward - expectedVaultDelta - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - expect(await rewardToken.totalAssets()).to.eq(totalLegacyAssets + expectedLegacyDelta) - expect(await vault.totalAssets()).to.eq(totalVaultAssets + expectedVaultDelta) - await snapshotGasCost(receipt) - }) - - it('skips updating legacy with zero total assets', async () => { - await acceptPoolEscrowOwnership() - await rewardToken.setTotalStaked(0n) - await rewardToken.setTotalRewards(0n) - await rewardToken.setTotalPenalty(0n) - - const reward = ethers.parseEther('5') - const unlockedMevReward = 0n - - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - - const totalLegacyAssetsBefore = await rewardToken.totalAssets() - const totalVaultAssetsBefore = await vault.totalAssets() - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - expect(await rewardToken.totalAssets()).to.eq(totalLegacyAssetsBefore) - expect(await vault.totalAssets()).to.eq(totalVaultAssetsBefore + reward) - await snapshotGasCost(receipt) - }) - - it('fails when pool escrow ownership not accepted', async () => { - const [vault] = await createGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - const totalRewards = ethers.parseEther('30') - const vaultReward = getHarvestParams(await vault.getAddress(), totalRewards, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ).to.be.revertedWithCustomError(vault, 'InvalidInitialHarvest') - }) - - it('fails with negative first update', async () => { - const [vault] = await createGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - await vault.connect(admin).acceptPoolEscrowOwnership() - const totalPenalty = ethers.parseEther('-5') - const vaultReward = getHarvestParams(await vault.getAddress(), totalPenalty, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ).to.revertedWithCustomError(vault, 'InvalidInitialHarvest') - }) - - it('splits penalty between rewardToken and vault', async () => { - await acceptPoolEscrowOwnership() - await collatGnoVault() - const reward = ethers.parseEther('-5') - const unlockedMevReward = 0n - const expectedVaultDelta = - (reward * totalVaultAssets) / (totalLegacyAssets + totalVaultAssets) - const expectedLegacyDelta = reward - expectedVaultDelta - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - expect((await rewardToken.totalAssets()) - (await rewardToken.totalPenalty())).to.eq( - totalLegacyAssets + expectedLegacyDelta + 1n // rounding error - ) - expect(await vault.totalAssets()).to.eq(totalVaultAssets + expectedVaultDelta - 1n) // rounding error - await snapshotGasCost(receipt) - }) - - it('deducts rewards on first state update', async () => { - const [vault, rewardToken] = await createGenesisVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - await vault.connect(admin).acceptPoolEscrowOwnership() - await depositGno( - vault, - gnoToken, - totalVaultAssets - SECURITY_DEPOSIT, - other, - other, - ZERO_ADDRESS - ) - await rewardToken.connect(other).setTotalStaked(totalLegacyAssets) - - const totalRewards = ethers.parseEther('25') - const legacyRewards = ethers.parseEther('5') - await rewardToken.connect(other).setTotalRewards(legacyRewards) - expect(await rewardToken.totalAssets()).to.eq(totalLegacyAssets + legacyRewards) - expect(await rewardToken.totalRewards()).to.eq(legacyRewards) - expect(await vault.totalAssets()).to.eq(totalVaultAssets) - - const expectedVaultDelta = - ((totalRewards - legacyRewards) * totalVaultAssets) / - (totalLegacyAssets + legacyRewards + totalVaultAssets) - const expectedLegacyDelta = totalRewards - legacyRewards - expectedVaultDelta - const vaultReward = getHarvestParams(await vault.getAddress(), totalRewards, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - expect(await rewardToken.totalAssets()).to.eq( - totalLegacyAssets + legacyRewards + expectedLegacyDelta - ) - expect(await vault.totalAssets()).to.eq(totalVaultAssets + expectedVaultDelta) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/gnosis/GnoGenesisVault.t.sol b/test/gnosis/GnoGenesisVault.t.sol new file mode 100644 index 00000000..016bebab --- /dev/null +++ b/test/gnosis/GnoGenesisVault.t.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {IGnoGenesisVault} from '../../contracts/interfaces/IGnoGenesisVault.sol'; +import {GnoGenesisVault} from '../../contracts/vaults/gnosis/GnoGenesisVault.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; + +contract GnoGenesisVaultTest is Test, GnoHelpers { + ForkContracts public contracts; + address public admin; + address public user; + address public poolEscrow; + address public rewardGnoToken; + bytes public initParams; + + function setUp() public { + // Activate Gnosis fork and get contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + + // Provide GNO to the test accounts + _mintGnoToken(admin, 100 ether); + _mintGnoToken(user, 100 ether); + + // Get pool escrow and reward token addresses from the helper + poolEscrow = _poolEscrow; + rewardGnoToken = _rewardGnoToken; + + initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + } + + function test_deployFails() public { + // Deploy the vault directly + vm.deal(admin, 1 ether); + vm.prank(admin); + address impl = _getOrCreateVaultImpl(VaultType.GnoGenesisVault); + address _vault = address(new ERC1967Proxy(impl, '')); + + vm.expectRevert(Errors.UpgradeFailed.selector); + IGnoGenesisVault(_vault).initialize(initParams); + } + + function test_upgradesCorrectly() public { + // Get or create a vault + address vaultAddr = _getForkVault(VaultType.GnoGenesisVault); + GnoGenesisVault existingVault = GnoGenesisVault(payable(vaultAddr)); + + _depositToVault(address(existingVault), 15 ether, user, user); + _registerGnoValidator(address(existingVault), 1 ether, true); + + vm.prank(user); + existingVault.enterExitQueue(10 ether, user); + + // Record initial state + uint256 initialTotalAssets = existingVault.totalAssets(); + uint256 initialTotalShares = existingVault.totalShares(); + uint256 totalExitingAssetsBefore = existingVault.totalExitingAssets(); + uint256 queuedSharesBefore = existingVault.queuedShares(); + uint256 senderBalanceBefore = existingVault.getShares(user); + uint256 initialCapacity = existingVault.capacity(); + uint256 initialFeePercent = existingVault.feePercent(); + address validatorsManager = existingVault.validatorsManager(); + address feeRecipient = existingVault.feeRecipient(); + address adminBefore = existingVault.admin(); + + assertEq(existingVault.vaultId(), keccak256('GnoGenesisVault')); + assertEq(existingVault.version(), 3); + + _startSnapshotGas('GnoGenesisVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoGenesisVault, address(existingVault)); + _stopSnapshotGas(); + + assertEq(existingVault.vaultId(), keccak256('GnoGenesisVault')); + assertEq(existingVault.version(), 4); + assertEq(existingVault.admin(), adminBefore); + assertEq(existingVault.capacity(), initialCapacity); + assertEq(existingVault.feePercent(), initialFeePercent); + assertEq(existingVault.feeRecipient(), feeRecipient); + assertEq(existingVault.validatorsManager(), validatorsManager); + assertEq(existingVault.queuedShares(), queuedSharesBefore); + assertEq(existingVault.totalShares(), initialTotalShares); + assertEq(existingVault.totalAssets(), initialTotalAssets); + assertEq(existingVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(existingVault.validatorsManagerNonce(), 0); + assertEq(existingVault.getShares(user), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(existingVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + } + + function test_cannotInitializeTwice() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Try to initialize it again + vm.prank(admin); + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize(initParams); + } + + function test_migrate_failsWithInvalidCaller() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Try to migrate with invalid caller (not rewardGnoToken) + vm.prank(user); + vm.expectRevert(Errors.AccessDenied.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithNotHarvested() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Ensure vault needs harvesting + _setGnoVaultReward(address(vault), 1 ether, 0); + _setGnoVaultReward(address(vault), 2 ether, 0); + + vm.prank(rewardGnoToken); + vm.expectRevert(Errors.NotHarvested.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithInvalidReceiver() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + vm.prank(rewardGnoToken); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.migrate(address(0), 1 ether); + } + + function test_migrate_failsWithInvalidAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + vm.prank(rewardGnoToken); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.migrate(user, 0); + } + + function test_migrate_works() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + + // Set up migration + uint256 migrateAmount = 10 ether; + uint256 osTokenShares = vault.osTokenPositions(user); + assertEq(osTokenShares, 0, 'OsToken position should be empty'); + + // Perform migration + _startSnapshotGas('GnoGenesisVaultTest_test_migrate_works'); + vm.prank(rewardGnoToken); + uint256 shares = vault.migrate(user, migrateAmount); + _stopSnapshotGas(); + + // Verify results + assertGt(shares, 0, 'Should have minted shares'); + assertEq(vault.getShares(user), shares, 'User should have received shares'); + assertEq( + vault.totalAssets(), + initialTotalAssets + migrateAmount, + 'Total assets should increase' + ); + assertEq(vault.totalShares(), initialTotalShares + shares, 'Total shares should increase'); + + // Verify OsToken position + osTokenShares = vault.osTokenPositions(user); + assertGt(osTokenShares, 0, 'OsToken position should match shares'); + } + + function test_pullWithdrawals_claimEscrowAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Add some GNO to the pool escrow + uint256 escrowAmount = 5 ether; + _mintGnoToken(poolEscrow, escrowAmount); + + // Set up withdrawable amount in the validators registry for the escrow + uint256 withdrawalAmount = 3 ether; + _setGnoWithdrawals(poolEscrow, withdrawalAmount); + + // Record initial balances + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + + // Register a validator to trigger _pullWithdrawals + _startSnapshotGas('GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets'); + _registerGnoValidator(address(vault), 1 ether, false); + _stopSnapshotGas(); + + // Verify results + uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); + uint256 escrowFinalBalance = contracts.gnoToken.balanceOf(poolEscrow); + + assertGt( + vaultFinalBalance, + vaultInitialBalance, + 'Vault balance should increase from claiming escrow assets' + ); + + assertLt(escrowFinalBalance, escrowAmount, 'Escrow balance should decrease from withdrawal'); + } +} diff --git a/test/gnosis/GnoOsTokenVaultEscrow.spec.ts b/test/gnosis/GnoOsTokenVaultEscrow.spec.ts deleted file mode 100644 index f67c0dbb..00000000 --- a/test/gnosis/GnoOsTokenVaultEscrow.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ethers } from 'hardhat' -import { Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - ERC20Mock, - GnoVault, - IKeeperRewards, - Keeper, - OsTokenVaultEscrow, - OsTokenVaultEscrowAuthMock, - OsTokenVaultEscrowAuthMock__factory, -} from '../../typechain-types' -import { collateralizeGnoVault, depositGno, gnoVaultFixture } from '../shared/gnoFixtures' -import { EXITING_ASSETS_MIN_DELAY, ZERO_ADDRESS } from '../shared/constants' -import { getHarvestParams, getRewardsRootProof, updateRewards } from '../shared/rewards' -import { extractExitPositionTicket, getBlockTimestamp, increaseTime } from '../shared/utils' -import { expect } from '../shared/expect' - -describe('GnoOsTokenVaultEscrow', () => { - const assets = ethers.parseEther('100') - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let dao: Wallet, admin: Signer, owner: Wallet - let vault: GnoVault, - osTokenVaultEscrow: OsTokenVaultEscrow, - osTokenVaultEscrowAuth: OsTokenVaultEscrowAuthMock, - keeper: Keeper, - gnoToken: ERC20Mock - let vaultAddr: string - let osTokenShares: bigint - - beforeEach('deploy fixture', async () => { - ;[dao, admin, owner] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - vault = await fixture.createGnoVault(admin, vaultParams) - vaultAddr = await vault.getAddress() - admin = await ethers.getImpersonatedSigner(await vault.admin()) - osTokenVaultEscrow = fixture.osTokenVaultEscrow - keeper = fixture.keeper - gnoToken = fixture.gnoToken - osTokenVaultEscrowAuth = OsTokenVaultEscrowAuthMock__factory.connect( - await osTokenVaultEscrow.authenticator(), - dao - ) - await osTokenVaultEscrowAuth.setCanRegister(owner.address, true) - - // collateralize vault - await collateralizeGnoVault( - vault, - fixture.gnoToken, - fixture.keeper, - fixture.depositDataRegistry, - admin as Wallet, - fixture.validatorsRegistry - ) - await depositGno(vault, gnoToken, assets, owner, owner, ZERO_ADDRESS) - osTokenShares = await fixture.osTokenVaultController.convertToShares(assets / 2n) - await vault.connect(owner).mintOsToken(owner.address, osTokenShares, ZERO_ADDRESS) - }) - - it('succeeds', async () => { - const exitOsTokenShares = await vault.osTokenPositions(owner.address) - let tx = await vault.connect(owner).transferOsTokenPositionToEscrow(exitOsTokenShares) - const positionTicket = await extractExitPositionTicket(tx) - const timestamp = await getBlockTimestamp(tx) - - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - await osTokenVaultEscrow - .connect(owner) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - const balanceBefore = await gnoToken.balanceOf(owner.address) - tx = await osTokenVaultEscrow - .connect(owner) - .claimExitedAssets(vaultAddr, positionTicket, exitOsTokenShares) - const balanceAfter = await gnoToken.balanceOf(owner.address) - expect(balanceAfter).to.be.greaterThan(balanceBefore) - await expect(tx).to.emit(osTokenVaultEscrow, 'ExitedAssetsClaimed') - }) -}) diff --git a/test/gnosis/GnoOsTokenVaultEscrow.t.sol b/test/gnosis/GnoOsTokenVaultEscrow.t.sol new file mode 100644 index 00000000..94caaccb --- /dev/null +++ b/test/gnosis/GnoOsTokenVaultEscrow.t.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from '../../lib/forge-std/src/Test.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; + +interface IStrategiesRegistry { + function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; + function setStrategy(address strategy, bool enabled) external; + + function owner() external view returns (address); +} + +contract GnoOsTokenVaultEscrowTest is Test, GnoHelpers { + IStrategiesRegistry private constant _strategiesRegistry = + IStrategiesRegistry(0x4abB9BBb82922A6893A5d6890cd2eE94610BEc48); + + ForkContracts public contracts; + IGnoVault public vault; + + address public user; + address public admin; + + function setUp() public { + // Activate Gnosis fork and get contracts + contracts = _activateGnosisFork(); + + // Setup addresses + user = makeAddr('user'); + admin = makeAddr('admin'); + + // Fund accounts + vm.deal(user, 1 ether); + _mintGnoToken(user, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Register user + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(user)), user); + + // Create a vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + vault = IGnoVault(_vault); + + // add escrow to vaults registry + vm.prank(contracts.vaultsRegistry.owner()); + contracts.vaultsRegistry.addVault(address(contracts.osTokenVaultEscrow)); + } + + function test_transferAssets() public { + _collateralizeGnoVault(address(vault)); + + uint256 depositAmount = 10 ether; + + _depositToVault(address(vault), depositAmount, user, user); + + // calculate osToken shares + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + // mint osToken shares + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // Transfer osToken position to escrow + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + _startSnapshotGas('GnoOsTokenVaultEscrowTest_test_transferAssets_transfer'); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + + uint256 afterTransferOsTokenPosition = vault.osTokenPositions(user); + assertEq(afterTransferOsTokenPosition, 0, 'osToken position was not transferred'); + + (address owner, uint256 exitedAssets, uint256 escrowOsTokenShares) = contracts + .osTokenVaultEscrow + .getPosition(address(vault), exitPositionTicket); + + assertEq(owner, user, 'Incorrect owner in escrow position'); + assertEq(exitedAssets, 0, 'Exited assets should be zero initially'); + assertEq(escrowOsTokenShares, osTokenShares, 'Incorrect osToken shares in escrow'); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + _mintGnoToken( + address(vault), + vault.totalExitingAssets() + vault.convertToAssets(vault.queuedShares()) + ); + vault.updateState(harvestParams); + + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + _startSnapshotGas('GnoOsTokenVaultEscrowTest_test_transferAssets_process'); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), + exitPositionTicket, + timestamp, + uint256(vault.getExitQueueIndex(exitPositionTicket)) + ); + _stopSnapshotGas(); + + // User claims exited assets + uint256 userBalanceBefore = contracts.gnoToken.balanceOf(user); + + vm.prank(user); + _startSnapshotGas('GnoOsTokenVaultEscrowTest_test_transferAssets_claim'); + uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares + ); + _stopSnapshotGas(); + + uint256 userBalanceAfter = contracts.gnoToken.balanceOf(user); + + assertEq( + userBalanceAfter - userBalanceBefore, + claimedAssets, + 'Incorrect amount of assets transferred' + ); + assertGt(claimedAssets, 0, 'No assets were claimed'); + } +} diff --git a/test/gnosis/GnoOwnMevEscrow.spec.ts b/test/gnosis/GnoOwnMevEscrow.spec.ts deleted file mode 100644 index bdab9079..00000000 --- a/test/gnosis/GnoOwnMevEscrow.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ethers } from 'hardhat' -import { ContractFactory, Wallet } from 'ethers' -import { OwnMevEscrow__factory } from '../../typechain-types' -import snapshotGasCost from '../shared/snapshotGasCost' -import { expect } from '../shared/expect' - -describe('GnoOwnMevEscrow', () => { - let ownMevEscrowFactory: ContractFactory - let vault: Wallet, other: Wallet - - before(async () => { - ;[vault, other] = await (ethers as any).getSigners() - ownMevEscrowFactory = await ethers.getContractFactory('GnoOwnMevEscrow') - }) - - it('vault deployment gas', async () => { - const contract = await ownMevEscrowFactory.deploy(await vault.getAddress()) - await snapshotGasCost(contract.deploymentTransaction() as any) - }) - - it('only vault can withdraw assets', async () => { - const tx = await ethers.deployContract('GnoOwnMevEscrow', [await vault.getAddress()]) - const contract = await tx.waitForDeployment() - const ownMevEscrow = OwnMevEscrow__factory.connect(await contract.getAddress(), other) - await expect(ownMevEscrow.connect(other).harvest()).to.be.revertedWithCustomError( - ownMevEscrow, - 'HarvestFailed' - ) - }) - - it('emits event on transfers', async () => { - const value = ethers.parseEther('1') - const tx = await ethers.deployContract('OwnMevEscrow', [await vault.getAddress()]) - const contract = await tx.waitForDeployment() - const ownMevEscrow = OwnMevEscrow__factory.connect(await contract.getAddress(), other) - - await expect( - other.sendTransaction({ - to: await ownMevEscrow.getAddress(), - value: value, - }) - ) - .to.be.emit(ownMevEscrow, 'MevReceived') - .withArgs(value) - }) -}) diff --git a/test/gnosis/GnoOwnMevEscrow.t.sol b/test/gnosis/GnoOwnMevEscrow.t.sol new file mode 100644 index 00000000..0637e5e0 --- /dev/null +++ b/test/gnosis/GnoOwnMevEscrow.t.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; + +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {IOwnMevEscrow} from '../../contracts/interfaces/IOwnMevEscrow.sol'; +import {GnoOwnMevEscrow} from '../../contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol'; + +contract GnoOwnMevEscrowTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoOwnMevEscrow public ownMevEscrow; + address public vault; + address public other; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + vault = makeAddr('vault'); + other = makeAddr('other'); + vm.deal(other, 10 ether); // Give 'other' some xDAI + + // Deploy the contract + ownMevEscrow = new GnoOwnMevEscrow(vault); + } + + function test_ownMevEscrowDeploymentGas() public { + _startSnapshotGas('GnoOwnMevEscrowTest_test_ownMevEscrowDeploymentGas'); + new GnoOwnMevEscrow(vault); + _stopSnapshotGas(); + } + + function test_onlyVaultCanWithdrawAssets() public { + // Attempt to call harvest from a non-vault address should revert + vm.prank(other); + vm.expectRevert(Errors.HarvestFailed.selector); + ownMevEscrow.harvest(); + } + + function test_emitsEventOnTransfers() public { + uint256 value = 1 ether; + + // Expect the MevReceived event with the correct value + vm.expectEmit(true, false, false, true); + emit IOwnMevEscrow.MevReceived(value); + + // Send xDAI from the other account + vm.prank(other); + (bool success, ) = address(ownMevEscrow).call{value: value}(''); + vm.assertTrue(success, 'xDAI transfer failed'); + } + + function test_worksWithZeroBalance() public { + // Ensure contract has zero balance + assertEq(address(ownMevEscrow).balance, 0); + + // Call harvest as vault + vm.prank(vault); + uint256 harvestedAmount = ownMevEscrow.harvest(); + + // Should always return 0 + assertEq(harvestedAmount, 0); + + // Vault balance should remain unchanged + assertEq(vault.balance, 0); + } + + function test_worksWithNonZeroBalance() public { + uint256 mevAmount = 0.5 ether; + + // Send xDAI to the contract to simulate MEV rewards + vm.deal(address(ownMevEscrow), mevAmount); + assertEq(address(ownMevEscrow).balance, mevAmount); + + // Record vault's initial balance + uint256 initialVaultBalance = vault.balance; + + // Expect the Harvested event with the correct value + vm.expectEmit(true, false, false, true); + emit IOwnMevEscrow.Harvested(mevAmount); + + // Call harvest as vault + vm.prank(vault); + uint256 harvestedAmount = ownMevEscrow.harvest(); + + // Should always return 0 + assertEq(harvestedAmount, 0); + + // Vault balance should increase by the harvested amount + assertEq(vault.balance, initialVaultBalance + mevAmount); + + // Contract balance should now be 0 + assertEq(address(ownMevEscrow).balance, 0); + } +} diff --git a/test/gnosis/GnoPrivErc20Vault.spec.ts b/test/gnosis/GnoPrivErc20Vault.spec.ts deleted file mode 100644 index fe867d48..00000000 --- a/test/gnosis/GnoPrivErc20Vault.spec.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - ERC20Mock, - GnoPrivErc20Vault, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../../typechain-types' -import { collateralizeGnoVault, depositGno, gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' - -describe('GnoPrivErc20Vault', () => { - const name = 'SW GNO Vault' - const symbol = 'SW-GNO-1' - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, whitelister: Wallet, receiver: Wallet - let vault: GnoPrivErc20Vault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - gnoToken: ERC20Mock, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, whitelister] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - vault = await fixture.createGnoPrivErc20Vault(admin, { - name, - symbol, - capacity, - feePercent, - metadataIpfsHash, - }) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - gnoToken = fixture.gnoToken - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('GnoPrivErc20Vault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(whitelister.address) - await vault.connect(whitelister).updateWhitelist(sender.address, true) - }) - - it('cannot be called by not whitelisted sender', async () => { - await expect( - depositGno(vault, gnoToken, amount, receiver, sender, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to not whitelisted user', async () => { - await expect( - depositGno(vault, gnoToken, amount, sender, receiver, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by whitelisted user', async () => { - const receipt = await depositGno(vault, gnoToken, amount, sender, sender, referrer) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, amount, shares, referrer) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await vault.connect(admin).updateWhitelist(await admin.getAddress(), true) - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await vault.connect(admin).updateWhitelist(sender.address, true) - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not whitelisted user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) - - describe('transfer', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).updateWhitelist(sender.address, true) - await depositGno(vault, gnoToken, amount, sender, sender, referrer) - }) - - it('cannot transfer to not whitelisted user', async () => { - await expect( - vault.connect(sender).transfer(other.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot transfer from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(other.address, true) - await vault.connect(sender).transfer(other.address, amount) - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(other).transfer(sender.address, amount) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can transfer to whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(other.address, true) - const receipt = await vault.connect(sender).transfer(other.address, amount) - expect(await vault.balanceOf(sender.address)).to.eq(0) - expect(await vault.balanceOf(other.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Transfer') - .withArgs(sender.address, other.address, amount) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/gnosis/GnoPrivErc20Vault.t.sol b/test/gnosis/GnoPrivErc20Vault.t.sol new file mode 100644 index 00000000..36cf17b7 --- /dev/null +++ b/test/gnosis/GnoPrivErc20Vault.t.sol @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; +import {GnoPrivErc20Vault} from '../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol'; + +contract GnoPrivErc20VaultTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoPrivErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + whitelister = makeAddr('whitelister'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoPrivErc20Vault, admin, initParams, false); + vault = GnoPrivErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('GnoPrivErc20Vault'); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 3); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_transfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(other, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas('GnoPrivErc20VaultTest_test_transfer'); + vault.transfer(other, shares); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(sender), 0, 1); + assertEq(vault.balanceOf(other), shares); + } + + function test_cannotTransferToNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not other + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Try to transfer to non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist other but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(other, true); + + // First whitelist sender temporarily to deposit + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to transfer from non-whitelisted user to whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit as non-whitelisted user + vm.startPrank(other); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user to whitelisted receiver + _startSnapshotGas('GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser'); + _depositGno(amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(receiver), expectedShares, 1); + } + + function test_cannotMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and temporarily whitelist sender to deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken as non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('GnoPrivErc20VaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.GnoPrivErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); + + assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); + assertEq(privErc20Vault.version(), 3); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.queuedShares(), 0); + assertEq(privErc20Vault.totalShares(), _securityDeposit); + assertEq(privErc20Vault.totalAssets(), _securityDeposit); + assertEq(privErc20Vault.totalExitingAssets(), 0); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.totalSupply(), _securityDeposit); + assertEq(privErc20Vault.symbol(), 'SW-GNO-1'); + assertEq(privErc20Vault.name(), 'SW GNO Vault'); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: 'SW GNO Vault', + symbol: 'SW-GNO-1', + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoPrivErc20Vault, admin, initParams, true); + GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); + + // whitelist sender and register validator + vm.prank(privErc20Vault.whitelister()); + privErc20Vault.updateWhitelist(sender, true); + + _depositToVault(address(privErc20Vault), 15 ether, sender, sender); + _registerGnoValidator(address(privErc20Vault), 1 ether, true); + + vm.prank(sender); + privErc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privErc20Vault.totalShares(); + uint256 totalAssetsBefore = privErc20Vault.totalAssets(); + uint256 totalExitingAssetsBefore = privErc20Vault.totalExitingAssets(); + uint256 queuedSharesBefore = privErc20Vault.queuedShares(); + uint256 senderBalanceBefore = privErc20Vault.getShares(sender); + + assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); + assertEq(privErc20Vault.version(), 2); + assertEq( + contracts.gnoToken.allowance(address(privErc20Vault), address(contracts.validatorsRegistry)), + 0 + ); + + _startSnapshotGas('GnoPrivErc20VaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoPrivErc20Vault, address(privErc20Vault)); + _stopSnapshotGas(); + + assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); + assertEq(privErc20Vault.version(), 3); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.queuedShares(), queuedSharesBefore); + assertEq(privErc20Vault.totalShares(), totalSharesBefore); + assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); + assertEq(privErc20Vault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(privErc20Vault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + assertEq(privErc20Vault.totalSupply(), totalSharesBefore); + assertEq(privErc20Vault.symbol(), 'SW-GNO-1'); + assertEq(privErc20Vault.name(), 'SW GNO Vault'); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } +} diff --git a/test/gnosis/GnoPrivVault.spec.ts b/test/gnosis/GnoPrivVault.spec.ts deleted file mode 100644 index 66379ff9..00000000 --- a/test/gnosis/GnoPrivVault.spec.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - ERC20Mock, - GnoPrivVault, - Keeper, - OsTokenVaultController, - DepositDataRegistry, -} from '../../typechain-types' -import { collateralizeGnoVault, depositGno, gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { ZERO_ADDRESS } from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import keccak256 from 'keccak256' -import { extractDepositShares } from '../shared/utils' - -describe('GnoPrivVault', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, admin: Wallet, other: Wallet, whitelister: Wallet, receiver: Wallet - let vault: GnoPrivVault, - keeper: Keeper, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - gnoToken: ERC20Mock, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other, whitelister] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - vault = await fixture.createGnoPrivVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - osTokenVaultController = fixture.osTokenVaultController - gnoToken = fixture.gnoToken - depositDataRegistry = fixture.depositDataRegistry - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('GnoPrivVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).setWhitelister(whitelister.address) - await vault.connect(whitelister).updateWhitelist(sender.address, true) - }) - - it('cannot be called by not whitelisted sender', async () => { - await expect( - depositGno(vault, gnoToken, amount, receiver, sender, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to not whitelisted user', async () => { - await expect( - depositGno(vault, gnoToken, amount, sender, receiver, referrer) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by whitelisted user', async () => { - const receipt = await depositGno(vault, gnoToken, amount, sender, sender, referrer) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, amount, shares, referrer) - await snapshotGasCost(receipt) - }) - }) - - describe('mint osToken', () => { - const assets = ethers.parseEther('1') - let osTokenShares: bigint - - beforeEach(async () => { - await vault.connect(admin).updateWhitelist(await admin.getAddress(), true) - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await vault.connect(admin).updateWhitelist(sender.address, true) - await depositGno(vault, gnoToken, assets, sender, sender, referrer) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint from not whitelisted user', async () => { - await vault.connect(admin).updateWhitelist(sender.address, false) - await expect( - vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can mint from not whitelisted user', async () => { - const tx = await vault - .connect(sender) - .mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - await expect(tx).to.emit(vault, 'OsTokenMinted') - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/gnosis/GnoPrivVault.t.sol b/test/gnosis/GnoPrivVault.t.sol new file mode 100644 index 00000000..4284f28a --- /dev/null +++ b/test/gnosis/GnoPrivVault.t.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {GnoPrivVault} from '../../contracts/vaults/gnosis/GnoPrivVault.sol'; + +contract GnoPrivVaultTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoPrivVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + other = makeAddr('other'); + whitelister = makeAddr('whitelister'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoPrivVault, admin, initParams, false); + vault = GnoPrivVault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_cannotDepositFromNotWhitelistedSender() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist receiver but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(receiver, true); + + // Try to deposit from non-whitelisted user + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 assets = 1 ether; + uint256 shares = vault.convertToShares(assets); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user + _startSnapshotGas('GnoPrivVaultTest_test_canDepositAsWhitelistedUser'); + _depositGno(assets, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_cannotMintOsTokenFromNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and whitelist a user for initial deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken from non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas('GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser'); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_whitelistUpdateDoesNotAffectExistingFunds() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + uint256 initialBalance = vault.getShares(sender); + assertApproxEqAbs(initialBalance, vault.convertToShares(amount), 1); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Verify share balance remains the same + assertEq( + vault.getShares(sender), + initialBalance, + 'Balance should not change when whitelisting is removed' + ); + + // Verify cannot make new deposits but still has existing shares + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, sender, referrer); + vm.stopPrank(); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('GnoPrivVaultTest_test_deploysCorrectly'); + address _vault = _createVault(VaultType.GnoPrivVault, admin, initParams, false); + _stopSnapshotGas(); + GnoPrivVault privVault = GnoPrivVault(payable(_vault)); + + assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); + assertEq(privVault.version(), 3); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), admin); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.queuedShares(), 0); + assertEq(privVault.totalShares(), _securityDeposit); + assertEq(privVault.totalAssets(), _securityDeposit); + assertEq(privVault.totalExitingAssets(), 0); + assertEq(privVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoPrivVault, admin, initParams, false); + GnoPrivVault privVault = GnoPrivVault(payable(_vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + privVault.setWhitelister(whitelister); + + vm.prank(whitelister); + privVault.updateWhitelist(sender, true); + + // Make a deposit + _depositToVault(address(privVault), 15 ether, sender, sender); + _registerGnoValidator(address(privVault), 1 ether, true); + + vm.prank(sender); + privVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privVault.totalShares(); + uint256 totalAssetsBefore = privVault.totalAssets(); + uint256 totalExitingAssetsBefore = privVault.totalExitingAssets(); + uint256 queuedSharesBefore = privVault.queuedShares(); + uint256 senderBalanceBefore = privVault.getShares(sender); + bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); + + assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); + assertEq(privVault.version(), 2); + assertEq( + contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), + 0 + ); + + _startSnapshotGas('GnoPrivVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoPrivVault, address(privVault)); + _stopSnapshotGas(); + + assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); + assertEq(privVault.version(), 3); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), whitelister); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.queuedShares(), queuedSharesBefore); + assertEq(privVault.totalShares(), totalSharesBefore); + assertEq(privVault.totalAssets(), totalAssetsBefore); + assertEq(privVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(privVault.getShares(sender), senderBalanceBefore); + assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); + assertEq( + contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + } + + function test_setWhitelister() public { + address newWhitelister = makeAddr('newWhitelister'); + + // Non-admin cannot set whitelister + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setWhitelister(newWhitelister); + + // Admin can set whitelister + vm.prank(admin); + _startSnapshotGas('GnoPrivVaultTest_test_setWhitelister'); + vault.setWhitelister(newWhitelister); + _stopSnapshotGas(); + + assertEq(vault.whitelister(), newWhitelister, 'Whitelister not set correctly'); + } + + function test_updateWhitelist() public { + // Set whitelister + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Non-whitelister cannot update whitelist + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateWhitelist(sender, true); + + // Whitelister can update whitelist + vm.prank(whitelister); + _startSnapshotGas('GnoPrivVaultTest_test_updateWhitelist'); + vault.updateWhitelist(sender, true); + _stopSnapshotGas(); + + assertTrue(vault.whitelistedAccounts(sender), 'Account not whitelisted correctly'); + + // Whitelister can remove from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + assertFalse(vault.whitelistedAccounts(sender), 'Account not removed from whitelist correctly'); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } +} diff --git a/test/gnosis/GnoSharedMevEscrow.spec.ts b/test/gnosis/GnoSharedMevEscrow.spec.ts deleted file mode 100644 index 271d083e..00000000 --- a/test/gnosis/GnoSharedMevEscrow.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { GnoSharedMevEscrow, VaultsRegistry } from '../../typechain-types' -import snapshotGasCost from '../shared/snapshotGasCost' -import { expect } from '../shared/expect' - -import { gnoVaultFixture } from '../shared/gnoFixtures' - -describe('GnoSharedMevEscrow', () => { - let other: Wallet, sharedMevEscrow: GnoSharedMevEscrow, vaultsRegistry: VaultsRegistry - - beforeEach('deploy fixture', async () => { - ;[other] = (await (ethers as any).getSigners()).slice(1, 2) - ;({ sharedMevEscrow, vaultsRegistry } = await loadFixture(gnoVaultFixture)) - }) - - it('vault deployment gas', async () => { - const sharedMevEscrowFactory = await ethers.getContractFactory('GnoSharedMevEscrow') - const tx = await sharedMevEscrowFactory.deploy(await vaultsRegistry.getAddress()) - await snapshotGasCost(tx.deploymentTransaction() as any) - }) - - it('only vault can withdraw assets', async () => { - await expect( - sharedMevEscrow.connect(other).harvest(ethers.parseEther('1')) - ).to.be.revertedWithCustomError(sharedMevEscrow, 'HarvestFailed') - }) - - it('emits event on transfers', async () => { - const value = ethers.parseEther('1') - - await expect( - other.sendTransaction({ - to: await sharedMevEscrow.getAddress(), - value: value, - }) - ) - .to.be.emit(sharedMevEscrow, 'MevReceived') - .withArgs(value) - }) -}) diff --git a/test/gnosis/GnoSharedMevEscrow.t.sol b/test/gnosis/GnoSharedMevEscrow.t.sol new file mode 100644 index 00000000..29dc23d7 --- /dev/null +++ b/test/gnosis/GnoSharedMevEscrow.t.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; + +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; +import {GnoSharedMevEscrow} from '../../contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol'; + +contract GnoSharedMevEscrowTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoSharedMevEscrow public sharedMevEscrow; + address public other; + address public mockVault; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Deploy a new GnoSharedMevEscrow + sharedMevEscrow = new GnoSharedMevEscrow(address(contracts.vaultsRegistry)); + + // Set up test account + other = makeAddr('other'); + vm.deal(other, 10 ether); + + // Register a mock vault in the registry + mockVault = makeAddr('mockVault'); + vm.prank(contracts.vaultsRegistry.owner()); + contracts.vaultsRegistry.addVault(mockVault); + } + + function test_sharedEscrowDeploymentGas() public { + _startSnapshotGas('GnoSharedMevEscrowTest_test_sharedEscrowDeploymentGas'); + new GnoSharedMevEscrow(address(contracts.vaultsRegistry)); + _stopSnapshotGas(); + } + + function test_onlyVaultCanWithdrawAssets() public { + // Attempt to call harvest from a non-vault address should revert + vm.prank(other); + vm.expectRevert(Errors.HarvestFailed.selector); + sharedMevEscrow.harvest(1 ether); + } + + function test_emitsEventOnTransfers() public { + uint256 value = 1 ether; + + // Expect the MevReceived event with the correct value + vm.expectEmit(true, false, false, true); + emit ISharedMevEscrow.MevReceived(value); + + // Send xDAI from the other account + vm.prank(other); + (bool success, ) = address(sharedMevEscrow).call{value: value}(''); + vm.assertTrue(success, 'xDAI transfer failed'); + } + + function test_worksWithZeroBalance() public { + // Simulate a call from the vault with zero balance in the escrow + vm.prank(mockVault); + uint256 balanceBefore = address(mockVault).balance; + + // Harvest should succeed even with 0 balance + sharedMevEscrow.harvest(0); + + // Verify the balance didn't change + assertEq(address(mockVault).balance, balanceBefore, "Vault balance shouldn't change"); + } + + function test_worksWithNonZeroBalance() public { + // Fund the escrow contract + uint256 fundAmount = 3 ether; + vm.deal(address(sharedMevEscrow), fundAmount); + + // Record the initial balances + uint256 escrowBalanceBefore = address(sharedMevEscrow).balance; + uint256 vaultBalanceBefore = address(mockVault).balance; + + // Harvest a portion of the balance + uint256 harvestAmount = 1 ether; + + // The Harvested event should be emitted with the correct amount + vm.expectEmit(true, false, false, true); + emit ISharedMevEscrow.Harvested(mockVault, harvestAmount); + + // Perform the harvest + vm.prank(mockVault); + sharedMevEscrow.harvest(harvestAmount); + + // Verify the balances changed correctly + assertEq( + address(sharedMevEscrow).balance, + escrowBalanceBefore - harvestAmount, + 'Escrow balance should decrease by harvestAmount' + ); + assertEq( + address(mockVault).balance, + vaultBalanceBefore + harvestAmount, + 'Vault balance should increase by harvestAmount' + ); + + // Harvest the remaining balance + uint256 remainingBalance = address(sharedMevEscrow).balance; + + vm.expectEmit(true, false, false, true); + emit ISharedMevEscrow.Harvested(mockVault, remainingBalance); + + vm.prank(mockVault); + sharedMevEscrow.harvest(remainingBalance); + + // Verify escrow is now empty and vault received all funds + assertEq(address(sharedMevEscrow).balance, 0, 'Escrow should be empty'); + assertEq( + address(mockVault).balance, + vaultBalanceBefore + fundAmount, + 'Vault should have received all funds' + ); + } +} diff --git a/test/gnosis/GnoVault.register.spec.ts b/test/gnosis/GnoVault.register.spec.ts deleted file mode 100644 index 9fae85c7..00000000 --- a/test/gnosis/GnoVault.register.spec.ts +++ /dev/null @@ -1,521 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { UintNumberType } from '@chainsafe/ssz' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { ThenArg } from '../../helpers/types' -import { - DepositDataRegistry, - ERC20Mock, - GnoVault, - IKeeperValidators, - Keeper, -} from '../../typechain-types' -import snapshotGasCost from '../shared/snapshotGasCost' -import { expect } from '../shared/expect' -import { toHexString } from '../shared/utils' -import { - appendDepositData, - createEthValidatorsData, - EthValidatorsData, - exitSignatureIpfsHashes, - getEthValidatorsSigningData, - getValidatorProof, - getValidatorsMultiProof, - getWithdrawalCredentials, - registerEthValidator, - ValidatorsMultiProof, -} from '../shared/validators' -import { getOraclesSignatures } from '../shared/fixtures' -import { - MAX_UINT256, - PANIC_CODES, - SECURITY_DEPOSIT, - VALIDATORS_DEADLINE, - VALIDATORS_MIN_ORACLES, - ZERO_ADDRESS, - ZERO_BYTES32, -} from '../shared/constants' -import { gnoVaultFixture, setGnoWithdrawals } from '../shared/gnoFixtures' - -const gwei = 1000000000n -const uintSerializer = new UintNumberType(8) - -describe('GnoVault - register', () => { - const vaultDeposit = ethers.parseEther('1') - const validatorDeposit = ethers.parseEther('32') - const capacity = MAX_UINT256 - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const deadline = VALIDATORS_DEADLINE - - let admin: Signer, other: Wallet - let vault: GnoVault, - keeper: Keeper, - validatorsRegistry: Contract, - gnoToken: ERC20Mock, - depositDataRegistry: DepositDataRegistry - let validatorsData: EthValidatorsData - let validatorsRegistryRoot: string - - let createVault: ThenArg>['createGnoVault'] - - before('create fixture loader', async () => { - ;[admin, other] = (await (ethers as any).getSigners()).slice(1, 3) - }) - - beforeEach('deploy fixture', async () => { - ;({ - validatorsRegistry, - createGnoVault: createVault, - keeper, - gnoToken, - depositDataRegistry, - } = await loadFixture(gnoVaultFixture)) - - vault = await createVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - validatorsData = await createEthValidatorsData(vault) - validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const vaultAddr = await vault.getAddress() - await gnoToken.mint(other.address, vaultDeposit) - await gnoToken.connect(other).approve(vaultAddr, vaultDeposit) - await vault.connect(other).deposit(vaultDeposit, other.address, ZERO_ADDRESS) - await depositDataRegistry.connect(admin).setDepositDataRoot(vaultAddr, validatorsData.root) - }) - - describe('single validator', () => { - let validator: Buffer - let proof: string[] - let approvalParams: IKeeperValidators.ApprovalParamsStruct - - beforeEach(async () => { - validator = validatorsData.validators[0] - proof = getValidatorProof(validatorsData.tree, validator, 0) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - validator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - approvalParams = { - validatorsRegistryRoot, - validators: validator, - signatures, - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails with not enough withdrawable assets', async () => { - await vault.connect(other).enterExitQueue(await vault.getShares(other.address), other.address) - await expect( - depositDataRegistry.registerValidator(await vault.getAddress(), approvalParams, proof) - ).to.be.revertedWithCustomError(vault, 'InsufficientAssets') - }) - - it('fails with invalid validator length', async () => { - const invalidValidator = appendDepositData( - validator, - validatorDeposit, - await vault.getAddress() - ) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - { - validatorsRegistryRoot, - validators: appendDepositData(validator, validatorDeposit, await vault.getAddress()), - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - proof - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - }) - - it('pulls withdrawals on single validator registration', async () => { - await vault.connect(other).enterExitQueue(await vault.getShares(other), other.address) - expect(await vault.withdrawableAssets()).to.eq(SECURITY_DEPOSIT) - await setGnoWithdrawals(validatorsRegistry, gnoToken, vault, vaultDeposit) - expect(await vault.withdrawableAssets()).to.be.eq(vaultDeposit + SECURITY_DEPOSIT) - - const tx = await registerEthValidator( - vault, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await snapshotGasCost(tx) - }) - - it('succeeds', async () => { - const index = await validatorsRegistry.get_deposit_count() - const receipt = await depositDataRegistry.registerValidator( - await vault.getAddress(), - approvalParams, - proof - ) - const publicKey = `0x${validator.subarray(0, 48).toString('hex')}` - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - index - ) - await snapshotGasCost(receipt) - }) - }) - - describe('multiple validators', () => { - let validators: Buffer[] - let indexes: number[] - let approvalParams: IKeeperValidators.ApprovalParamsStruct - let multiProof: ValidatorsMultiProof - let signatures: Buffer - - beforeEach(async () => { - multiProof = getValidatorsMultiProof(validatorsData.tree, validatorsData.validators, [ - ...Array(validatorsData.validators.length).keys(), - ]) - validators = validatorsData.validators - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const sortedVals = multiProof.leaves.map((v) => v[0]) - indexes = validators.map((v) => sortedVals.indexOf(v)) - - // add gno to vault - const missingGno = vaultDeposit * (BigInt(validators.length) - 1n) - await gnoToken.mint(other.address, missingGno) - await gnoToken.connect(other).approve(await vault.getAddress(), missingGno) - await vault.connect(other).deposit(missingGno, other.address, ZERO_ADDRESS) - - // reset validator index - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), ZERO_BYTES32) - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), validatorsData.root) - - signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.concat(validators), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - approvalParams = { - validatorsRegistryRoot, - validators: Buffer.concat(validators), - signatures, - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails with not enough withdrawable assets', async () => { - await vault.connect(other).enterExitQueue(vaultDeposit, other.address) - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(vault, 'InsufficientAssets') - }) - - it('fails with invalid validators count', async () => { - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - validators: Buffer.from(''), - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.from(''), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - }) - - it('fails with invalid deposit data root', async () => { - const invalidRoot = appendDepositData( - validators[1].subarray(0, 144), - validatorDeposit, - await vault.getAddress() - ).subarray(144, 176) - const invalidValidators = [ - Buffer.concat([validators[0].subarray(0, 144), invalidRoot]), - ...validators.slice(1), - ] - const invalidValidatorsConcat = Buffer.concat(invalidValidators) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - deadline, - validators: invalidValidatorsConcat, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidatorsConcat, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWith( - 'DepositContract: reconstructed DepositData does not match supplied deposit_data_root' - ) - }) - - it('fails with invalid deposit amount', async () => { - const invalidValidators = [ - appendDepositData( - validators[0].subarray(0, 144), - ethers.parseEther('1'), - await vault.getAddress() - ), - ...validators.slice(1), - ] - const invalidValidatorsConcat = Buffer.concat(invalidValidators) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - validators: invalidValidatorsConcat, - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidatorsConcat, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWith( - 'DepositContract: reconstructed DepositData does not match supplied deposit_data_root' - ) - }) - - it('fails with invalid withdrawal credentials', async () => { - const invalidValidators = [ - appendDepositData( - validators[0].subarray(0, 144), - ethers.parseEther('1'), - await keeper.getAddress() - ), - ...validators.slice(1), - ] - const invalidValidatorsConcat = Buffer.concat(invalidValidators) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - validators: invalidValidatorsConcat, - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidatorsConcat, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWith( - 'DepositContract: reconstructed DepositData does not match supplied deposit_data_root' - ) - }) - - it('fails with invalid indexes', async () => { - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - [], - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - indexes.map((i) => i + 1), - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithPanic(PANIC_CODES.OUT_OF_BOUND_INDEX) - - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - indexes.sort(() => 0.5 - Math.random()), - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(depositDataRegistry, 'InvalidProof') - }) - - it('fails with invalid validator length', async () => { - const invalidValidators = [ - validators[0].subarray(0, 100), - Buffer.concat([validators[0], validators[1].subarray(0, 10)]), - ] - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - - for (let i = 0; i < invalidValidators.length; i++) { - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - validators: invalidValidators[i], - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidators[i], - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - } - }) - - it('pulls withdrawals on multiple validators registration', async () => { - await vault.connect(other).enterExitQueue(await vault.getShares(other), other.address) - expect(await vault.withdrawableAssets()).to.eq(SECURITY_DEPOSIT) - const withdrawals = vaultDeposit * BigInt(validators.length) - await setGnoWithdrawals(validatorsRegistry, gnoToken, vault, withdrawals) - expect(await vault.withdrawableAssets()).to.be.eq(withdrawals + SECURITY_DEPOSIT) - - const tx = await depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - await snapshotGasCost(tx) - }) - - it('succeeds', async () => { - const startIndex = uintSerializer.deserialize( - ethers.getBytes(await validatorsRegistry.get_deposit_count()) - ) - const receipt = await depositDataRegistry.registerValidators( - await vault.getAddress(), - approvalParams, - indexes, - multiProof.proofFlags, - multiProof.proof - ) - for (let i = 0; i < validators.length; i++) { - const validator = validators[i] - const publicKey = toHexString(validator.subarray(0, 48)) - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - toHexString(Buffer.from(uintSerializer.serialize(startIndex + i))) - ) - } - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/gnosis/GnoVault.spec.ts b/test/gnosis/GnoVault.spec.ts deleted file mode 100644 index 926cfa05..00000000 --- a/test/gnosis/GnoVault.spec.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, parseEther, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - BalancerVaultMock, - ERC20Mock, - GnoVault, - Keeper, - DepositDataRegistry, -} from '../../typechain-types' -import { gnoVaultFixture, setGnoWithdrawals } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import snapshotGasCost from '../shared/snapshotGasCost' -import { - extractExitPositionTicket, - getBlockTimestamp, - increaseTime, - setBalance, -} from '../shared/utils' -import { EXITING_ASSETS_MIN_DELAY, SECURITY_DEPOSIT, ZERO_ADDRESS } from '../shared/constants' -import { registerEthValidator } from '../shared/validators' -import keccak256 from 'keccak256' -import { getHarvestParams, getRewardsRootProof, updateRewards } from '../shared/rewards' - -describe('GnoVault', () => { - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let other: Wallet, admin: Wallet, sender: Wallet, receiver: Wallet - let gnoToken: ERC20Mock, - balancerVault: BalancerVaultMock, - vault: GnoVault, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - beforeEach('deploy fixtures', async () => { - ;[admin, sender, receiver, other] = (await (ethers as any).getSigners()).slice(1, 5) - const fixture = await loadFixture(gnoVaultFixture) - gnoToken = fixture.gnoToken - balancerVault = fixture.balancerVault - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - depositDataRegistry = fixture.depositDataRegistry - vault = await fixture.createGnoVault(admin, vaultParams) - }) - - it('has id', async () => { - expect(await vault.vaultId()).to.eq(`0x${keccak256('GnoVault').toString('hex')}`) - }) - - it('has version', async () => { - expect(await vault.version()).to.eq(3) - }) - - it('cannot initialize twice', async () => { - await expect(vault.connect(other).initialize('0x')).revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - }) - - describe('swap xdai to gno', () => { - const maxXdaiSwap = ethers.parseEther('12000') - let maxGnoSwap: bigint - let xdaiGnoRate: bigint - - beforeEach(async () => { - xdaiGnoRate = await balancerVault.xdaiGnoRate() - maxGnoSwap = (maxXdaiSwap * xdaiGnoRate) / parseEther('1') - await gnoToken.mint(await balancerVault.getAddress(), maxGnoSwap) - await other.sendTransaction({ - to: await vault.getAddress(), - value: maxXdaiSwap, - }) - }) - - it('skips swapping when balance less than 1 gwei xdai', async () => { - await setBalance(await vault.getAddress(), parseEther('0.0000000009')) - const tx = await vault.swapXdaiToGno() - await expect(tx).to.not.emit(vault, 'XdaiSwapped') - await snapshotGasCost(tx) - }) - - it('can swap all xdai to gno', async () => { - const xdaiAmount = maxXdaiSwap - const gnoAmount = maxGnoSwap - const totalAssetsBefore = await vault.totalAssets() - const tx = await vault.swapXdaiToGno() - expect(await vault.totalAssets()).to.eq(totalAssetsBefore + gnoAmount) - await expect(tx).to.emit(vault, 'XdaiSwapped').withArgs(xdaiAmount, gnoAmount) - await snapshotGasCost(tx) - }) - }) - - describe('deposit', () => { - const referrer = '0x' + '1'.repeat(40) - const amount = ethers.parseEther('100') - - beforeEach(async () => { - await gnoToken.mint(sender.address, amount) - await gnoToken.connect(sender).approve(await vault.getAddress(), amount) - }) - - it('fails with zero amount', async () => { - await expect( - vault.connect(sender).deposit(0, receiver.address, referrer) - ).to.be.revertedWithCustomError(vault, 'InvalidAssets') - }) - - it('fails with insufficient gno', async () => { - await gnoToken.connect(sender).approve(await vault.getAddress(), amount + 1n) - await expect( - vault.connect(sender).deposit(amount + 1n, receiver.address, referrer) - ).to.be.revertedWithCustomError(gnoToken, 'ERC20InsufficientBalance') - }) - - it('fails with not approved gno', async () => { - await gnoToken.connect(sender).approve(await vault.getAddress(), 0n) - await expect( - vault.connect(sender).deposit(amount, receiver.address, referrer) - ).to.be.revertedWithCustomError(gnoToken, 'ERC20InsufficientAllowance') - }) - - it('deposit', async () => { - const amount = ethers.parseEther('100') - const expectedShares = ethers.parseEther('100') - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - - const receipt = await vault.connect(sender).deposit(amount, receiver.address, referrer) - expect(await vault.getShares(receiver.address)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, expectedShares, referrer) - await snapshotGasCost(receipt) - }) - }) - - it('pulls withdrawals on claim exited assets', async () => { - // deposit - const assets = ethers.parseEther('1') - SECURITY_DEPOSIT - const shares = await vault.convertToShares(assets) - await gnoToken.mint(sender.address, assets) - await gnoToken.connect(sender).approve(await vault.getAddress(), assets) - await vault.connect(sender).deposit(assets, sender.address, ZERO_ADDRESS) - expect(await vault.getShares(sender.address)).to.eq(shares) - - // register validator - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - expect(await gnoToken.balanceOf(await vault.getAddress())).to.eq(0n) - - // enter exit queue - let tx = await vault.connect(sender).enterExitQueue(shares, receiver.address) - const positionTicket = await extractExitPositionTicket(tx) - const timestamp = await getBlockTimestamp(tx) - expect(await vault.getExitQueueIndex(positionTicket)).to.eq(-1) - - // withdrawals arrives - await setGnoWithdrawals(validatorsRegistry, gnoToken, vault, assets) - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - const exitQueueIndex = await vault.getExitQueueIndex(positionTicket) - expect(exitQueueIndex).to.eq(0) - expect(await vault.withdrawableAssets()).to.eq(0n) - - // claim exited assets - await increaseTime(EXITING_ASSETS_MIN_DELAY) - tx = await vault.connect(receiver).claimExitedAssets(positionTicket, timestamp, exitQueueIndex) - await expect(tx) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(receiver.address, positionTicket, 0, assets) - await snapshotGasCost(tx) - }) -}) diff --git a/test/gnosis/GnoVault.state.spec.ts b/test/gnosis/GnoVault.state.spec.ts deleted file mode 100644 index 2b93c466..00000000 --- a/test/gnosis/GnoVault.state.spec.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, parseEther, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - BalancerVaultMock, - DepositDataRegistry, - ERC20Mock, - GnoOwnMevEscrow, - GnoOwnMevEscrow__factory, - GnoSharedMevEscrow, - GnoVault, - Keeper, -} from '../../typechain-types' -import { collateralizeGnoVault, gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { ThenArg } from '../../helpers/types' -import { getHarvestParams, getRewardsRootProof, updateRewards } from '../shared/rewards' -import { setBalance } from '../shared/utils' -import snapshotGasCost from '../shared/snapshotGasCost' -import { ONE_DAY } from '../shared/constants' - -describe('GnoVault', () => { - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let admin: Wallet - let gnoToken: ERC20Mock, - balancerVault: BalancerVaultMock, - sharedMevEscrow: GnoSharedMevEscrow, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - let xdaiGnoRate: bigint - - let createVault: ThenArg>['createGnoVault'] - - beforeEach('deploy fixtures', async () => { - ;[admin] = (await (ethers as any).getSigners()).slice(1, 2) - const fixture = await loadFixture(gnoVaultFixture) - gnoToken = fixture.gnoToken - balancerVault = fixture.balancerVault - keeper = fixture.keeper - validatorsRegistry = fixture.validatorsRegistry - sharedMevEscrow = fixture.sharedMevEscrow - depositDataRegistry = fixture.depositDataRegistry - createVault = fixture.createGnoVault - await fixture.xdaiExchange.setStalePriceTimeDelta(ONE_DAY * 10) - }) - - describe('Shared MEV Escrow', () => { - let vault: GnoVault - - beforeEach('deploy vault', async () => { - vault = await createVault(admin, vaultParams, false) - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - xdaiGnoRate = await balancerVault.xdaiGnoRate() - }) - - it('does not include MEV rewards in total assets delta', async () => { - const vaultAddr = await vault.getAddress() - const consensusReward = parseEther('0.001') - const executionReward = parseEther('0.002') - const vaultReward = getHarvestParams( - await vault.getAddress(), - consensusReward, - executionReward - ) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await setBalance(await sharedMevEscrow.getAddress(), executionReward) - - const totalAssetsBefore = await vault.totalAssets() - expect(await ethers.provider.getBalance(vaultAddr)).to.eq(0n) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - expect(await vault.totalAssets()).to.eq(totalAssetsBefore + consensusReward) - expect(await ethers.provider.getBalance(vaultAddr)).to.eq(executionReward) - expect(receipt).to.emit(sharedMevEscrow, 'Harvested').withArgs(vaultAddr, executionReward) - await snapshotGasCost(receipt) - - const swappedGno = (executionReward * xdaiGnoRate) / parseEther('1') - await gnoToken.mint(await balancerVault.getAddress(), swappedGno) - - await vault.swapXdaiToGno() - expect(await ethers.provider.getBalance(vaultAddr)).to.eq(0n) - expect(await vault.totalAssets()).to.eq(totalAssetsBefore + consensusReward + swappedGno) - }) - }) - - describe('Own MEV Escrow', () => { - let vault: GnoVault - let mevEscrow: GnoOwnMevEscrow - - beforeEach('deploy vault', async () => { - vault = await createVault(admin, vaultParams, true) - const mevEscrowAddr = await vault.mevEscrow() - mevEscrow = GnoOwnMevEscrow__factory.connect(mevEscrowAddr, admin) - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - xdaiGnoRate = await balancerVault.xdaiGnoRate() - }) - - it('does not include MEV rewards in total assets delta', async () => { - const vaultAddr = await vault.getAddress() - const consensusReward = parseEther('0.001') - const executionReward = parseEther('0.002') - const vaultReward = getHarvestParams(await vault.getAddress(), consensusReward, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - await setBalance(await mevEscrow.getAddress(), executionReward) - - const totalAssetsBefore = await vault.totalAssets() - expect(await ethers.provider.getBalance(vaultAddr)).to.eq(0n) - const receipt = await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - expect(await vault.totalAssets()).to.eq(totalAssetsBefore + consensusReward) - expect(await ethers.provider.getBalance(vaultAddr)).to.eq(executionReward) - - expect(receipt).to.emit(mevEscrow, 'Harvested').withArgs(vaultAddr, executionReward) - await snapshotGasCost(receipt) - - const swappedGno = (executionReward * xdaiGnoRate) / parseEther('1') - await gnoToken.mint(await balancerVault.getAddress(), swappedGno) - - await vault.swapXdaiToGno() - expect(await ethers.provider.getBalance(vaultAddr)).to.eq(0n) - expect(await vault.totalAssets()).to.eq(totalAssetsBefore + consensusReward + swappedGno) - }) - }) -}) diff --git a/test/gnosis/GnoVault.t.sol b/test/gnosis/GnoVault.t.sol new file mode 100644 index 00000000..1c8efca4 --- /dev/null +++ b/test/gnosis/GnoVault.t.sol @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; + +contract GnoVaultTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + referrer = makeAddr('referrer'); + validatorsManager = makeAddr('validatorsManager'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + vault = GnoVault(payable(vaultAddr)); + + // Set validatorsManager for the vault + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + vm.deal(validatorsManager, 1 ether); + } + + function test_cannotInitializeTwice() public { + // Try to initialize the vault again, which should fail + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize('0x'); + } + + function test_deploysCorrectly() public { + // Create a new vault to test deployment + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + _startSnapshotGas('GnoVaultTest_test_deploysCorrectly'); + address vaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); + _stopSnapshotGas(); + + GnoVault newVault = GnoVault(payable(vaultAddr)); + + // Verify the vault was deployed correctly + assertEq(newVault.vaultId(), keccak256('GnoVault')); + assertEq(newVault.version(), 3); + assertEq(newVault.admin(), admin); + assertEq(newVault.capacity(), 1000 ether); + assertEq(newVault.feePercent(), 1000); + assertEq(newVault.feeRecipient(), admin); + assertEq(newVault.validatorsManager(), _depositDataRegistry); + assertEq(newVault.queuedShares(), 0); + assertEq(newVault.totalShares(), _securityDeposit); + assertEq(newVault.totalAssets(), _securityDeposit); + assertEq(newVault.totalExitingAssets(), 0); + assertEq(newVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // Create a v2 vault (previous version) + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); + GnoVault prevVault = GnoVault(payable(vaultAddr)); + + // Deposit some GNO + _depositToVault(address(prevVault), 15 ether, sender, sender); + + // Register a validator + _registerGnoValidator(address(prevVault), 1 ether, true); + + // Enter exit queue with some shares + vm.prank(sender); + prevVault.enterExitQueue(10 ether, sender); + + // Record state before upgrade + uint256 totalSharesBefore = prevVault.totalShares(); + uint256 totalAssetsBefore = prevVault.totalAssets(); + uint256 totalExitingAssetsBefore = prevVault.totalExitingAssets(); + uint256 queuedSharesBefore = prevVault.queuedShares(); + uint256 senderBalanceBefore = prevVault.getShares(sender); + + // Verify current version + assertEq(prevVault.vaultId(), keccak256('GnoVault')); + assertEq(prevVault.version(), 2); + + // Check validator registry allowance + assertEq( + contracts.gnoToken.allowance(address(prevVault), address(contracts.validatorsRegistry)), + 0 + ); + + // Upgrade the vault + _startSnapshotGas('GnoVaultTest_test_upgradesCorrectly'); + _upgradeVault(VaultType.GnoVault, address(prevVault)); + _stopSnapshotGas(); + + // Check that the vault was upgraded correctly + assertEq(prevVault.vaultId(), keccak256('GnoVault')); + assertEq(prevVault.version(), 3); + assertEq(prevVault.admin(), admin); + assertEq(prevVault.capacity(), 1000 ether); + assertEq(prevVault.feePercent(), 1000); + assertEq(prevVault.feeRecipient(), admin); + assertEq(prevVault.validatorsManager(), _depositDataRegistry); + + // State should be preserved + assertEq(prevVault.queuedShares(), queuedSharesBefore); + assertEq(prevVault.totalShares(), totalSharesBefore); + assertEq(prevVault.totalAssets(), totalAssetsBefore); + assertEq(prevVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(prevVault.validatorsManagerNonce(), 0); + assertEq(prevVault.getShares(sender), senderBalanceBefore); + + // Allowance should be set after upgrade + assertEq( + contracts.gnoToken.allowance(address(prevVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + } + + function test_exitQueue_works() public { + // Collateralize the vault first + _collateralizeGnoVault(address(vault)); + + // Deposit GNO into the vault + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, sender, sender); + + // Get initial state + uint256 senderSharesBefore = vault.getShares(sender); + uint256 queuedSharesBefore = vault.queuedShares(); + + // Amount to exit with + uint256 exitAmount = senderSharesBefore / 2; + + // Enter exit queue + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(sender); + _startSnapshotGas('GnoVaultTest_test_exitQueue_works'); + uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); + _stopSnapshotGas(); + + // Check state after entering exit queue + assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, 'Sender shares not reduced'); + assertEq(vault.queuedShares(), queuedSharesBefore + exitAmount, 'Queued shares not increased'); + + _mintGnoToken( + address(vault), + vault.totalExitingAssets() + vault.convertToAssets(vault.queuedShares()) + ); + + // Process exit queue by updating state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Check that position can be found in exit queue + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Wait for the claiming delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Verify exited assets can be calculated + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault + .calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // Assets should be exited and claimable + assertApproxEqAbs(leftTickets, 0, 1, 'All tickets should be processed'); + assertGt(exitedTickets, 0, 'No tickets exited'); + assertGt(exitedAssets, 0, 'No assets exited'); + + // Claim exited assets + uint256 receiverBalanceBefore = contracts.gnoToken.balanceOf(receiver); + + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify receiver got their GNO + uint256 receiverBalanceAfter = contracts.gnoToken.balanceOf(receiver); + assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver didn't get GNO tokens"); + assertEq( + receiverBalanceAfter, + receiverBalanceBefore + exitedAssets, + 'Incorrect amount received' + ); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256('GnoVault'); + assertEq(vault.vaultId(), expectedId, 'Invalid vault ID'); + } + + function test_vaultVersion() public view { + assertEq(vault.version(), 3, 'Invalid vault version'); + } + + function test_withdrawValidator_validatorsManager() public { + // First deposit and register a validator + _depositToVault(address(vault), 10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // Execute withdrawal as validatorsManager + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(validatorsManager); + _startSnapshotGas('GnoVaultTest_test_withdrawValidator_validatorsManager'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_osTokenRedeemer() public { + // Set osToken redeemer + address osTokenRedeemer = makeAddr('osTokenRedeemer'); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + // Fund the redeemer account + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // Execute withdrawal as osTokenRedeemer + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(osTokenRedeemer); + _startSnapshotGas('GnoVaultTest_test_withdrawValidator_osTokenRedeemer'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_unknown() public { + // Create an unknown address + address unknown = makeAddr('unknown'); + + // Fund the unknown account + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // Execute withdrawal as an unknown address - should fail + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(unknown); + _startSnapshotGas('GnoVaultTest_test_withdrawValidator_unknown'); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } +} diff --git a/test/gnosis/GnoVault.upgrade.spec.ts b/test/gnosis/GnoVault.upgrade.spec.ts deleted file mode 100644 index 8e563b9b..00000000 --- a/test/gnosis/GnoVault.upgrade.spec.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - DepositDataRegistry, - GnoVault__factory, - GnoVaultFactory, - Keeper, - OsTokenConfig, - OsTokenVaultController, - SharedMevEscrow, - VaultsRegistry, - XdaiExchange, - ERC20Mock, -} from '../../typechain-types' -import snapshotGasCost from '../shared/snapshotGasCost' -import { - approveSecurityDeposit, - deployGnoVaultV2, - depositGno, - encodeGnoErc20VaultInitParams, - encodeGnoVaultInitParams, - gnoVaultFixture, -} from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { EXITING_ASSETS_MIN_DELAY, ZERO_ADDRESS } from '../shared/constants' -import { collateralizeGnoVault } from '../shared/gnoFixtures' -import { - getGnoBlocklistErc20VaultV2Factory, - getGnoBlocklistVaultV2Factory, - getGnoErc20VaultV2Factory, - getGnoGenesisVaultV2Factory, - getGnoPrivErc20VaultV2Factory, - getGnoPrivVaultV2Factory, - getGnoVaultV2Factory, -} from '../shared/contracts' -import { ThenArg } from '../../helpers/types' - -describe('GnoVault - upgrade', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7r' - let admin: Signer, dao: Wallet, other: Wallet - let vaultsRegistry: VaultsRegistry, - keeper: Keeper, - validatorsRegistry: Contract, - sharedMevEscrow: SharedMevEscrow, - osTokenConfig: OsTokenConfig, - osTokenVaultController: OsTokenVaultController, - depositDataRegistry: DepositDataRegistry, - xdaiExchange: XdaiExchange, - gnoToken: ERC20Mock, - gnoVaultFactory: GnoVaultFactory, - gnoPrivVaultFactory: GnoVaultFactory, - gnoBlocklistVaultFactory: GnoVaultFactory, - gnoErc20VaultFactory: GnoVaultFactory, - gnoPrivErc20VaultFactory: GnoVaultFactory, - gnoBlocklistErc20VaultFactory: GnoVaultFactory - let fixture: any - - let createGenesisVault: ThenArg>['createGnoGenesisVault'] - - beforeEach('deploy fixture', async () => { - ;[dao, admin, other] = await (ethers as any).getSigners() - fixture = await loadFixture(gnoVaultFixture) - vaultsRegistry = fixture.vaultsRegistry - validatorsRegistry = fixture.validatorsRegistry - keeper = fixture.keeper - sharedMevEscrow = fixture.sharedMevEscrow - osTokenVaultController = fixture.osTokenVaultController - depositDataRegistry = fixture.depositDataRegistry - gnoVaultFactory = fixture.gnoVaultFactory - gnoPrivVaultFactory = fixture.gnoPrivVaultFactory - gnoBlocklistVaultFactory = fixture.gnoBlocklistVaultFactory - gnoErc20VaultFactory = fixture.gnoErc20VaultFactory - gnoPrivErc20VaultFactory = fixture.gnoPrivErc20VaultFactory - gnoBlocklistErc20VaultFactory = fixture.gnoBlocklistErc20VaultFactory - createGenesisVault = fixture.createGnoGenesisVault - osTokenConfig = fixture.osTokenConfig - xdaiExchange = fixture.xdaiExchange - gnoToken = fixture.gnoToken - }) - - it('does not modify the state variables', async () => { - const vaults: Contract[] = [] - for (const factory of [ - await getGnoVaultV2Factory(), - await getGnoPrivVaultV2Factory(), - await getGnoBlocklistVaultV2Factory(), - ]) { - const vault = await deployGnoVaultV2( - factory, - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - encodeGnoVaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - }) - ) - vaults.push(vault) - } - for (const factory of [ - await getGnoErc20VaultV2Factory(), - await getGnoPrivErc20VaultV2Factory(), - await getGnoBlocklistErc20VaultV2Factory(), - ]) { - const vault = await deployGnoVaultV2( - factory, - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - encodeGnoErc20VaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - name: 'Vault', - symbol: 'VLT', - }) - ) - vaults.push(vault) - } - - const checkVault = async (vault: Contract, newImpl: string, isGenesis: boolean = false) => { - await collateralizeGnoVault( - vault, - gnoToken, - keeper, - depositDataRegistry, - admin, - validatorsRegistry - ) - await depositGno(vault, gnoToken, parseEther('3'), other, other, ZERO_ADDRESS) - await vault.connect(other).enterExitQueue(parseEther('1'), other.address) - await vault.connect(other).mintOsToken(other.address, parseEther('1'), ZERO_ADDRESS) - - const userShares = await vault.getShares(other.address) - const userAssets = await vault.convertToAssets(userShares) - const osTokenPosition = await vault.osTokenPositions(other.address) - const mevEscrow = await vault.mevEscrow() - const totalAssets = await vault.totalAssets() - const totalShares = await vault.totalShares() - const vaultAddress = await vault.getAddress() - expect(await vault.version()).to.be.eq(isGenesis ? 3 : 2) - - const receipt = await vault.connect(admin).upgradeToAndCall(newImpl, '0x') - const vaultV3 = GnoVault__factory.connect(vaultAddress, admin) - expect(await vaultV3.version()).to.be.eq(isGenesis ? 4 : 3) - expect(await vaultV3.implementation()).to.be.eq(newImpl) - expect(await vaultV3.getShares(other.address)).to.be.eq(userShares) - expect(await vaultV3.convertToAssets(userShares)).to.be.deep.eq(userAssets) - expect(await vaultV3.osTokenPositions(other.address)).to.be.above(osTokenPosition) - expect(await vaultV3.validatorsManager()).to.be.eq(await depositDataRegistry.getAddress()) - expect(await vaultV3.mevEscrow()).to.be.eq(mevEscrow) - expect(await vaultV3.totalAssets()).to.be.eq(totalAssets) - expect(await vaultV3.totalShares()).to.be.eq(totalShares) - await snapshotGasCost(receipt) - } - await checkVault(vaults[0], await gnoVaultFactory.implementation()) - await vaults[1].connect(admin).updateWhitelist(other.address, true) - await checkVault(vaults[1], await gnoPrivVaultFactory.implementation()) - await checkVault(vaults[2], await gnoBlocklistVaultFactory.implementation()) - - await checkVault(vaults[3], await gnoErc20VaultFactory.implementation()) - await vaults[4].connect(admin).updateWhitelist(other.address, true) - await checkVault(vaults[4], await gnoPrivErc20VaultFactory.implementation()) - await checkVault(vaults[5], await gnoBlocklistErc20VaultFactory.implementation()) - - const [v3GenesisVault, rewardGnoToken, poolEscrow] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - const factory = await getGnoGenesisVaultV2Factory() - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - await gnoToken.getAddress(), - await xdaiExchange.getAddress(), - await poolEscrow.getAddress(), - await rewardGnoToken.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const contract = await factory.deploy(...constructorArgs) - const genesisImpl = await contract.getAddress() - const genesisImplV3 = await v3GenesisVault.implementation() - await vaultsRegistry.addVaultImpl(genesisImpl) - - const proxyFactory = await ethers.getContractFactory('ERC1967Proxy') - const proxy = await proxyFactory.deploy(genesisImpl, '0x') - const proxyAddress = await proxy.getAddress() - const genesisVault = new Contract(proxyAddress, contract.interface, admin) - await rewardGnoToken.connect(dao).setVault(proxyAddress) - await poolEscrow.connect(dao).commitOwnershipTransfer(proxyAddress) - await approveSecurityDeposit(await genesisVault.getAddress(), gnoToken, admin) - await genesisVault.initialize( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [await admin.getAddress(), [capacity, feePercent, metadataIpfsHash]] - ) - ) - await genesisVault.acceptPoolEscrowOwnership() - await vaultsRegistry.addVault(proxyAddress) - await checkVault(genesisVault, genesisImplV3, true) - }) -}) diff --git a/test/gnosis/GnoVaultExitQueue.t.sol b/test/gnosis/GnoVaultExitQueue.t.sol new file mode 100644 index 00000000..13831b8b --- /dev/null +++ b/test/gnosis/GnoVaultExitQueue.t.sol @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test, console} from '../../lib/forge-std/src/Test.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; +import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; + +contract GnoVaultExitQueueTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoVault public vault; + + address public vaultAddr; + address public admin; + address public user1; + address public user2; + address public user3; + + uint256 public depositAmount = 10 ether; + uint256 public exitAmount = 5 ether; + + uint256 public user1InitialGno; + uint256 public user2InitialGno; + uint256 public user3InitialGno; + + uint256 public timestamp1; + uint256 public timestamp2; + uint256 public timestamp3; + uint256 public timestamp4; + + uint256 public positionTicket1; + uint256 public positionTicket2; + uint256 public positionTicket3; + uint256 public positionTicket4; + + function setUp() public { + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr('admin'); + user1 = makeAddr('user1'); + user2 = makeAddr('user2'); + user3 = makeAddr('user3'); + + // Fund accounts + _mintGnoToken(admin, 100 ether); + _mintGnoToken(user1, 100 ether); + _mintGnoToken(user2, 100 ether); + _mintGnoToken(user3, 100 ether); + + // Step 1: Create a v2 GNO vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + vaultAddr = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); + vault = GnoVault(payable(vaultAddr)); + } + + function testVaultV2ToV3ExitQueue() public { + // Verify initial vault version + assertEq(vault.version(), 2, 'Vault should be version 2'); + + // Collateralize the vault + _collateralizeGnoVault(vaultAddr); + + // Make deposits for users + uint256 depositShares = vault.convertToShares(depositAmount); + _depositToVault(vaultAddr, depositAmount, user1, user1); + _depositToVault(vaultAddr, depositAmount, user2, user2); + _depositToVault(vaultAddr, depositAmount, user3, user3); + + // remove deposited GNO token from the vault + uint256 withdrawableAssets = vault.withdrawableAssets(); + vm.prank(vaultAddr); + contracts.gnoToken.transfer(address(1), withdrawableAssets); + + // Verify initial shares + assertEq(vault.getShares(user1), depositShares, 'User1 initial shares incorrect'); + assertEq(vault.getShares(user2), depositShares, 'User2 initial shares incorrect'); + assertEq(vault.getShares(user3), depositShares, 'User3 initial shares incorrect'); + + // Record initial GNO balances + user1InitialGno = contracts.gnoToken.balanceOf(user1); + user2InitialGno = contracts.gnoToken.balanceOf(user2); + user3InitialGno = contracts.gnoToken.balanceOf(user3); + + // Step 2: Add 3 exit requests to the vault + uint256 exitShares = vault.convertToShares(exitAmount); + uint256 totalExitingAssetsBefore = vault.totalExitingAssets(); + + timestamp1 = vm.getBlockTimestamp(); + vm.prank(user1); + positionTicket1 = vault.enterExitQueue(exitShares, user1); + + timestamp2 = vm.getBlockTimestamp(); + vm.prank(user2); + positionTicket2 = vault.enterExitQueue(exitShares, user2); + + timestamp3 = vm.getBlockTimestamp(); + vm.prank(user3); + positionTicket3 = vault.enterExitQueue(exitShares, user3); + + // Verify exit requests are in the queue + assertEq( + vault.totalExitingAssets(), + totalExitingAssetsBefore + exitAmount * 3, + 'Exit requests not added to queue' + ); + + // Step 3: Make 1st and 2nd exit requests claimable + _mintGnoToken( + vaultAddr, + vault.convertToAssets(exitAmount * 2) // Just enough for 2 requests + ); + + // Update state to process exit requests (should process the first 2) + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vaultAddr, 0, 0); + vault.updateState(harvestParams); + + // Advance time to make exit requests claimable + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Verify first and second exit positions are claimable + int256 exitQueueIndex1 = vault.getExitQueueIndex(positionTicket1); + assertGt(exitQueueIndex1, -1, 'Exit queue index not found for position 1'); + (uint256 leftTickets1, , uint256 exitedAssets1) = vault.calculateExitedAssets( + user1, + positionTicket1, + timestamp1, + uint256(exitQueueIndex1) + ); + assertEq(leftTickets1, 0, 'Position 1 should be fully processed'); + assertGt(exitedAssets1, 0, 'Position 1 should have exited assets'); + + int256 exitQueueIndex2 = vault.getExitQueueIndex(positionTicket2); + assertGt(exitQueueIndex2, -1, 'Exit queue index not found for position 2'); + (uint256 leftTickets2, , uint256 exitedAssets2) = vault.calculateExitedAssets( + user2, + positionTicket2, + timestamp2, + uint256(exitQueueIndex2) + ); + assertEq(leftTickets2, 0, 'Position 2 should be fully processed'); + assertGt(exitedAssets2, 0, 'Position 2 should have exited assets'); + + // Verify third exit position is not yet claimable + int256 exitQueueIndex3 = vault.getExitQueueIndex(positionTicket3); + assertEq(exitQueueIndex3, -1, 'Exit queue index found for position 3'); + + // Step 4: Claim 2nd exit request + uint256 exitedAssets2Claimed = exitedAssets2; + vm.prank(user2); + _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position2_before_upgrade'); + vault.claimExitedAssets(positionTicket2, timestamp2, uint256(exitQueueIndex2)); + _stopSnapshotGas(); + + // Verify user2 received their GNO + uint256 user2GnoAfterClaim = contracts.gnoToken.balanceOf(user2); + assertEq( + user2GnoAfterClaim, + user2InitialGno + exitedAssets2Claimed, + 'User2 received incorrect amount of GNO tokens' + ); + + // Step 5: Upgrade vault to v3 + _upgradeVault(VaultType.GnoVault, vaultAddr); + + // Verify upgrade was successful + assertEq(vault.version(), 3, 'Vault not upgraded to v3'); + + // Step 6: Create another exit request + uint256 remainingShares = vault.getShares(user2); + uint256 remainingAssets = vault.convertToAssets(vault.getShares(user2)); + vm.prank(user2); + positionTicket4 = vault.enterExitQueue(remainingShares, user2); + timestamp4 = vm.getBlockTimestamp(); + + // Advance time to make exit requests claimable + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Step 7: Make all exit requests claimable + _mintGnoToken( + vaultAddr, + vault.convertToAssets(exitAmount * 2 + remainingAssets) // Enough for the rest + ); + + // Update state again to process all exit requests + harvestParams = _setGnoVaultReward(vaultAddr, 0, 0); + vault.updateState(harvestParams); + + // Step 8: Claim all exit requests + + // Claim 1st exit request (user1) + vm.prank(user1); + _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position1_after_upgrade'); + vault.claimExitedAssets(positionTicket1, timestamp1, uint256(exitQueueIndex1)); + _stopSnapshotGas(); + + // Verify user1 received their GNO + uint256 user1GnoAfterClaim = contracts.gnoToken.balanceOf(user1); + assertApproxEqAbs( + user1GnoAfterClaim, + user1InitialGno + exitedAssets1, + 1, + 'User1 received incorrect amount of GNO tokens' + ); + + // Claim 3rd exit request (user3) + // Re-get the index as it may have changed after upgrade + exitQueueIndex3 = vault.getExitQueueIndex(positionTicket3); + assertGt(exitQueueIndex3, -1, 'Exit queue index not found for position 3 after upgrade'); + + // Calculate exited assets for position 3 + (, , uint256 exitedAssets3) = vault.calculateExitedAssets( + user3, + positionTicket3, + timestamp3, + uint256(exitQueueIndex3) + ); + assertGt(exitedAssets3, 0, 'Position 3 should have exited assets after upgrade'); + + vm.prank(user3); + _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position3_after_upgrade'); + vault.claimExitedAssets(positionTicket3, timestamp3, uint256(exitQueueIndex3)); + _stopSnapshotGas(); + + // Verify user3 received their GNO + uint256 user3GnoAfterClaim = contracts.gnoToken.balanceOf(user3); + assertApproxEqAbs( + user3GnoAfterClaim, + user3InitialGno + exitedAssets3, + 1, + 'User3 received incorrect amount of GNO tokens' + ); + + // Claim 4th exit request (user2's second request) + int256 exitQueueIndex4 = vault.getExitQueueIndex(positionTicket4); + assertGt(exitQueueIndex4, -1, 'Exit queue index not found for position 4 after upgrade'); + + // Calculate exited assets for position 4 + (, , uint256 exitedAssets4) = vault.calculateExitedAssets( + user2, + positionTicket4, + timestamp4, + uint256(exitQueueIndex4) + ); + assertGt(exitedAssets4, 0, 'Position 4 should have exited assets'); + + vm.prank(user2); + _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position4_after_upgrade'); + vault.claimExitedAssets(positionTicket4, timestamp4, uint256(exitQueueIndex4)); + _stopSnapshotGas(); + + // Verify user2 received the rest of their GNO + uint256 user2GnoFinalClaim = contracts.gnoToken.balanceOf(user2); + assertApproxEqAbs( + user2GnoFinalClaim, + user2GnoAfterClaim + exitedAssets4, + 1, + 'User2 received incorrect amount of GNO tokens on final claim' + ); + + // Verify final share balances + assertEq( + vault.convertToAssets(vault.getShares(user1)), + depositAmount - exitAmount, + 'User1 assets incorrect' + ); + assertEq(vault.getShares(user2), 0, 'User2 should have 0 shares'); + assertEq( + vault.convertToAssets(vault.getShares(user3)), + depositAmount - exitAmount, + 'User3 assets incorrect' + ); + } + + function test_exitingAssetsPenalized() public { + _depositToVault(vaultAddr, depositAmount, user1, user1); + + // Enter half of the deposit into the exit queue + vm.prank(user1); + vault.enterExitQueue(exitAmount, user1); + + uint256 totalExitingAssetsBefore = vault.totalExitingAssets(); + + // Upgrade the vault to v3 + _upgradeVault(VaultType.GnoVault, vaultAddr); + + // Calculate what the penalty should be + int256 penalty = -1 ether; // 1 GNO worth of penalty + uint256 expectedPenalty = (uint256(-penalty) * uint256(vault.totalExitingAssets())) / + (uint256(vault.totalExitingAssets()) + uint256(vault.totalAssets())); + + // Set a negative reward (penalty) and update the vault state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vaultAddr, + int160(penalty), + 0 + ); + + // Expect the ExitingAssetsPenalized event with the correct penalty amount + vm.expectEmit(true, true, true, true); + emit IVaultState.ExitingAssetsPenalized(expectedPenalty); + + _startSnapshotGas('GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify the exiting assets were penalized + assertLt( + vault.totalExitingAssets(), + totalExitingAssetsBefore + exitAmount, + 'Exiting assets should be reduced by the penalty' + ); + } +} diff --git a/test/gnosis/VaultGnoStaking.t.sol b/test/gnosis/VaultGnoStaking.t.sol new file mode 100644 index 00000000..b2780b22 --- /dev/null +++ b/test/gnosis/VaultGnoStaking.t.sol @@ -0,0 +1,568 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; +import {IVaultValidators} from '../../contracts/interfaces/IVaultValidators.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; + +contract VaultGnoStakingTest is Test, GnoHelpers { + ForkContracts public contracts; + GnoVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + + uint256 public depositAmount = 1 ether; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr('sender'); + receiver = makeAddr('receiver'); + admin = makeAddr('admin'); + referrer = makeAddr('referrer'); + validatorsManager = makeAddr('validatorsManager'); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + vault = GnoVault(payable(vaultAddr)); + + // set validators manager + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + vm.deal(validatorsManager, 1 ether); + } + + function test_deposit() public { + // Initial balances + uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + uint256 vaultTotalSharesBefore = vault.totalShares(); + uint256 vaultTotalAssetsBefore = vault.totalAssets(); + + // Approve and deposit + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), depositAmount); + + _startSnapshotGas('VaultGnoStakingTest_test_deposit'); + uint256 shares = vault.deposit(depositAmount, receiver, referrer); + _stopSnapshotGas(); + + vm.stopPrank(); + + // Verify balances changed correctly + assertEq( + contracts.gnoToken.balanceOf(sender), + senderInitialBalance - depositAmount, + 'Sender balance should decrease' + ); + assertEq( + contracts.gnoToken.balanceOf(address(vault)), + vaultInitialBalance + depositAmount, + 'Vault balance should increase' + ); + + // Verify shares minted correctly + assertEq(vault.getShares(receiver), shares, 'Receiver should get correct shares'); + + uint256 expectedShares = vault.convertToShares(depositAmount); + assertApproxEqAbs( + shares, + expectedShares, + 1, + 'Shares should match the expected conversion rate' + ); + + // Verify totalAssets and totalShares updated + assertEq( + vault.totalAssets(), + vaultTotalAssetsBefore + depositAmount, + 'Total assets should increase' + ); + assertEq(vault.totalShares(), vaultTotalSharesBefore + shares, 'Total shares should increase'); + } + + function test_withdrawableAssets() public { + uint256 withdrawableBefore = vault.withdrawableAssets(); + + // Deposit some GNO + _depositGno(depositAmount, sender, receiver); + + // Check withdrawable assets + uint256 withdrawable = vault.withdrawableAssets(); + assertGe( + withdrawable, + withdrawableBefore + depositAmount, + 'Withdrawable assets should include deposited amount' + ); + } + + function test_processTotalAssetsDelta() public { + // Deposit GNO + _depositGno(depositAmount, sender, receiver); + + // Now simulate some xDAI balance that would trigger distribution + vm.deal(vault.mevEscrow(), 1 ether); + + // use the same conversion function as for GnoVault + uint256 vaultBalanceBefore = address(vault).balance; + uint256 expectedAddedSDai = IGnoVault(address(contracts.sdaiToken)).convertToShares( + vaultBalanceBefore + 1 ether + ); + + _collateralizeGnoVault(address(vault)); + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + address(vault), + 0, + 1 ether + ); + + uint256 distributorBalanceBefore = contracts.sdaiToken.balanceOf( + address(contracts.merkleDistributor) + ); + + // Update state which will trigger _processTotalAssetsDelta + _startSnapshotGas('VaultGnoStakingTest_test_processTotalAssetsDelta'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify sDAI was sent to the distributor + assertEq(address(vault).balance, 0, 'Vault should have no xDAI left'); + assertEq( + contracts.sdaiToken.balanceOf(address(contracts.merkleDistributor)), + distributorBalanceBefore + expectedAddedSDai, + 'Distributor should get sDAI' + ); + } + + function test_processTotalAssetsDelta_smallXdaiBalance() public { + // Deposit GNO + _depositGno(depositAmount, sender, sender); + + // Small xDAI amount (below 0.1 ETH threshold) + vm.deal(vault.mevEscrow(), 0.09 ether); + + // Process rewards + _collateralizeGnoVault(address(vault)); + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + address(vault), + 1 ether, + 0 + ); + + uint256 mevBalanceBefore = address(vault.mevEscrow()).balance; + + // Update state + _startSnapshotGas('VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance'); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify small xDAI balance wasn't processed (below 0.1 ETH threshold) + assertEq( + address(vault.mevEscrow()).balance, + mevBalanceBefore, + 'xDAI balance should remain unchanged' + ); + } + + function test_vaultAssets() public { + // Initial check + uint256 initialAssets = vault.totalAssets(); + uint256 senderDeposit = vault.convertToAssets(vault.queuedShares()) + + vault.totalExitingAssets() + + 1 ether; + + // Deposit GNO + _mintGnoToken(sender, senderDeposit); + _depositGno(senderDeposit, sender, receiver); + + // Check assets increased + assertEq( + vault.totalAssets(), + initialAssets + senderDeposit, + 'Total assets should increase by deposit amount' + ); + + // Simulate GNO in validator registry that's withdrawable + _setGnoWithdrawals(address(vault), 1 ether); + + // Since _vaultAssets is internal, we need to check a public function that uses it + uint256 withdrawableAfter = vault.withdrawableAssets(); + assertGe(withdrawableAfter, 1 ether, 'Withdrawable assets should include all assets'); + } + + function test_pullWithdrawals() public { + // 1. Deposit GNO + _depositGno(depositAmount, sender, sender); + + // 2. Register a validator + _registerGnoValidator(address(vault), 1 ether, true); + + // 3. Set up withdrawable GNO in the registry (simulate validator withdrawal) + uint256 withdrawalAmount = 2 ether; + _setGnoWithdrawals(address(vault), withdrawalAmount); + + // Verify the registry shows the correct withdrawable amount + assertEq( + contracts.validatorsRegistry.withdrawableAmount(address(vault)), + withdrawalAmount, + 'Withdrawal amount not set correctly' + ); + + // Record initial balances + uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + + // 4. Enter the exit queue with shares + uint256 shares = vault.getShares(sender); + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(sender); + uint256 positionTicket = vault.enterExitQueue(shares, sender); + + // 5. Process the exit queue + // Update vault state to process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Claim exited assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + _startSnapshotGas('VaultGnoStakingTest_test_pullWithdrawals'); + vm.prank(sender); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // 7. Verify results + // Sender should have received their GNO + uint256 senderFinalBalance = contracts.gnoToken.balanceOf(sender); + assertGt(senderFinalBalance, senderInitialBalance, 'Sender did not receive exited assets'); + + // Registry should have 0 withdrawable amount + uint256 registryFinalWithdrawable = contracts.validatorsRegistry.withdrawableAmount( + address(vault) + ); + assertEq( + registryFinalWithdrawable, + 0, + 'Registry withdrawable amount should be completely claimed' + ); + + // Vault's GNO balance should have changed due to _pullWithdrawals + uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); + // The vault should have transferred out GNO (either directly or via _pullWithdrawals) + assertLt( + vaultFinalBalance, + vaultInitialBalance + withdrawalAmount, + 'Vault balance should reflect withdrawals' + ); + } + + function test_registerValidators_pullsWithdrawals() public { + // Setup: Set GNO withdrawals in the validators registry + uint256 withdrawalAmount = 2 ether; + _setGnoWithdrawals(address(vault), withdrawalAmount); + uint256 withdrawableBefore = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + + // Get vault's GNO balance before registration + uint256 vaultGnoBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); + + // setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Register a validator - this should trigger a withdrawal claim + IKeeperValidators.ApprovalParams memory approvalParams = _getGnoValidatorApproval( + address(vault), + 1 ether, + 'ipfsHash', + false + ); + + vm.prank(validatorsManager); + vault.registerValidators(approvalParams, ''); + + // Verify that withdrawals were pulled by checking the vault's GNO balance increased + uint256 vaultGnoBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); + assertGe( + vaultGnoBalanceAfter, + vaultGnoBalanceBefore + withdrawableBefore - 1 ether, + 'Vault should have received withdrawals' + ); + + // Verify the withdrawable amount is now 0 + uint256 withdrawableAfter = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + assertEq(withdrawableAfter, 0, 'Withdrawable amount should be cleared after claiming'); + + // revert previous state + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_succeeds() public { + // Setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Test successful registration with 0x01 prefix + _depositGno(1 ether, sender, sender); + IKeeperValidators.ApprovalParams memory approvalParams = _getGnoValidatorApproval( + address(vault), + 1 ether, + 'ipfsHash', + true + ); + + vm.prank(validatorsManager); + _startSnapshotGas('test_registerValidators_succeeds_0x01'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // Test successful registration with 0x02 prefix and valid amount + _depositGno(64 ether, sender, sender); + approvalParams = _getGnoValidatorApproval(address(vault), 64 ether, 'ipfsHash', false); + + vm.prank(validatorsManager); + _startSnapshotGas('test_registerValidators_succeeds_0x02'); + vault.registerValidators(approvalParams, ''); + _stopSnapshotGas(); + + // revert previous state + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_receive_xDai() public { + // Send xDAI directly to the vault + uint256 sendAmount = 0.5 ether; + vm.deal(sender, sendAmount); + + uint256 balanceBefore = address(vault).balance; + + vm.prank(sender); + _startSnapshotGas('VaultGnoStakingTest_test_receive_xDai'); + (bool success, ) = address(vault).call{value: sendAmount}(''); + _stopSnapshotGas(); + + assertTrue(success, 'Failed to send xDAI to vault'); + assertEq( + address(vault).balance, + balanceBefore + sendAmount, + "Vault balance didn't increase correctly" + ); + } + + function test_validatorRegistration_minMaxEffectiveBalance() public { + // 1. Test registration with amount less than min effective balance (should fail) + uint256 tooSmallAmount = 0.5 ether; // Less than the min 1 GNO requirement + _depositGno(tooSmallAmount, sender, sender); + + // Setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Prepare registration with too small amount + IKeeperValidators.ApprovalParams memory approvalParams = _getGnoValidatorApproval( + address(vault), + tooSmallAmount, + 'ipfsHash', + false + ); + + // Should fail because amount is too small + vm.prank(validatorsManager); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.registerValidators(approvalParams, ''); + + // 2. Test registration with amount greater than max effective balance (should fail) + uint256 tooLargeAmount = 65 ether; // More than the max 64 GNO requirement + _depositGno(tooLargeAmount, sender, sender); + + // Prepare registration with too large amount + approvalParams = _getGnoValidatorApproval(address(vault), tooLargeAmount, 'ipfsHash', false); + + // Should fail because amount is too large + vm.prank(validatorsManager); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.registerValidators(approvalParams, ''); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidator_topUp() public { + // Deposit enough GNO for multiple validator registrations + _depositGno(10 ether, sender, sender); + + // Setup oracle for validator registration and top-up + _startOracleImpersonate(address(contracts.keeper)); + + // Step 1: Register a validator first to make it tracked + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // Step 2: Try to top up a non-existing validator (should fail) + bytes memory nonExistingPublicKey = vm.randomBytes(48); + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = (1 ether * 32) / 1 gwei; + bytes32 depositDataRoot = _getDepositDataRoot( + nonExistingPublicKey, + signature, + withdrawalCredentials, + topUpAmount + ); + + // Create top-up data for non-existing validator + bytes memory invalidTopUpData = bytes.concat( + nonExistingPublicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + vm.prank(validatorsManager); + _startSnapshotGas('VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid'); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(invalidTopUpData, ''); + _stopSnapshotGas(); + + // Step 3: Successfully top up the registered validator + // Create valid top-up data using the same public key as the registered validator + depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + bytes memory validTopUpData = bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(uint64(topUpAmount)) + ); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + vm.prank(validatorsManager); + _startSnapshotGas('VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid'); + vault.fundValidators(validTopUpData, ''); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_withdrawValidator_fullFlow() public { + // 1. First deposit and register a validator + _depositGno(10 ether, sender, sender); + _registerGnoValidator(address(vault), 1 ether, false); + + // 2. Ensure validator is tracked + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Fund the validators manager + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 4. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas('VaultGnoStakingTest_test_withdrawValidator_fullFlow'); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); + _stopSnapshotGas(); + } + + function test_transferVaultAssets() public { + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to the vault + uint256 senderDeposit = vault.convertToAssets(vault.queuedShares()) + + vault.totalExitingAssets() + + depositAmount; + _mintGnoToken(sender, senderDeposit); + _depositGno(senderDeposit, sender, sender); + + // Add some funds to test withdrawal + uint256 vaultBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); + uint256 receiverBalanceBefore = contracts.gnoToken.balanceOf(receiver); + + // Enter exit queue + uint256 withdrawalAmount = vault.convertToShares(depositAmount); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(withdrawalAmount, receiver); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + // Claim exited assets which will trigger _transferVaultAssets + vm.prank(receiver); + _startSnapshotGas('VaultGnoStakingTest_test_transferVaultAssets'); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify the transfer occurred + uint256 vaultBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); + uint256 receiverBalanceAfter = contracts.gnoToken.balanceOf(receiver); + + assertLt(vaultBalanceAfter, vaultBalanceBefore, 'Vault balance should decrease'); + assertGt(receiverBalanceAfter, receiverBalanceBefore, 'Receiver balance should increase'); + } + + function test_vaultGnoStaking_init() public { + // Create a vault that calls __VaultGnoStaking_init + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + + // To test creation and initialization + _startSnapshotGas('VaultGnoStakingTest_test_vaultGnoStaking_init'); + address newVaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); + _stopSnapshotGas(); + + GnoVault newVault = GnoVault(payable(newVaultAddr)); + + // Verify that initialization properly set up the vault + assertGt(newVault.totalShares(), 0, 'Vault should have initial shares for security deposit'); + assertGt(newVault.totalAssets(), 0, 'Vault should have initial assets for security deposit'); + + // Check initial GNO balance matches security deposit + uint256 securityDeposit = 1e9; // Same as defined in VaultGnoStaking + assertEq( + contracts.gnoToken.balanceOf(address(newVault)), + securityDeposit, + 'Incorrect security deposit' + ); + } + + // Helper functions + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } +} diff --git a/test/gnosis/XdaiExchange.spec.ts b/test/gnosis/XdaiExchange.spec.ts deleted file mode 100644 index eea7178b..00000000 --- a/test/gnosis/XdaiExchange.spec.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { ethers } from 'hardhat' -import { parseEther, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - XdaiExchange, - ERC20Mock, - BalancerVaultMock, - XdaiExchangeV2Mock, - XdaiExchangeV2Mock__factory, - PriceFeedMock, - VaultsRegistry, -} from '../../typechain-types' -import { gnoVaultFixture } from '../shared/gnoFixtures' -import { expect } from '../shared/expect' -import { - XDAI_EXCHANGE_MAX_SLIPPAGE, - XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA, - ZERO_BYTES32, -} from '../shared/constants' -import snapshotGasCost from '../shared/snapshotGasCost' -import { getLatestBlockTimestamp } from '../shared/utils' - -describe('XdaiExchange', () => { - let dao: Wallet, other: Wallet - let xdaiExchange: XdaiExchange, - gnoToken: ERC20Mock, - balancerVault: BalancerVaultMock, - gnoPriceFeed: PriceFeedMock, - daiPriceFeed: PriceFeedMock, - vaultsRegistry: VaultsRegistry - - beforeEach('deploy fixtures', async () => { - ;[dao, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(gnoVaultFixture) - xdaiExchange = fixture.xdaiExchange - gnoToken = fixture.gnoToken - balancerVault = fixture.balancerVault - vaultsRegistry = fixture.vaultsRegistry - gnoPriceFeed = fixture.gnoPriceFeed - daiPriceFeed = fixture.daiPriceFeed - }) - - it('cannot initialize twice', async () => { - await expect( - xdaiExchange - .connect(other) - .initialize( - other.address, - XDAI_EXCHANGE_MAX_SLIPPAGE, - XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA, - ZERO_BYTES32 - ) - ).to.be.revertedWithCustomError(xdaiExchange, 'InvalidInitialization') - expect(await xdaiExchange.owner()).to.eq(dao.address) - }) - - describe('max slippage', () => { - it('is set during deployment', async () => { - expect(await xdaiExchange.maxSlippage()).to.eq(XDAI_EXCHANGE_MAX_SLIPPAGE) - }) - - it('cannot be set by non-admin', async () => { - await expect(xdaiExchange.connect(other).setMaxSlippage(0)).to.be.revertedWithCustomError( - xdaiExchange, - 'OwnableUnauthorizedAccount' - ) - }) - - it('cannot be larger than 100.00', async () => { - await expect(xdaiExchange.connect(dao).setMaxSlippage(10001)).to.be.revertedWithCustomError( - xdaiExchange, - 'InvalidSlippage' - ) - }) - - it('can be set by the admin', async () => { - const tx = await xdaiExchange.connect(dao).setMaxSlippage(100) - await expect(tx).to.emit(xdaiExchange, 'MaxSlippageUpdated').withArgs(100) - expect(await xdaiExchange.maxSlippage()).to.eq(100) - await snapshotGasCost(tx) - }) - }) - - describe('stale price time delta', () => { - it('is set during deployment', async () => { - expect(await xdaiExchange.stalePriceTimeDelta()).to.eq(XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA) - }) - - it('cannot be set by non-admin', async () => { - await expect( - xdaiExchange.connect(other).setStalePriceTimeDelta(0) - ).to.be.revertedWithCustomError(xdaiExchange, 'OwnableUnauthorizedAccount') - }) - - it('can be set by the admin', async () => { - const tx = await xdaiExchange.connect(dao).setStalePriceTimeDelta(1) - await expect(tx).to.emit(xdaiExchange, 'StalePriceTimeDeltaUpdated').withArgs(1) - expect(await xdaiExchange.stalePriceTimeDelta()).to.eq(1) - await snapshotGasCost(tx) - }) - }) - - describe('balancer pool id', () => { - const poolId = '0xc5263ec0cf13b2a75c287991506f86fe917a6a467242bf57520d5d71a6e647f7' - - it('is set during deployment', async () => { - expect(await xdaiExchange.balancerPoolId()).to.eq(ZERO_BYTES32) - }) - - it('cannot be set by non-admin', async () => { - await expect( - xdaiExchange.connect(other).setBalancerPoolId(poolId) - ).to.be.revertedWithCustomError(xdaiExchange, 'OwnableUnauthorizedAccount') - }) - - it('can be set by the admin', async () => { - const tx = await xdaiExchange.connect(dao).setBalancerPoolId(poolId) - await expect(tx).to.emit(xdaiExchange, 'BalancerPoolIdUpdated').withArgs(poolId) - expect(await xdaiExchange.balancerPoolId()).to.eq(poolId) - await snapshotGasCost(tx) - }) - }) - - describe('upgrade', () => { - let newImpl: XdaiExchangeV2Mock - - beforeEach('deploy new implementation', async () => { - const factory = await ethers.getContractFactory('XdaiExchangeV2Mock') - const contract = await factory.deploy( - await gnoToken.getAddress(), - await balancerVault.getAddress(), - await vaultsRegistry.getAddress(), - await daiPriceFeed.getAddress(), - await gnoPriceFeed.getAddress() - ) - newImpl = XdaiExchangeV2Mock__factory.connect(await contract.getAddress(), dao) - }) - - it('fails to upgrade if not admin', async () => { - await expect( - xdaiExchange.connect(other).upgradeToAndCall(await newImpl.getAddress(), '0x') - ).revertedWithCustomError(xdaiExchange, 'OwnableUnauthorizedAccount') - }) - - it('upgrades', async () => { - const tx = await xdaiExchange.connect(dao).upgradeToAndCall(await newImpl.getAddress(), '0x') - await expect(tx).to.emit(xdaiExchange, 'Upgraded') - const xdaiExchangeMock = XdaiExchangeV2Mock__factory.connect( - await xdaiExchange.getAddress(), - dao - ) - expect(await xdaiExchangeMock.newVar()).to.eq(0) - await snapshotGasCost(tx) - }) - }) - - describe('swap', () => { - const value = parseEther('1') - - beforeEach(async () => { - const currentTimestamp = await getLatestBlockTimestamp() - await daiPriceFeed.setLatestTimestamp(currentTimestamp) - await gnoPriceFeed.setLatestTimestamp(currentTimestamp) - }) - - it('fails for not vault', async () => { - await expect( - xdaiExchange.connect(other).swap({ - value, - }) - ).to.be.revertedWithCustomError(xdaiExchange, 'AccessDenied') - }) - - it('fails with zero amount', async () => { - await expect(xdaiExchange.connect(dao).swap()).to.be.revertedWithCustomError( - xdaiExchange, - 'InvalidAssets' - ) - }) - - it('fails with zero DAI price feed answer', async () => { - await vaultsRegistry.connect(dao).addVault(dao.address) - await daiPriceFeed.connect(dao).setLatestAnswer(0) - await expect( - xdaiExchange.connect(dao).swap({ - value, - }) - ).to.be.revertedWithCustomError(xdaiExchange, 'PriceFeedError') - }) - - it('fails with stale DAI price feed answer', async () => { - await vaultsRegistry.connect(dao).addVault(dao.address) - const currentTimestamp = await getLatestBlockTimestamp() - await daiPriceFeed - .connect(dao) - .setLatestTimestamp(currentTimestamp - XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA - 1) - await expect( - xdaiExchange.connect(dao).swap({ - value, - }) - ).to.be.revertedWithCustomError(xdaiExchange, 'PriceFeedError') - }) - - it('fails with zero GNO price feed answer', async () => { - await vaultsRegistry.connect(dao).addVault(dao.address) - await gnoPriceFeed.connect(dao).setLatestAnswer(0) - await expect( - xdaiExchange.connect(dao).swap({ - value, - }) - ).to.be.revertedWithCustomError(xdaiExchange, 'PriceFeedError') - }) - - it('fails with stale price feed answer', async () => { - await vaultsRegistry.connect(dao).addVault(dao.address) - const currentTimestamp = await getLatestBlockTimestamp() - await gnoPriceFeed - .connect(dao) - .setLatestTimestamp(currentTimestamp - XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA - 1) - await expect( - xdaiExchange.connect(dao).swap({ - value, - }) - ).to.be.revertedWithCustomError(xdaiExchange, 'PriceFeedError') - }) - - it('successfully swaps', async () => { - await vaultsRegistry.connect(dao).addVault(dao.address) - const receipt = await gnoToken - .connect(dao) - .mint(await balancerVault.getAddress(), parseEther('100')) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/helpers/EthHelpers.sol b/test/helpers/EthHelpers.sol new file mode 100644 index 00000000..9699a447 --- /dev/null +++ b/test/helpers/EthHelpers.sol @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; +import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; +import {IOsTokenVaultController} from '../../contracts/interfaces/IOsTokenVaultController.sol'; +import {IOsTokenVaultEscrow} from '../../contracts/interfaces/IOsTokenVaultEscrow.sol'; +import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; +import {IEthValidatorsRegistry} from '../../contracts/interfaces/IEthValidatorsRegistry.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; +import {IConsolidationsChecker} from '../../contracts/interfaces/IConsolidationsChecker.sol'; +import {ConsolidationsChecker} from '../../contracts/validators/ConsolidationsChecker.sol'; +import {EthBlocklistErc20Vault} from '../../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; +import {EthBlocklistVault} from '../../contracts/vaults/ethereum/EthBlocklistVault.sol'; +import {EthErc20Vault, IEthErc20Vault} from '../../contracts/vaults/ethereum/EthErc20Vault.sol'; +import {EthGenesisVault} from '../../contracts/vaults/ethereum/EthGenesisVault.sol'; +import {EthPrivErc20Vault} from '../../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; +import {EthPrivVault} from '../../contracts/vaults/ethereum/EthPrivVault.sol'; +import {EthVault, IEthVault} from '../../contracts/vaults/ethereum/EthVault.sol'; +import {EthVaultFactory} from '../../contracts/vaults/ethereum/EthVaultFactory.sol'; +import {EthFoxVault} from '../../contracts/vaults/ethereum/custom/EthFoxVault.sol'; +import {Keeper} from '../../contracts/keeper/Keeper.sol'; +import {ValidatorsConsolidationsMock} from '../../contracts/mocks/ValidatorsConsolidationsMock.sol'; +import {ValidatorsHelpers} from './ValidatorsHelpers.sol'; +import {ValidatorsWithdrawalsMock} from '../../contracts/mocks/ValidatorsWithdrawalsMock.sol'; +import {VaultsRegistry, IVaultsRegistry} from '../../contracts/vaults/VaultsRegistry.sol'; + +abstract contract EthHelpers is Test, ValidatorsHelpers { + uint256 internal constant forkBlockNumber = 22100000; + uint256 internal constant _securityDeposit = 1e9; + address private constant _keeper = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; + address private constant _validatorsRegistry = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + address private constant _vaultsRegistry = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; + address internal constant _osToken = 0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38; + address internal constant _osTokenFlashLoans = 0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2; + address private constant _osTokenVaultController = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; + address private constant _osTokenConfig = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; + address private constant _osTokenVaultEscrow = 0x09e84205DF7c68907e619D07aFD90143c5763605; + address private constant _sharedMevEscrow = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; + address internal constant _depositDataRegistry = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; + address internal constant _poolEscrow = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; + address internal constant _rewardEthToken = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; + uint256 internal constant _exitingAssetsClaimDelay = 1 days; + + enum VaultType { + EthVault, + EthBlocklistVault, + EthPrivVault, + EthGenesisVault, + EthErc20Vault, + EthBlocklistErc20Vault, + EthPrivErc20Vault, + EthFoxVault + } + + struct ForkContracts { + Keeper keeper; + IEthValidatorsRegistry validatorsRegistry; + VaultsRegistry vaultsRegistry; + IOsTokenVaultController osTokenVaultController; + IOsTokenConfig osTokenConfig; + IOsTokenVaultEscrow osTokenVaultEscrow; + ISharedMevEscrow sharedMevEscrow; + IConsolidationsChecker consolidationsChecker; + } + + mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; + mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; + mapping(VaultType vaultType => address vaultFactory) private _vaultPrevFactories; + + address internal _consolidationsChecker; + address internal _validatorsWithdrawals; + address internal _validatorsConsolidations; + + function _activateEthereumFork() internal returns (ForkContracts memory) { + vm.createSelectFork(vm.envString('MAINNET_RPC_URL'), forkBlockNumber); + + _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); + _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); + _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); + + return + ForkContracts({ + keeper: Keeper(_keeper), + validatorsRegistry: IEthValidatorsRegistry(_validatorsRegistry), + vaultsRegistry: VaultsRegistry(_vaultsRegistry), + osTokenVaultController: IOsTokenVaultController(_osTokenVaultController), + osTokenConfig: IOsTokenConfig(_osTokenConfig), + osTokenVaultEscrow: IOsTokenVaultEscrow(_osTokenVaultEscrow), + sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), + consolidationsChecker: IConsolidationsChecker(_consolidationsChecker) + }); + } + + function _getOrCreateVault( + VaultType vaultType, + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address vault) { + vault = _getForkVault(vaultType); + if (vault != address(0)) { + _upgradeVault(vaultType, vault); + if (Keeper(_keeper).isHarvestRequired(vault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(vault, 0, 0); + IVaultState(vault).updateState(harvestParams); + } + } else { + vault = _createVault(vaultType, admin, initParams, isOwnMevEscrow); + } + + address currentAdmin = IEthVault(vault).admin(); + if (currentAdmin != admin) { + vm.prank(currentAdmin); + IEthVault(vault).setAdmin(admin); + } + } + + function _getOrCreateFactory(VaultType _vaultType) internal returns (EthVaultFactory) { + if (_vaultFactories[_vaultType] != address(0)) { + return EthVaultFactory(_vaultFactories[_vaultType]); + } + + address impl = _getOrCreateVaultImpl(_vaultType); + EthVaultFactory factory = new EthVaultFactory(impl, IVaultsRegistry(_vaultsRegistry)); + + _vaultFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; + } + + function _getPrevVersionVaultFactory(VaultType _vaultType) internal returns (EthVaultFactory) { + if (_vaultPrevFactories[_vaultType] != address(0)) { + return EthVaultFactory(_vaultPrevFactories[_vaultType]); + } + + // Return actual contract addresses of previous factory versions if needed + address impl; + if (_vaultType == VaultType.EthVault) { + impl = 0xDecb606ee9140f229Df78F9E40041EAD61610F8f; + } else if (_vaultType == VaultType.EthPrivVault) { + impl = 0x135f45e0179dd928E73422B40Bdc6C5d7047a035; + } else if (_vaultType == VaultType.EthBlocklistVault) { + impl = 0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478; + } else if (_vaultType == VaultType.EthErc20Vault) { + impl = 0x7E5198DF09fED891e7AecD623cD2231443cEb5d5; + } else if (_vaultType == VaultType.EthPrivErc20Vault) { + impl = 0x9488A7dd178F0D927707eEc61A7D8C0ae9558c88; + } else if (_vaultType == VaultType.EthBlocklistErc20Vault) { + impl = 0x84d44A696539B3eF4162184fb8ab97596A311e9E; + } else { + return EthVaultFactory(address(0)); + } + + EthVaultFactory factory = new EthVaultFactory(impl, IVaultsRegistry(_vaultsRegistry)); + _vaultPrevFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; + } + + function _depositToVault(address vault, uint256 amount, address from, address to) internal { + vm.prank(from); + IEthVault(vault).deposit{value: amount}(to, address(0)); + } + + function _collateralizeEthVault(address vault) internal { + _collateralizeVault(_keeper, _validatorsRegistry, vault); + } + + function _mintOsToken(address user, uint256 amount) internal { + vm.prank(_getForkVault(VaultType.EthGenesisVault)); + IOsTokenVaultController(_osTokenVaultController).mintShares(user, amount); + } + + function _setEthVaultReward( + address vault, + int160 totalReward, + uint160 unlockedMevReward + ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { + (totalReward, unlockedMevReward) = _getVaultRewards(vault, totalReward, unlockedMevReward); + SetVaultRewardParams memory params = SetVaultRewardParams({ + keeper: _keeper, + osTokenCtrl: _osTokenVaultController, + vault: vault, + totalReward: totalReward, + unlockedMevReward: unlockedMevReward + }); + return _setVaultReward(params); + } + + function _registerEthValidator( + address vault, + uint256 depositAmount, + bool isV1Validator + ) internal returns (bytes memory publicKey) { + return _registerValidator(_keeper, _validatorsRegistry, vault, depositAmount, isV1Validator); + } + + function _getEthValidatorApproval( + address vault, + uint256 depositAmount, + string memory ipfsHash, + bool isV1Validator + ) internal view returns (IKeeperValidators.ApprovalParams memory harvestParams) { + uint256[] memory deposits = new uint256[](1); + deposits[0] = depositAmount / 1 gwei; + + harvestParams = _getValidatorsApproval( + _keeper, + _validatorsRegistry, + vault, + ipfsHash, + deposits, + isV1Validator + ); + } + + function _startSnapshotGas(string memory label) internal { + if (vm.envBool('USE_FORK_VAULTS')) return; + return vm.startSnapshotGas(label); + } + + function _stopSnapshotGas() internal { + if (vm.envBool('USE_FORK_VAULTS')) return; + vm.stopSnapshotGas(); + } + + function _getForkVault(VaultType vaultType) internal view returns (address) { + if (vaultType == VaultType.EthGenesisVault) { + return 0xAC0F906E433d58FA868F936E8A43230473652885; + } else if (vaultType == VaultType.EthFoxVault) { + return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; + } + + if (!vm.envBool('USE_FORK_VAULTS')) return address(0); + + // Update with actual deployed vault addresses for each type + if (vaultType == VaultType.EthVault) { + return 0x8A93A876912c9F03F88Bc9114847cf5b63c89f56; + } else if (vaultType == VaultType.EthPrivVault) { + return 0xD66A71A68392767F26b7EE47e9a0293191A23072; + } else if (vaultType == VaultType.EthErc20Vault) { + return 0x7106FA765d45dF6d5340972C58742fC54f0d1Ef9; + } else if (vaultType == VaultType.EthPrivErc20Vault) { + return 0xFB22Ded2bd69aff0907e195F23E448aB44E3cA97; + } else if (vaultType == VaultType.EthFoxVault) { + return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; + } + return address(0); + } + + function _getVaultRewards( + address vault, + int160 newTotalReward, + uint160 newUnlockedMevReward + ) private view returns (int160, uint160) { + // Update with actual values if needed for specific vaults + if (vault == 0xAC0F906E433d58FA868F936E8A43230473652885) { + // Genesis Vault + newTotalReward += 11492988394536925432019; + newUnlockedMevReward += 588134256533622872486; + } else if (vault == 0x4FEF9D741011476750A243aC70b9789a63dd47Df) { + newTotalReward += 242948554351000000000; + } + + if (!vm.envBool('USE_FORK_VAULTS')) { + return (newTotalReward, newUnlockedMevReward); + } + + // Add specific rewards for each vault type + if (vault == 0x8A93A876912c9F03F88Bc9114847cf5b63c89f56) { + newTotalReward += 39158842473943927643; + newUnlockedMevReward += 6210915181493109989; + } else if (vault == 0xD66A71A68392767F26b7EE47e9a0293191A23072) { + newTotalReward += 17651468000000000; + } + + return (newTotalReward, newUnlockedMevReward); + } + + function _createVault( + VaultType vaultType, + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address) { + EthVaultFactory factory = _getOrCreateFactory(vaultType); + + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + + return vaultAddress; + } + + function _createPrevVersionVault( + VaultType vaultType, + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address) { + EthVaultFactory factory = _getPrevVersionVaultFactory(vaultType); + + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + + return vaultAddress; + } + + function _createV1EthVault( + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address) { + EthVaultFactory factory = EthVaultFactory(0xDada5a8E3703B1e3EA2bAe5Ab704627eb2659fCC); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + + return vaultAddress; + } + + function _upgradeVault(VaultType vaultType, address vault) internal { + EthVault vaultContract = EthVault(payable(vault)); + uint256 currentVersion = vaultContract.version(); + + if (vaultType == VaultType.EthFoxVault) { + if (currentVersion == 2) return; + require(currentVersion == 1, 'Invalid vault version'); + } else { + if (currentVersion == 5) return; + require(currentVersion == 4, 'Invalid vault version'); + } + + address newImpl = _getOrCreateVaultImpl(vaultType); + address admin = vaultContract.admin(); + + vm.deal(admin, admin.balance + 1 ether); + vm.prank(admin); + vaultContract.upgradeToAndCall(newImpl, '0x'); + } + + function _getOrCreateVaultImpl(VaultType _vaultType) internal returns (address impl) { + if (_vaultImplementations[_vaultType] != address(0)) { + return _vaultImplementations[_vaultType]; + } + + IEthVault.EthVaultConstructorArgs memory ethArgs = IEthVault.EthVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + IEthErc20Vault.EthErc20VaultConstructorArgs memory ethErc20Args = IEthErc20Vault + .EthErc20VaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + if (_vaultType == VaultType.EthVault) { + impl = address(new EthVault(ethArgs)); + } else if (_vaultType == VaultType.EthBlocklistVault) { + impl = address(new EthBlocklistVault(ethArgs)); + } else if (_vaultType == VaultType.EthPrivVault) { + impl = address(new EthPrivVault(ethArgs)); + } else if (_vaultType == VaultType.EthGenesisVault) { + impl = address(new EthGenesisVault(ethArgs, _poolEscrow, _rewardEthToken)); + } else if (_vaultType == VaultType.EthErc20Vault) { + impl = address(new EthErc20Vault(ethErc20Args)); + } else if (_vaultType == VaultType.EthBlocklistErc20Vault) { + impl = address(new EthBlocklistErc20Vault(ethErc20Args)); + } else if (_vaultType == VaultType.EthPrivErc20Vault) { + impl = address(new EthPrivErc20Vault(ethErc20Args)); + } else if (_vaultType == VaultType.EthFoxVault) { + impl = address( + new EthFoxVault( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _sharedMevEscrow, + _depositDataRegistry, + _exitingAssetsClaimDelay + ) + ); + } + + _vaultImplementations[_vaultType] = impl; + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addVaultImpl(impl); + + return impl; + } +} diff --git a/test/helpers/GnoHelpers.sol b/test/helpers/GnoHelpers.sol new file mode 100644 index 00000000..2f66d87b --- /dev/null +++ b/test/helpers/GnoHelpers.sol @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; +import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; +import {IOsTokenVaultController} from '../../contracts/interfaces/IOsTokenVaultController.sol'; +import {IOsTokenVaultEscrow} from '../../contracts/interfaces/IOsTokenVaultEscrow.sol'; +import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; +import {IGnoValidatorsRegistry} from '../../contracts/interfaces/IGnoValidatorsRegistry.sol'; +import {IMerkleDistributor} from '../../contracts/interfaces/IMerkleDistributor.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; +import {IConsolidationsChecker} from '../../contracts/interfaces/IConsolidationsChecker.sol'; +import {GnoDaiDistributor, IGnoDaiDistributor} from '../../contracts/misc/GnoDaiDistributor.sol'; +import {ConsolidationsChecker} from '../../contracts/validators/ConsolidationsChecker.sol'; +import {GnoBlocklistErc20Vault} from '../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol'; +import {GnoBlocklistVault} from '../../contracts/vaults/gnosis/GnoBlocklistVault.sol'; +import {GnoErc20Vault, IGnoErc20Vault} from '../../contracts/vaults/gnosis/GnoErc20Vault.sol'; +import {GnoGenesisVault} from '../../contracts/vaults/gnosis/GnoGenesisVault.sol'; +import {GnoPrivErc20Vault} from '../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol'; +import {GnoPrivVault} from '../../contracts/vaults/gnosis/GnoPrivVault.sol'; +import {GnoVault, IGnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; +import {GnoVaultFactory} from '../../contracts/vaults/gnosis/GnoVaultFactory.sol'; +import {Keeper} from '../../contracts/keeper/Keeper.sol'; +import {ValidatorsConsolidationsMock} from '../../contracts/mocks/ValidatorsConsolidationsMock.sol'; +import {ValidatorsHelpers} from './ValidatorsHelpers.sol'; +import {ValidatorsWithdrawalsMock} from '../../contracts/mocks/ValidatorsWithdrawalsMock.sol'; +import {VaultsRegistry, IVaultsRegistry} from '../../contracts/vaults/VaultsRegistry.sol'; + +interface IGnoToken { + function mint(address _to, uint256 _amount) external returns (bool); + function owner() external view returns (address); +} + +abstract contract GnoHelpers is Test, ValidatorsHelpers { + uint256 internal constant forkBlockNumber = 39014183; + uint256 internal constant _securityDeposit = 1e9; + address private constant _keeper = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; + address private constant _validatorsRegistry = 0x0B98057eA310F4d31F2a452B414647007d1645d9; + address private constant _vaultsRegistry = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; + address private constant _osTokenVaultController = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; + address private constant _osTokenConfig = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; + address private constant _osTokenVaultEscrow = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; + address private constant _sharedMevEscrow = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; + address internal constant _depositDataRegistry = 0x58e16621B5c0786D6667D2d54E28A20940269E16; + address private constant _gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; + address internal constant _poolEscrow = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; + address internal constant _rewardGnoToken = 0x6aC78efae880282396a335CA2F79863A1e6831D4; + address private constant _merkleDistributor = 0xFBceefdBB0ca25a4043b35EF49C2810425243710; + address private constant _savingsXDaiAdapter = 0xD499b51fcFc66bd31248ef4b28d656d67E591A94; + address private constant _sDaiToken = 0xaf204776c7245bF4147c2612BF6e5972Ee483701; + uint256 internal constant _exitingAssetsClaimDelay = 1 days; + + enum VaultType { + GnoVault, + GnoBlocklistVault, + GnoPrivVault, + GnoGenesisVault, + GnoErc20Vault, + GnoBlocklistErc20Vault, + GnoPrivErc20Vault + } + + struct ForkContracts { + Keeper keeper; + IGnoValidatorsRegistry validatorsRegistry; + VaultsRegistry vaultsRegistry; + IOsTokenVaultController osTokenVaultController; + IOsTokenConfig osTokenConfig; + IOsTokenVaultEscrow osTokenVaultEscrow; + ISharedMevEscrow sharedMevEscrow; + IERC20 gnoToken; + IERC20 sdaiToken; + IConsolidationsChecker consolidationsChecker; + IGnoDaiDistributor gnoDaiDistributor; + IMerkleDistributor merkleDistributor; + } + + mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; + mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; + + address private _gnoDaiDistributor; + address private _consolidationsChecker; + address private _validatorsWithdrawals; + address private _validatorsConsolidations; + + function _activateGnosisFork() internal returns (ForkContracts memory) { + vm.createSelectFork(vm.envString('GNOSIS_RPC_URL'), forkBlockNumber); + + _gnoDaiDistributor = address( + new GnoDaiDistributor(_sDaiToken, _vaultsRegistry, _savingsXDaiAdapter, _merkleDistributor) + ); + _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); + _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); + _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); + + vm.prank(IMerkleDistributor(_merkleDistributor).owner()); + IMerkleDistributor(_merkleDistributor).setDistributor(_gnoDaiDistributor, true); + return + ForkContracts({ + keeper: Keeper(_keeper), + validatorsRegistry: IGnoValidatorsRegistry(_validatorsRegistry), + vaultsRegistry: VaultsRegistry(_vaultsRegistry), + osTokenVaultController: IOsTokenVaultController(_osTokenVaultController), + osTokenConfig: IOsTokenConfig(_osTokenConfig), + osTokenVaultEscrow: IOsTokenVaultEscrow(_osTokenVaultEscrow), + sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), + gnoToken: IERC20(_gnoToken), + sdaiToken: IERC20(_sDaiToken), + consolidationsChecker: IConsolidationsChecker(_consolidationsChecker), + gnoDaiDistributor: IGnoDaiDistributor(_gnoDaiDistributor), + merkleDistributor: IMerkleDistributor(_merkleDistributor) + }); + } + + function _mintGnoToken(address to, uint256 amount) internal { + vm.prank(IGnoToken(_gnoToken).owner()); + IGnoToken(_gnoToken).mint(to, amount); + } + + function _depositToVault(address vault, uint256 amount, address from, address to) internal { + vm.startPrank(from); + IERC20(_gnoToken).approve(vault, amount); + IGnoVault(vault).deposit(amount, to, address(0)); + vm.stopPrank(); + } + + function _collateralizeGnoVault(address vault) internal { + _collateralizeVault(_keeper, _validatorsRegistry, vault); + } + + function _setGnoVaultReward( + address vault, + int160 totalReward, + uint160 unlockedMevReward + ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { + (totalReward, unlockedMevReward) = _getVaultRewards(vault, totalReward, unlockedMevReward); + SetVaultRewardParams memory params = SetVaultRewardParams({ + keeper: _keeper, + osTokenCtrl: _osTokenVaultController, + vault: vault, + totalReward: totalReward, + unlockedMevReward: unlockedMevReward + }); + return _setVaultReward(params); + } + + function _registerGnoValidator( + address vault, + uint256 depositAmount, + bool isV1Validator + ) internal returns (bytes memory publicKey) { + // multiply by 32 to convert GNO to mGNO + return + _registerValidator(_keeper, _validatorsRegistry, vault, depositAmount * 32, isV1Validator); + } + + function _getGnoValidatorApproval( + address vault, + uint256 depositAmount, + string memory ipfsHash, + bool isV1Validator + ) internal view returns (IKeeperValidators.ApprovalParams memory harvestParams) { + uint256[] memory deposits = new uint256[](1); + deposits[0] = (depositAmount * 32) / 1 gwei; + + harvestParams = _getValidatorsApproval( + _keeper, + _validatorsRegistry, + vault, + ipfsHash, + deposits, + isV1Validator + ); + } + + function _getOrCreateVault( + VaultType vaultType, + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address vault) { + vault = _getForkVault(vaultType); + if (vault != address(0)) { + _upgradeVault(vaultType, vault); + if (Keeper(_keeper).isHarvestRequired(vault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, 0, 0); + IVaultState(vault).updateState(harvestParams); + } + } else { + vault = _createVault(vaultType, admin, initParams, isOwnMevEscrow); + } + + address currentAdmin = IGnoVault(vault).admin(); + if (currentAdmin != admin) { + vm.prank(currentAdmin); + IGnoVault(vault).setAdmin(admin); + } + } + + function _getOrCreateFactory(VaultType _vaultType) internal returns (GnoVaultFactory) { + if (_vaultFactories[_vaultType] != address(0)) { + return GnoVaultFactory(_vaultFactories[_vaultType]); + } + + address impl = _getOrCreateVaultImpl(_vaultType); + GnoVaultFactory factory = new GnoVaultFactory( + impl, + IVaultsRegistry(_vaultsRegistry), + _gnoToken + ); + + _vaultFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; + } + + function _getPrevVersionVaultFactory( + VaultType _vaultType + ) internal pure returns (GnoVaultFactory) { + if (_vaultType == VaultType.GnoVault) { + return GnoVaultFactory(0xC2ecc7620416bd65bfab7010B0db955a0e49579a); + } else if (_vaultType == VaultType.GnoPrivVault) { + return GnoVaultFactory(0x574952EC88b2fC271d0C0dB130794c86Ea42139A); + } else if (_vaultType == VaultType.GnoBlocklistVault) { + return GnoVaultFactory(0x78FbfBd1DD38892476Ac469325df36604A27F5B7); + } else if (_vaultType == VaultType.GnoErc20Vault) { + return GnoVaultFactory(0xF6BBBc05536Ab198d4b7Ab74a93f8e2d4cAd5354); + } else if (_vaultType == VaultType.GnoPrivErc20Vault) { + return GnoVaultFactory(0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86); + } + return GnoVaultFactory(0x99E4300326867FE3f97864a74e500d19654c19e9); + } + + function _setGnoWithdrawals(address vault, uint256 amount) internal { + // Mint GNO to the validators registry + _mintGnoToken(_validatorsRegistry, amount); + + // Access the system address to execute withdrawals + address systemAddr = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; + vm.deal(systemAddr, 1 ether); + + // Calculate the call amount + uint64 callAmount = uint64((amount * 32) / 1 gwei); + + uint64[] memory amounts = new uint64[](1); + amounts[0] = callAmount; + + address[] memory addresses = new address[](1); + addresses[0] = address(vault); + + // Execute system withdrawals as the system account + vm.startPrank(systemAddr); + // Call the executor function - this may need to be adjusted based on the registry implementation + (bool success, ) = _validatorsRegistry.call( + abi.encodeWithSignature('executeSystemWithdrawals(uint64[],address[])', amounts, addresses) + ); + vm.stopPrank(); + + // Ensure the call was successful + require(success, 'Setting GNO withdrawals failed'); + } + + function _startSnapshotGas(string memory label) internal { + if (vm.envBool('USE_FORK_VAULTS')) return; + return vm.startSnapshotGas(label); + } + + function _stopSnapshotGas() internal { + if (vm.envBool('USE_FORK_VAULTS')) return; + vm.stopSnapshotGas(); + } + + function _getForkVault(VaultType vaultType) internal view returns (address) { + if (vaultType == VaultType.GnoGenesisVault) { + return 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a; + } + + if (!vm.envBool('USE_FORK_VAULTS')) return address(0); + + if (vaultType == VaultType.GnoVault) { + return 0x00025C729A3364FaEf02c7D1F577068d87E90ba6; + } else if (vaultType == VaultType.GnoBlocklistVault) { + return 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC; + } else if (vaultType == VaultType.GnoPrivVault) { + return 0x52Bd0fbF4839824680001d3653f2d503C6081085; + } else if (vaultType == VaultType.GnoErc20Vault) { + return 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD; + } else if (vaultType == VaultType.GnoPrivErc20Vault) { + return 0xdfdA4238359703180DAEc01e48F4625C1569c4dE; + } + return address(0); + } + + function _getVaultRewards( + address vault, + int160 newTotalReward, + uint160 newUnlockedMevReward + ) private view returns (int160, uint160) { + if (vault == 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a) { + newTotalReward += 14465786742141121046698; + newUnlockedMevReward += 12291679027502580216003; + } + + if (!vm.envBool('USE_FORK_VAULTS')) { + return (newTotalReward, newUnlockedMevReward); + } + + if (vault == 0x00025C729A3364FaEf02c7D1F577068d87E90ba6) { + newTotalReward += 393962803328781250000; + newUnlockedMevReward += 1680633820544574435947; + } else if (vault == 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC) { + newTotalReward += 1050592958531250000; + newUnlockedMevReward += 3442955231281615690; + } else if (vault == 0x52Bd0fbF4839824680001d3653f2d503C6081085) { + newTotalReward += 32023359208750000000; + } else if (vault == 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD) { + newTotalReward += 93551557523312500000; + newUnlockedMevReward += 199880304782632057829; + } else if (vault == 0xdfdA4238359703180DAEc01e48F4625C1569c4dE) { + newTotalReward += 5690635875000000; + } + return (newTotalReward, newUnlockedMevReward); + } + + function _createVault( + VaultType vaultType, + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address) { + GnoVaultFactory factory = _getOrCreateFactory(vaultType); + + vm.startPrank(admin); + IERC20(_gnoToken).approve(address(factory), _securityDeposit); + address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); + vm.stopPrank(); + + return vaultAddress; + } + + function _createPrevVersionVault( + VaultType vaultType, + address admin, + bytes memory initParams, + bool isOwnMevEscrow + ) internal returns (address) { + GnoVaultFactory factory = _getPrevVersionVaultFactory(vaultType); + + vm.startPrank(admin); + IERC20(_gnoToken).approve(address(factory), _securityDeposit); + address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); + vm.stopPrank(); + + return vaultAddress; + } + + function _upgradeVault(VaultType vaultType, address vault) internal { + GnoVault vaultContract = GnoVault(payable(vault)); + uint256 currentVersion = vaultContract.version(); + if (vaultType == VaultType.GnoGenesisVault) { + if (currentVersion == 4) return; + require(currentVersion == 3, 'Invalid vault version'); + } else { + if (currentVersion == 3) return; + require(currentVersion == 2, 'Invalid vault version'); + } + address newImpl = _getOrCreateVaultImpl(vaultType); + address admin = vaultContract.admin(); + + vm.deal(admin, admin.balance + 1 ether); + vm.prank(admin); + vaultContract.upgradeToAndCall(newImpl, '0x'); + } + + function _getOrCreateVaultImpl(VaultType _vaultType) internal returns (address impl) { + if (_vaultImplementations[_vaultType] != address(0)) { + return _vaultImplementations[_vaultType]; + } + IGnoVault.GnoVaultConstructorArgs memory gnoArgs = IGnoVault.GnoVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + _gnoToken, + _gnoDaiDistributor, + _exitingAssetsClaimDelay + ); + IGnoErc20Vault.GnoErc20VaultConstructorArgs memory gnoErc20Args = IGnoErc20Vault + .GnoErc20VaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + _gnoToken, + _gnoDaiDistributor, + _exitingAssetsClaimDelay + ); + + if (_vaultType == VaultType.GnoVault) { + impl = address(new GnoVault(gnoArgs)); + } else if (_vaultType == VaultType.GnoBlocklistVault) { + impl = address(new GnoBlocklistVault(gnoArgs)); + } else if (_vaultType == VaultType.GnoPrivVault) { + impl = address(new GnoPrivVault(gnoArgs)); + } else if (_vaultType == VaultType.GnoGenesisVault) { + impl = address(new GnoGenesisVault(gnoArgs, _poolEscrow, _rewardGnoToken)); + } else if (_vaultType == VaultType.GnoErc20Vault) { + impl = address(new GnoErc20Vault(gnoErc20Args)); + } else if (_vaultType == VaultType.GnoBlocklistErc20Vault) { + impl = address(new GnoBlocklistErc20Vault(gnoErc20Args)); + } else if (_vaultType == VaultType.GnoPrivErc20Vault) { + impl = address(new GnoPrivErc20Vault(gnoErc20Args)); + } + _vaultImplementations[_vaultType] = impl; + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addVaultImpl(impl); + } +} diff --git a/test/helpers/KeeperHelpers.sol b/test/helpers/KeeperHelpers.sol new file mode 100644 index 00000000..c1fd2e9c --- /dev/null +++ b/test/helpers/KeeperHelpers.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; +import {IOsTokenVaultController} from '../../contracts/interfaces/IOsTokenVaultController.sol'; +import {Keeper} from '../../contracts/keeper/Keeper.sol'; + +abstract contract KeeperHelpers is Test { + struct SetVaultRewardParams { + address keeper; + address osTokenCtrl; + address vault; + int160 totalReward; + uint160 unlockedMevReward; + } + + address private _oracle; + uint256 internal _oraclePrivateKey; + uint256 private _validatorsMinOraclesBefore; + uint256 private _rewardsMinOraclesBefore; + + function _startOracleImpersonate(address keeper) internal { + if (_oracle != address(0)) return; + + _validatorsMinOraclesBefore = Keeper(keeper).validatorsMinOracles(); + _rewardsMinOraclesBefore = Keeper(keeper).rewardsMinOracles(); + + (_oracle, _oraclePrivateKey) = makeAddrAndKey('oracle'); + vm.startPrank(Keeper(keeper).owner()); + Keeper(keeper).setValidatorsMinOracles(1); + Keeper(keeper).setRewardsMinOracles(1); + Keeper(keeper).addOracle(_oracle); + vm.stopPrank(); + } + + function _stopOracleImpersonate(address keeper) internal { + if (_oracle == address(0)) return; + vm.startPrank(Keeper(keeper).owner()); + Keeper(keeper).setValidatorsMinOracles(_validatorsMinOraclesBefore); + Keeper(keeper).setRewardsMinOracles(_rewardsMinOraclesBefore); + Keeper(keeper).removeOracle(_oracle); + vm.stopPrank(); + + _oracle = address(0); + _oraclePrivateKey = 0; + _validatorsMinOraclesBefore = 0; + _rewardsMinOraclesBefore = 0; + } + + function _setVaultReward( + SetVaultRewardParams memory params + ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { + // setup oracle + _startOracleImpersonate(params.keeper); + + bytes32 rewardsRoot = keccak256( + bytes.concat( + keccak256(abi.encode(params.vault, params.totalReward, params.unlockedMevReward)) + ) + ); + + uint256 avgRewardPerSecond = IOsTokenVaultController(params.osTokenCtrl).avgRewardPerSecond(); + uint64 updateTimestamp = uint64(vm.getBlockTimestamp()); + string memory ipfsHash = 'rewardsIpfsHash'; + uint256 rewardsNonce = Keeper(params.keeper).rewardsNonce(); + bytes32 digest = _hashKeeperTypedData( + params.keeper, + keccak256( + abi.encode( + keccak256( + 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' + ), + rewardsRoot, + keccak256(bytes(ipfsHash)), + avgRewardPerSecond, + updateTimestamp, + rewardsNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + + // push down the stack + SetVaultRewardParams memory _params = params; + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: ipfsHash, + avgRewardPerSecond: avgRewardPerSecond, + updateTimestamp: updateTimestamp, + signatures: abi.encodePacked(r, s, v) + }); + + vm.warp(vm.getBlockTimestamp() + Keeper(_params.keeper).rewardsDelay() + 1); + Keeper(_params.keeper).updateRewards(updateParams); + + _stopOracleImpersonate(params.keeper); + + bytes32[] memory proof = new bytes32[](0); + return + IKeeperRewards.HarvestParams({ + rewardsRoot: rewardsRoot, + reward: _params.totalReward, + unlockedMevReward: _params.unlockedMevReward, + proof: proof + }); + } + + function _hashKeeperTypedData( + address keeper, + bytes32 structHash + ) internal view returns (bytes32) { + return + MessageHashUtils.toTypedDataHash( + keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256(bytes('KeeperOracles')), + keccak256(bytes('1')), + block.chainid, + keeper + ) + ), + structHash + ); + } +} diff --git a/test/helpers/ValidatorsHelpers.sol b/test/helpers/ValidatorsHelpers.sol new file mode 100644 index 00000000..8f8f86d5 --- /dev/null +++ b/test/helpers/ValidatorsHelpers.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {Keeper, IKeeper} from '../../contracts/keeper/Keeper.sol'; +import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; +import {IVaultValidators} from '../../contracts/interfaces/IVaultValidators.sol'; +import {IValidatorsRegistry} from '../../contracts/interfaces/IValidatorsRegistry.sol'; +import {KeeperHelpers} from './KeeperHelpers.sol'; + +abstract contract ValidatorsHelpers is Test, KeeperHelpers { + function _registerValidator( + address keeper, + address validatorsRegistry, + address vault, + uint256 depositAmount, + bool isV1Validator + ) internal returns (bytes memory) { + // setup oracle + _startOracleImpersonate(keeper); + + uint256[] memory deposits = new uint256[](1); + deposits[0] = (depositAmount) / 1 gwei; + + // Test successful registration with 0x01 prefix + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + keeper, + validatorsRegistry, + vault, + 'ipfsHash', + deposits, + isV1Validator + ); + + address validatorsManager = IVaultValidators(vault).validatorsManager(); + vm.prank(validatorsManager); + IVaultValidators(vault).registerValidators(approvalParams, ''); + + _stopOracleImpersonate(keeper); + + return _extractBytes(approvalParams.validators, 0, 48); + } + + function _extractBytes( + bytes memory data, + uint256 offset, + uint256 length + ) internal pure returns (bytes memory) { + bytes memory result = new bytes(length); + for (uint i = 0; i < length; i++) { + if (offset + i < data.length) { + result[i] = data[offset + i]; + } else { + break; // Prevent reading beyond array bounds + } + } + return result; + } + + function _collateralizeVault(address keeper, address validatorsRegistry, address vault) internal { + if (IKeeper(keeper).isCollateralized(vault)) return; + + _startOracleImpersonate(keeper); + + uint256[] memory depositAmounts = new uint256[](1); + depositAmounts[0] = 32 ether / 1 gwei; + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + keeper, + validatorsRegistry, + vault, + 'ipfsHash', + depositAmounts, + false + ); + + vm.prank(vault); + IKeeper(keeper).approveValidators(approvalParams); + + // revert previous state + _stopOracleImpersonate(keeper); + } + + function _getValidatorsApproval( + address keeper, + address validatorsRegistry, + address vault, + string memory ipfsHash, + uint256[] memory deposits, + bool isV1Validator + ) internal view returns (IKeeperValidators.ApprovalParams memory approvalParams) { + bytes memory validators; + for (uint i = 0; i < deposits.length; i++) { + bytes memory validator = _getValidatorDepositData(vault, deposits[i], isV1Validator); + validators = bytes.concat(validators, validator); + } + + approvalParams = IKeeperValidators.ApprovalParams({ + validatorsRegistryRoot: IValidatorsRegistry(validatorsRegistry).get_deposit_root(), + deadline: vm.getBlockTimestamp() + 1, + validators: validators, + signatures: '', + exitSignaturesIpfsHash: ipfsHash + }); + bytes32 digest = _hashKeeperTypedData( + keeper, + keccak256( + abi.encode( + keccak256( + 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' + ), + approvalParams.validatorsRegistryRoot, + vault, + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); + } + + function _getValidatorDepositData( + address vault, + uint256 depositAmount, + bool isV1Validator + ) internal view returns (bytes memory) { + bytes memory publicKey = vm.randomBytes(48); + bytes memory signature = vm.randomBytes(96); + bytes memory withdrawalCredentials = abi.encodePacked( + isV1Validator ? bytes1(0x01) : bytes1(0x02), + bytes11(0x0), + vault + ); + bytes32 depositDataRoot = _getDepositDataRoot( + publicKey, + signature, + withdrawalCredentials, + depositAmount + ); + return + isV1Validator + ? bytes.concat(publicKey, signature, depositDataRoot) + : bytes.concat( + publicKey, + signature, + depositDataRoot, + bytes8(SafeCast.toUint64(depositAmount)) + ); + } + + function _getDepositDataRoot( + bytes memory publicKey, + bytes memory signature, + bytes memory withdrawalCredentials, + uint256 depositAmount + ) internal pure returns (bytes32) { + bytes memory amount = _toLittleEndian64(uint64(depositAmount)); + bytes32 publicKeyRoot = sha256(abi.encodePacked(publicKey, bytes16(0))); + + bytes memory signatureFirstHalf = new bytes(64); + bytes memory signatureSecondHalf = new bytes(64); + for (uint i = 0; i < 64; i++) { + signatureFirstHalf[i] = signature[i]; + } + for (uint i = 0; i < 32; i++) { + signatureSecondHalf[i] = signature[i + 64]; + } + + bytes32 signatureRoot = sha256( + abi.encodePacked(sha256(signatureFirstHalf), sha256(signatureSecondHalf)) + ); + return + sha256( + abi.encodePacked( + sha256(abi.encodePacked(publicKeyRoot, withdrawalCredentials)), + sha256(abi.encodePacked(amount, bytes24(0), signatureRoot)) + ) + ); + } + + function _toLittleEndian64(uint64 value) private pure returns (bytes memory ret) { + ret = new bytes(8); + bytes8 bytesValue = bytes8(value); + // Byte swapping during copying to bytes. + ret[0] = bytesValue[7]; + ret[1] = bytesValue[6]; + ret[2] = bytesValue[5]; + ret[3] = bytesValue[4]; + ret[4] = bytesValue[3]; + ret[5] = bytesValue[2]; + ret[6] = bytesValue[1]; + ret[7] = bytesValue[0]; + } +} From d6f8bdf9fac9ed6300d32ab310c269275101b3d0 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Tue, 8 Apr 2025 23:48:28 +0300 Subject: [PATCH 05/15] Fix VaultValidators module (#105) * Fix VaultValidators module * Fix VaultValidators module --- contracts/interfaces/IVaultValidators.sol | 2 +- contracts/vaults/modules/VaultValidators.sol | 17 ++++++--------- test/VaultValidators.t.sol | 23 +++++++++----------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/contracts/interfaces/IVaultValidators.sol b/contracts/interfaces/IVaultValidators.sol index 810aafa2..bdac149e 100644 --- a/contracts/interfaces/IVaultValidators.sol +++ b/contracts/interfaces/IVaultValidators.sol @@ -23,7 +23,7 @@ interface IVaultValidators is IVaultAdmin, IVaultState { * @param publicKey The public key of the validator that was registered * @param amount The amount of assets that was registered */ - event ValidatorRegistered(bytes publicKey, uint256 amount); + event V2ValidatorRegistered(bytes publicKey, uint256 amount); /** * @notice Event emitted on validator withdrawal diff --git a/contracts/vaults/modules/VaultValidators.sol b/contracts/vaults/modules/VaultValidators.sol index aef7c739..34c6f29b 100644 --- a/contracts/vaults/modules/VaultValidators.sol +++ b/contracts/vaults/modules/VaultValidators.sol @@ -219,7 +219,7 @@ abstract contract VaultValidators is bytes calldata validators, uint256 validatorsCount, bool consolidationsApproved - ) private { + ) private nonReentrant { uint256 totalFeeAssets = msg.value; // Process each validator @@ -402,7 +402,7 @@ abstract contract VaultValidators is // mark v2 validator public key as tracked if (!isV1Validators) { v2Validators[publicKeyHash] = true; - emit ValidatorRegistered(publicKey, depositAmount); + emit V2ValidatorRegistered(publicKey, depositAmount); } else { emit ValidatorRegistered(publicKey); } @@ -440,16 +440,13 @@ abstract contract VaultValidators is ) internal returns (bool) { // SLOAD to memory address validatorsManager_ = validatorsManager(); - if (msg.sender == validatorsManager_) { - return true; + if (validatorsManager_ == address(0) || validators.length == 0) { + return false; } - if ( - validatorsManager_ == address(0) || - validators.length == 0 || - validatorsManagerSignature.length == 0 - ) { - return false; + if (validatorsManagerSignature.length == 0) { + // if no signature is provided, check if the caller is the validators manager + return msg.sender == validatorsManager_; } // check signature diff --git a/test/VaultValidators.t.sol b/test/VaultValidators.t.sol index 5769e9f3..741decca 100644 --- a/test/VaultValidators.t.sol +++ b/test/VaultValidators.t.sol @@ -11,9 +11,6 @@ import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; contract VaultValidatorsTest is Test, EthHelpers { - // Declare events we're testing for - event ValidatorRegistered(bytes publicKey); - event ValidatorRegistered(bytes publicKey, uint256 depositAmount); ForkContracts public contracts; EthVault public vault; @@ -79,7 +76,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Expect ValidatorRegistered event emission vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); // Call registerValidators from validatorsManager vm.prank(validatorsManager); @@ -118,7 +115,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Expect ValidatorRegistered event emission vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); // Call registerValidators from a non-manager address but with valid signature vm.prank(nonManager); @@ -226,7 +223,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Call registerValidators with empty validators vm.prank(validatorsManager); _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidValidators'); - vm.expectRevert(Errors.InvalidValidators.selector); + vm.expectRevert(Errors.AccessDenied.selector); vault.registerValidators(approvalParams, ''); _stopSnapshotGas(); @@ -374,12 +371,12 @@ contract VaultValidatorsTest is Test, EthHelpers { // Extract first validator's public key and expect its event bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorRegistered(publicKey1, validatorDeposit); + emit IVaultValidators.V2ValidatorRegistered(publicKey1, validatorDeposit); // Extract second validator's public key and expect its event bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorRegistered(publicKey2, validatorDeposit); + emit IVaultValidators.V2ValidatorRegistered(publicKey2, validatorDeposit); // Call registerValidators with multiple validators vm.prank(validatorsManager); @@ -452,7 +449,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // For V2 validators, the event includes deposit amount vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); // Call registerValidators with V2 validator vm.prank(validatorsManager); @@ -493,7 +490,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Expect event for first use vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorRegistered(publicKey, validatorDeposit); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); // Use the signature once vm.prank(nonManager); @@ -763,7 +760,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Call fundValidators with empty validators data vm.prank(validatorsManager); _startSnapshotGas('VaultValidatorsTest_test_fundValidators_invalidValidators'); - vm.expectRevert(Errors.InvalidValidators.selector); + vm.expectRevert(Errors.AccessDenied.selector); vault.fundValidators(emptyValidatorsData, ''); _stopSnapshotGas(); } @@ -1128,7 +1125,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // 3. Call withdrawValidators with empty data vm.prank(validatorsManager); _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty'); - vm.expectRevert(Errors.InvalidValidators.selector); + vm.expectRevert(Errors.AccessDenied.selector); vault.withdrawValidators{value: 0.1 ether}(invalidWithdrawalData, ''); _stopSnapshotGas(); @@ -1400,7 +1397,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // 3. Call consolidateValidators with empty validators data vm.prank(validatorsManager); _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty'); - vm.expectRevert(Errors.InvalidValidators.selector); + vm.expectRevert(Errors.AccessDenied.selector); vault.consolidateValidators{value: consolidationFee}(emptyValidatorsData, '', ''); _stopSnapshotGas(); From a9b3fe95b23cd408aed1637aa18703e49d3fdb36 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Wed, 9 Apr 2025 11:45:06 +0300 Subject: [PATCH 06/15] Fix validators (#106) * Fix VaultValidators module * Fix VaultValidators module * Remove ABI * Refactor .github * Remove implementation files * Remove deployments * Remove hardhat tests, snapshots, modify GnoRewardSplitter tests * Add snapshot checks to RewardSplitter tests --- .github/workflows/CI.yaml | 73 - .github/workflows/coverage.yaml | 96 + .github/workflows/lint.yaml | 36 + .github/workflows/slither.yaml | 42 + .github/workflows/test-fork.yaml | 32 + .github/workflows/test.yaml | 32 + .husky/pre-commit | 5 - .openzeppelin/holesky.json | 15570 ---------------- .openzeppelin/mainnet.json | 15569 --------------- .openzeppelin/unknown-100.json | 3896 ---- .openzeppelin/unknown-10200.json | 3896 ---- .openzeppelin/unknown-560048.json | 12394 ------------ .solcover.js | 3 - abi/Errors.json | 232 - abi/IBalancerRateProvider.json | 15 - abi/IBalancerVault.json | 90 - abi/IChainlinkAggregator.json | 28 - abi/IChainlinkV3Aggregator.json | 74 - abi/IConsolidationsChecker.json | 103 - abi/IDepositDataRegistry.json | 356 - abi/IERC1155Errors.json | 104 - abi/IERC1271.json | 26 - abi/IERC1363.json | 373 - abi/IERC1822Proxiable.json | 15 - abi/IERC1967.json | 47 - abi/IERC20Errors.json | 88 - abi/IERC5267.json | 51 - abi/IERC721Errors.json | 105 - abi/IEthBlocklistErc20Vault.json | 1954 -- abi/IEthBlocklistVault.json | 1657 -- abi/IEthErc20Vault.json | 1847 -- abi/IEthFoxVault.json | 1361 -- abi/IEthGenesisVault.json | 1630 -- abi/IEthPoolEscrow.json | 129 - abi/IEthPrivErc20Vault.json | 1954 -- abi/IEthPrivVault.json | 1657 -- abi/IEthValidatorsRegistry.json | 80 - abi/IEthVault.json | 1550 -- abi/IEthVaultFactory.json | 96 - abi/IGnoBlocklistErc20Vault.json | 1835 -- abi/IGnoBlocklistVault.json | 1538 -- abi/IGnoDaiDistributor.json | 28 - abi/IGnoErc20Vault.json | 1728 -- abi/IGnoGenesisVault.json | 1511 -- abi/IGnoPoolEscrow.json | 152 - abi/IGnoPrivErc20Vault.json | 1835 -- abi/IGnoPrivVault.json | 1538 -- abi/IGnoValidatorsRegistry.json | 145 - abi/IGnoVault.json | 1431 -- abi/IGnoVaultFactory.json | 96 - abi/IKeeper.json | 737 - abi/IKeeperOracles.json | 161 - abi/IKeeperRewards.json | 548 - abi/IKeeperValidators.json | 724 - abi/IMerkleDistributor.json | 61 - abi/IMulticall.json | 21 - abi/IOsToken.json | 440 - abi/IOsTokenConfig.json | 143 - abi/IOsTokenFlashLoanRecipient.json | 20 - abi/IOsTokenFlashLoans.json | 39 - abi/IOsTokenVaultController.json | 416 - abi/IOsTokenVaultEscrow.json | 489 - abi/IOsTokenVaultEscrowAuth.json | 36 - abi/IOwnMevEscrow.json | 54 - abi/IRewardEthToken.json | 54 - abi/IRewardGnoToken.json | 54 - abi/IRewardSplitter.json | 496 - abi/IRewardSplitterFactory.json | 59 - abi/ISavingsXDaiAdapter.json | 21 - abi/ISharedMevEscrow.json | 47 - abi/IValidatorsChecker.json | 90 - abi/IValidatorsRegistry.json | 52 - abi/IVaultAdmin.json | 79 - abi/IVaultBlocklist.json | 186 - abi/IVaultEnterExit.json | 686 - abi/IVaultEthStaking.json | 1101 -- abi/IVaultFee.json | 169 - abi/IVaultGnoStaking.json | 1054 -- abi/IVaultMev.json | 422 - abi/IVaultOsToken.json | 966 - abi/IVaultState.json | 409 - abi/IVaultToken.json | 983 - abi/IVaultValidators.json | 729 - abi/IVaultVersion.json | 131 - abi/IVaultWhitelist.json | 186 - abi/IVaultsRegistry.json | 208 - deployments/chiado-upgrade-v3-tx.json | 213 - deployments/chiado-vault-v3-upgrades.json | 23 - deployments/chiado.json | 22 - deployments/gnosis-upgrade-v3-tx.json | 213 - deployments/gnosis-vault-v3-upgrades.json | 23 - deployments/gnosis.json | 22 - deployments/holesky-upgrade-v4-tx.json | 72 - deployments/holesky-vault-v4-upgrades.json | 23 - deployments/holesky.json | 22 - deployments/hoodi-upgrade-v2-tx.json | 172 - deployments/hoodi-upgrade-v3-tx.json | 213 - deployments/hoodi-upgrade-v4-tx.json | 72 - deployments/hoodi-vault-v2-upgrades.json | 23 - deployments/hoodi-vault-v3-upgrades.json | 23 - deployments/hoodi-vault-v4-upgrades.json | 23 - deployments/hoodi.json | 25 - deployments/mainnet-upgrade-v2-tx.json | 186 - deployments/mainnet-upgrade-v3-tx.json | 213 - deployments/mainnet-upgrade-v4-tx.json | 72 - deployments/mainnet-vault-v2-upgrades.json | 41 - deployments/mainnet-vault-v3-upgrades.json | 23 - deployments/mainnet-vault-v4-upgrades.json | 23 - deployments/mainnet.json | 22 - eslint.config.mjs | 44 - hardhat.config.ts | 127 - package-lock.json | 11796 ------------ package.json | 96 - slither.config.json | 7 - test/Constants.t.sol | 27 - test/EthOsTokenVaultEscrow.spec.ts | 792 - test/EthRewardSplitter.t.sol | 26 +- test/EthVault.burn.spec.ts | 133 - test/EthVault.deposit.spec.ts | 233 - test/EthVault.liquidate.spec.ts | 232 - test/EthVault.mint.spec.ts | 321 - test/EthVault.multicall.spec.ts | 235 - test/EthVault.redeem.spec.ts | 222 - test/EthVault.register.spec.ts | 499 - test/EthVault.settings.spec.ts | 178 - test/EthVault.state.spec.ts | 335 - test/EthVault.token.spec.ts | 470 - test/EthVault.upgrade.spec.ts | 354 - test/EthVault.whitelist.spec.ts | 186 - test/EthVault.withdraw.spec.ts | 1013 - test/EthVaultFactory.spec.ts | 255 - test/Fork.t.sol | 22 - test/GnoRewardSplitter.t.sol | 156 - test/GnosisFork.t.sol | 34 - test/KeeperOracles.spec.ts | 125 - test/KeeperOracles.t.sol | 1 - test/KeeperRewards.spec.ts | 837 - test/KeeperValidators.spec.ts | 633 - test/MainnetFork.t.sol | 32 - test/OsToken.spec.ts | 582 - test/OsTokenConfig.spec.ts | 168 - test/OsTokenFlashLoans.spec.ts | 85 - test/PriceFeed.test.ts | 118 - test/Rewards.t.sol | 130 - test/ValidatorsChecker.spec.ts | 389 - .../DepositDataRegistry.spec.ts.snap | 36 - .../EthBlocklistErc20Vault.spec.ts.snap | 29 - .../EthBlocklistVault.spec.ts.snap | 22 - test/__snapshots__/EthErc20Vault.spec.ts.snap | 50 - test/__snapshots__/EthFoxVault.spec.ts.snap | 50 - .../EthGenesisVault.spec.ts.snap | 64 - .../EthOsTokenVaultEscrow.spec.ts.snap | 64 - .../EthPrivErc20Vault.spec.ts.snap | 29 - test/__snapshots__/EthPrivVault.spec.ts.snap | 8 - test/__snapshots__/EthVault.burn.spec.ts.snap | 15 - .../EthVault.deposit.spec.ts.snap | 29 - .../EthVault.liquidate.spec.ts.snap | 15 - test/__snapshots__/EthVault.mint.spec.ts.snap | 36 - .../EthVault.multicall.spec.ts.snap | 15 - .../EthVault.redeem.spec.ts.snap | 15 - .../EthVault.register.spec.ts.snap | 15 - .../EthVault.settings.spec.ts.snap | 22 - .../__snapshots__/EthVault.state.spec.ts.snap | 22 - .../__snapshots__/EthVault.token.spec.ts.snap | 50 - .../EthVault.upgrade.spec.ts.snap | 57 - .../EthVault.whitelist.spec.ts.snap | 36 - .../EthVault.withdraw.spec.ts.snap | 59 - .../EthVaultFactory.spec.ts.snap | 57 - test/__snapshots__/KeeperOracles.spec.ts.snap | 22 - test/__snapshots__/KeeperRewards.spec.ts.snap | 71 - .../KeeperValidators.spec.ts.snap | 36 - test/__snapshots__/OsToken.spec.ts.snap | 92 - test/__snapshots__/OsTokenConfig.spec.ts.snap | 22 - .../OsTokenFlashLoans.spec.ts.snap | 8 - .../OsTokenVaultEscrow.spec.ts.snap | 64 - test/__snapshots__/OwnMevEscrow.spec.ts.snap | 8 - .../__snapshots__/RewardSplitter.spec.ts.snap | 36 - .../RewardSplitterFactory.spec.ts.snap | 8 - .../SharedMevEscrow.spec.ts.snap | 8 - .../__snapshots__/VaultsRegistry.spec.ts.snap | 43 - test/gnosis/GnoRewardSplitter.t.sol | 530 + .../GnoBlocklistErc20Vault.spec.ts.snap | 22 - .../GnoBlocklistVault.spec.ts.snap | 15 - .../__snapshots__/GnoErc20Vault.spec.ts.snap | 15 - .../GnoGenesisVault.spec.ts.snap | 43 - .../GnoOwnMevEscrow.spec.ts.snap | 8 - .../GnoPrivErc20Vault.spec.ts.snap | 22 - .../__snapshots__/GnoPrivVault.spec.ts.snap | 15 - .../GnoSharedMevEscrow.spec.ts.snap | 8 - .../GnoVault.register.spec.ts.snap | 29 - .../__snapshots__/GnoVault.spec.ts.snap | 29 - .../__snapshots__/GnoVault.state.spec.ts.snap | 15 - .../GnoVault.upgrade.spec.ts.snap | 50 - .../__snapshots__/XdaiExchange.spec.ts.snap | 36 - .../artifacts/EthBlocklistErc20Vault.json | 2057 -- test/shared/artifacts/EthBlocklistVault.json | 1745 -- test/shared/artifacts/EthErc20Vault.json | 1950 -- test/shared/artifacts/EthGenesisVault.json | 1751 -- test/shared/artifacts/EthPrivErc20Vault.json | 2057 -- test/shared/artifacts/EthPrivVault.json | 1745 -- .../artifacts/EthValidatorsRegistry.json | 120 - test/shared/artifacts/EthVault.json | 1638 -- test/shared/artifacts/EthVaultV1.json | 1596 -- .../artifacts/GnoBlocklistErc20Vault.json | 1943 -- test/shared/artifacts/GnoBlocklistVault.json | 1631 -- test/shared/artifacts/GnoErc20Vault.json | 1836 -- test/shared/artifacts/GnoGenesisVault.json | 1621 -- test/shared/artifacts/GnoPrivErc20Vault.json | 1943 -- test/shared/artifacts/GnoPrivVault.json | 1631 -- .../artifacts/GnoValidatorsRegistry.json | 395 - test/shared/artifacts/GnoVault.json | 1524 -- test/shared/artifacts/GnoVaultFactory.json | 164 - test/shared/constants.ts | 96 - test/shared/contracts.ts | 112 - test/shared/expect.ts | 6 - test/shared/fixtures.ts | 1156 -- test/shared/gnoFixtures.ts | 855 - test/shared/rewards.ts | 216 - test/shared/snapshotGasCost.ts | 51 - test/shared/types.ts | 60 - test/shared/utils.ts | 133 - test/shared/validators.ts | 368 - 222 files changed, 793 insertions(+), 145488 deletions(-) delete mode 100644 .github/workflows/CI.yaml create mode 100644 .github/workflows/coverage.yaml create mode 100644 .github/workflows/lint.yaml create mode 100644 .github/workflows/slither.yaml create mode 100644 .github/workflows/test-fork.yaml create mode 100644 .github/workflows/test.yaml delete mode 100755 .husky/pre-commit delete mode 100644 .openzeppelin/holesky.json delete mode 100644 .openzeppelin/mainnet.json delete mode 100644 .openzeppelin/unknown-100.json delete mode 100644 .openzeppelin/unknown-10200.json delete mode 100644 .openzeppelin/unknown-560048.json delete mode 100644 .solcover.js delete mode 100644 abi/Errors.json delete mode 100644 abi/IBalancerRateProvider.json delete mode 100644 abi/IBalancerVault.json delete mode 100644 abi/IChainlinkAggregator.json delete mode 100644 abi/IChainlinkV3Aggregator.json delete mode 100644 abi/IConsolidationsChecker.json delete mode 100644 abi/IDepositDataRegistry.json delete mode 100644 abi/IERC1155Errors.json delete mode 100644 abi/IERC1271.json delete mode 100644 abi/IERC1363.json delete mode 100644 abi/IERC1822Proxiable.json delete mode 100644 abi/IERC1967.json delete mode 100644 abi/IERC20Errors.json delete mode 100644 abi/IERC5267.json delete mode 100644 abi/IERC721Errors.json delete mode 100644 abi/IEthBlocklistErc20Vault.json delete mode 100644 abi/IEthBlocklistVault.json delete mode 100644 abi/IEthErc20Vault.json delete mode 100644 abi/IEthFoxVault.json delete mode 100644 abi/IEthGenesisVault.json delete mode 100644 abi/IEthPoolEscrow.json delete mode 100644 abi/IEthPrivErc20Vault.json delete mode 100644 abi/IEthPrivVault.json delete mode 100644 abi/IEthValidatorsRegistry.json delete mode 100644 abi/IEthVault.json delete mode 100644 abi/IEthVaultFactory.json delete mode 100644 abi/IGnoBlocklistErc20Vault.json delete mode 100644 abi/IGnoBlocklistVault.json delete mode 100644 abi/IGnoDaiDistributor.json delete mode 100644 abi/IGnoErc20Vault.json delete mode 100644 abi/IGnoGenesisVault.json delete mode 100644 abi/IGnoPoolEscrow.json delete mode 100644 abi/IGnoPrivErc20Vault.json delete mode 100644 abi/IGnoPrivVault.json delete mode 100644 abi/IGnoValidatorsRegistry.json delete mode 100644 abi/IGnoVault.json delete mode 100644 abi/IGnoVaultFactory.json delete mode 100644 abi/IKeeper.json delete mode 100644 abi/IKeeperOracles.json delete mode 100644 abi/IKeeperRewards.json delete mode 100644 abi/IKeeperValidators.json delete mode 100644 abi/IMerkleDistributor.json delete mode 100644 abi/IMulticall.json delete mode 100644 abi/IOsToken.json delete mode 100644 abi/IOsTokenConfig.json delete mode 100644 abi/IOsTokenFlashLoanRecipient.json delete mode 100644 abi/IOsTokenFlashLoans.json delete mode 100644 abi/IOsTokenVaultController.json delete mode 100644 abi/IOsTokenVaultEscrow.json delete mode 100644 abi/IOsTokenVaultEscrowAuth.json delete mode 100644 abi/IOwnMevEscrow.json delete mode 100644 abi/IRewardEthToken.json delete mode 100644 abi/IRewardGnoToken.json delete mode 100644 abi/IRewardSplitter.json delete mode 100644 abi/IRewardSplitterFactory.json delete mode 100644 abi/ISavingsXDaiAdapter.json delete mode 100644 abi/ISharedMevEscrow.json delete mode 100644 abi/IValidatorsChecker.json delete mode 100644 abi/IValidatorsRegistry.json delete mode 100644 abi/IVaultAdmin.json delete mode 100644 abi/IVaultBlocklist.json delete mode 100644 abi/IVaultEnterExit.json delete mode 100644 abi/IVaultEthStaking.json delete mode 100644 abi/IVaultFee.json delete mode 100644 abi/IVaultGnoStaking.json delete mode 100644 abi/IVaultMev.json delete mode 100644 abi/IVaultOsToken.json delete mode 100644 abi/IVaultState.json delete mode 100644 abi/IVaultToken.json delete mode 100644 abi/IVaultValidators.json delete mode 100644 abi/IVaultVersion.json delete mode 100644 abi/IVaultWhitelist.json delete mode 100644 abi/IVaultsRegistry.json delete mode 100644 deployments/chiado-upgrade-v3-tx.json delete mode 100644 deployments/chiado-vault-v3-upgrades.json delete mode 100644 deployments/chiado.json delete mode 100644 deployments/gnosis-upgrade-v3-tx.json delete mode 100644 deployments/gnosis-vault-v3-upgrades.json delete mode 100644 deployments/gnosis.json delete mode 100644 deployments/holesky-upgrade-v4-tx.json delete mode 100644 deployments/holesky-vault-v4-upgrades.json delete mode 100644 deployments/holesky.json delete mode 100644 deployments/hoodi-upgrade-v2-tx.json delete mode 100644 deployments/hoodi-upgrade-v3-tx.json delete mode 100644 deployments/hoodi-upgrade-v4-tx.json delete mode 100644 deployments/hoodi-vault-v2-upgrades.json delete mode 100644 deployments/hoodi-vault-v3-upgrades.json delete mode 100644 deployments/hoodi-vault-v4-upgrades.json delete mode 100644 deployments/hoodi.json delete mode 100644 deployments/mainnet-upgrade-v2-tx.json delete mode 100644 deployments/mainnet-upgrade-v3-tx.json delete mode 100644 deployments/mainnet-upgrade-v4-tx.json delete mode 100644 deployments/mainnet-vault-v2-upgrades.json delete mode 100644 deployments/mainnet-vault-v3-upgrades.json delete mode 100644 deployments/mainnet-vault-v4-upgrades.json delete mode 100644 deployments/mainnet.json delete mode 100644 eslint.config.mjs delete mode 100644 hardhat.config.ts delete mode 100644 package-lock.json delete mode 100644 package.json delete mode 100644 slither.config.json delete mode 100644 test/Constants.t.sol delete mode 100644 test/EthOsTokenVaultEscrow.spec.ts delete mode 100644 test/EthVault.burn.spec.ts delete mode 100644 test/EthVault.deposit.spec.ts delete mode 100644 test/EthVault.liquidate.spec.ts delete mode 100644 test/EthVault.mint.spec.ts delete mode 100644 test/EthVault.multicall.spec.ts delete mode 100644 test/EthVault.redeem.spec.ts delete mode 100644 test/EthVault.register.spec.ts delete mode 100644 test/EthVault.settings.spec.ts delete mode 100644 test/EthVault.state.spec.ts delete mode 100644 test/EthVault.token.spec.ts delete mode 100644 test/EthVault.upgrade.spec.ts delete mode 100644 test/EthVault.whitelist.spec.ts delete mode 100644 test/EthVault.withdraw.spec.ts delete mode 100644 test/EthVaultFactory.spec.ts delete mode 100644 test/Fork.t.sol delete mode 100644 test/GnoRewardSplitter.t.sol delete mode 100644 test/GnosisFork.t.sol delete mode 100644 test/KeeperOracles.spec.ts delete mode 100644 test/KeeperRewards.spec.ts delete mode 100644 test/KeeperValidators.spec.ts delete mode 100644 test/MainnetFork.t.sol delete mode 100644 test/OsToken.spec.ts delete mode 100644 test/OsTokenConfig.spec.ts delete mode 100644 test/OsTokenFlashLoans.spec.ts delete mode 100644 test/PriceFeed.test.ts delete mode 100644 test/Rewards.t.sol delete mode 100644 test/ValidatorsChecker.spec.ts delete mode 100644 test/__snapshots__/DepositDataRegistry.spec.ts.snap delete mode 100644 test/__snapshots__/EthBlocklistErc20Vault.spec.ts.snap delete mode 100644 test/__snapshots__/EthBlocklistVault.spec.ts.snap delete mode 100644 test/__snapshots__/EthErc20Vault.spec.ts.snap delete mode 100644 test/__snapshots__/EthFoxVault.spec.ts.snap delete mode 100644 test/__snapshots__/EthGenesisVault.spec.ts.snap delete mode 100644 test/__snapshots__/EthOsTokenVaultEscrow.spec.ts.snap delete mode 100644 test/__snapshots__/EthPrivErc20Vault.spec.ts.snap delete mode 100644 test/__snapshots__/EthPrivVault.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.burn.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.deposit.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.liquidate.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.mint.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.multicall.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.redeem.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.register.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.settings.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.state.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.token.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.upgrade.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.whitelist.spec.ts.snap delete mode 100644 test/__snapshots__/EthVault.withdraw.spec.ts.snap delete mode 100644 test/__snapshots__/EthVaultFactory.spec.ts.snap delete mode 100644 test/__snapshots__/KeeperOracles.spec.ts.snap delete mode 100644 test/__snapshots__/KeeperRewards.spec.ts.snap delete mode 100644 test/__snapshots__/KeeperValidators.spec.ts.snap delete mode 100644 test/__snapshots__/OsToken.spec.ts.snap delete mode 100644 test/__snapshots__/OsTokenConfig.spec.ts.snap delete mode 100644 test/__snapshots__/OsTokenFlashLoans.spec.ts.snap delete mode 100644 test/__snapshots__/OsTokenVaultEscrow.spec.ts.snap delete mode 100644 test/__snapshots__/OwnMevEscrow.spec.ts.snap delete mode 100644 test/__snapshots__/RewardSplitter.spec.ts.snap delete mode 100644 test/__snapshots__/RewardSplitterFactory.spec.ts.snap delete mode 100644 test/__snapshots__/SharedMevEscrow.spec.ts.snap delete mode 100644 test/__snapshots__/VaultsRegistry.spec.ts.snap create mode 100644 test/gnosis/GnoRewardSplitter.t.sol delete mode 100644 test/gnosis/__snapshots__/GnoBlocklistErc20Vault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoBlocklistVault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoErc20Vault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoGenesisVault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoOwnMevEscrow.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoPrivErc20Vault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoPrivVault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoSharedMevEscrow.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoVault.register.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoVault.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoVault.state.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/GnoVault.upgrade.spec.ts.snap delete mode 100644 test/gnosis/__snapshots__/XdaiExchange.spec.ts.snap delete mode 100644 test/shared/artifacts/EthBlocklistErc20Vault.json delete mode 100644 test/shared/artifacts/EthBlocklistVault.json delete mode 100644 test/shared/artifacts/EthErc20Vault.json delete mode 100644 test/shared/artifacts/EthGenesisVault.json delete mode 100644 test/shared/artifacts/EthPrivErc20Vault.json delete mode 100644 test/shared/artifacts/EthPrivVault.json delete mode 100644 test/shared/artifacts/EthValidatorsRegistry.json delete mode 100644 test/shared/artifacts/EthVault.json delete mode 100644 test/shared/artifacts/EthVaultV1.json delete mode 100644 test/shared/artifacts/GnoBlocklistErc20Vault.json delete mode 100644 test/shared/artifacts/GnoBlocklistVault.json delete mode 100644 test/shared/artifacts/GnoErc20Vault.json delete mode 100644 test/shared/artifacts/GnoGenesisVault.json delete mode 100644 test/shared/artifacts/GnoPrivErc20Vault.json delete mode 100644 test/shared/artifacts/GnoPrivVault.json delete mode 100644 test/shared/artifacts/GnoValidatorsRegistry.json delete mode 100644 test/shared/artifacts/GnoVault.json delete mode 100644 test/shared/artifacts/GnoVaultFactory.json delete mode 100644 test/shared/constants.ts delete mode 100644 test/shared/contracts.ts delete mode 100644 test/shared/expect.ts delete mode 100644 test/shared/fixtures.ts delete mode 100644 test/shared/gnoFixtures.ts delete mode 100644 test/shared/rewards.ts delete mode 100644 test/shared/snapshotGasCost.ts delete mode 100644 test/shared/types.ts delete mode 100644 test/shared/utils.ts delete mode 100644 test/shared/validators.ts diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml deleted file mode 100644 index 14924d5e..00000000 --- a/.github/workflows/CI.yaml +++ /dev/null @@ -1,73 +0,0 @@ -name: CI - -on: - push: - branches: - - main - pull_request: - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: 'npm' - - - name: Setup Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: stable - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - - name: Cache node modules - id: cache-npm - uses: actions/cache@v3 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }} - name: List the state of node modules - continue-on-error: true - run: npm list - - - name: Install dependencies - run: npm install - - - run: npm run lint - - run: npm run compile - env: { SKIP_LOAD: true } - - run: npm run test:gas - env: - SKIP_LOAD: true - MAINNET_FORK_RPC_URL: ${{ secrets.MAINNET_FORK_RPC_URL }} - - run: npm run test:fork - env: - SKIP_LOAD: true - MAINNET_FORK_RPC_URL: ${{ secrets.MAINNET_FORK_RPC_URL }} - - run: npm run coverage - env: - SKIP_LOAD: true - MAINNET_FORK_RPC_URL: ${{ secrets.MAINNET_FORK_RPC_URL }} - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - - run: pip3 install slither-analyzer && npm run slither diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml new file mode 100644 index 00000000..57dbb3a4 --- /dev/null +++ b/.github/workflows/coverage.yaml @@ -0,0 +1,96 @@ +name: code coverage + +on: + push: + branches: + - main + pull_request: + +jobs: + comment-forge-coverage: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Build + run: forge build + + - name: Run forge coverage + id: coverage + run: | + { + echo 'COVERAGE</dev/null | + grep '^|' | + grep -v 'test/' | + grep -v '^|--' | + grep -v 'File' | + sed 's/-*+//g' + echo EOF + } >> "$GITHUB_OUTPUT" + env: + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + + - name: Check coverage is updated + uses: actions/github-script@v5 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const file = "coverage.txt" + if(!fs.existsSync(file)) { + console.log("Nothing to check"); + return + } + const currentCoverage = fs.readFileSync(file, "utf8").trim(); + const newCoverage = (`${{ steps.coverage.outputs.COVERAGE }}`).trim(); + if (newCoverage != currentCoverage) { + core.setFailed(`Code coverage not updated. Run : forge coverage | grep '^|' | grep -v 'test/' > coverage.txt`); + } + + - name: Comment on PR + id: comment + uses: actions/github-script@v5 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const {data: comments} = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }) + + const botComment = comments.find(comment => comment.user.id === 41898282) + + const output = `${{ steps.coverage.outputs.COVERAGE }}`; + const commentBody = `Forge code coverage:\n${output}\n`; + + if (botComment) { + github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: commentBody + }) + } else { + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody + }); + } diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 00000000..aefccf97 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,36 @@ +name: Lint + +on: + push: + branches: + - main + pull_request: + +jobs: + run-linters: + name: Run linters + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v3 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Lint + run: forge fmt --check + + - uses: actions/cache@v3 + name: Configure npm caching + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/workflows/prettier.yml') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Check code formatting + run: |- + npx prettier --check . diff --git a/.github/workflows/slither.yaml b/.github/workflows/slither.yaml new file mode 100644 index 00000000..a21e5256 --- /dev/null +++ b/.github/workflows/slither.yaml @@ -0,0 +1,42 @@ +name: Slither + +on: + push: + branches: + - main + pull_request: + +jobs: + slither: + name: Slither analysis + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install pip3 + run: | + python -m pip install --upgrade pip + + - name: Install Slither + run: | + pip3 install slither-analyzer + + - name: Build + run: forge build + + - name: Run Slither + run: | + slither --fail-high --skip-clean . diff --git a/.github/workflows/test-fork.yaml b/.github/workflows/test-fork.yaml new file mode 100644 index 00000000..05c7fc54 --- /dev/null +++ b/.github/workflows/test-fork.yaml @@ -0,0 +1,32 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + +jobs: + forge-tests: + name: Forge Tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Build + run: forge build + + - name: Run tests + run: forge test --isolate -vvv + env: + FORGE_SNAPSHOT_CHECK: false + USE_FORK_VAULTS: true + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000..a9009a56 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,32 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + +jobs: + forge-tests: + name: Forge Tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Build + run: forge build + + - name: Run tests + run: forge test --isolate -vvv + env: + FORGE_SNAPSHOT_CHECK: true + USE_FORK_VAULTS: false + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 60a124cc..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npm run precommit -npm run export-abi && git add abi/ diff --git a/.openzeppelin/holesky.json b/.openzeppelin/holesky.json deleted file mode 100644 index 8fb075da..00000000 --- a/.openzeppelin/holesky.json +++ /dev/null @@ -1,15570 +0,0 @@ -{ - "manifestVersion": "3.2", - "proxies": [], - "impls": { - "eed112afbccc5e70d6a205b870af0c99b6531f56f2df680b1b89190efe783059": { - "address": "0x0360927C228a725bCDD9e1d35fEBCfa48741cFb7", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "0aa2dd5dca90cc525b0661c7c35a3609b53ef3ef943f6117ef8573b5f04c3a68": { - "address": "0x517cc95018e451AbF0F4e0A89376024e8B5B27e8", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:69" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:104" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "68b7800ecd7e5ae177a5f10dd1d866cfbaa4203e4d026538cb51024a2b3b9040": { - "address": "0xb732421B3179B5069EA88B4966e1c2067656C0BD", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "213", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "266", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "bdbcf2082c82cc7da842ca1b97446cba62d4c6897e6398942fb0ebf01fe50726": { - "address": "0xc7235D7E08d9A04e801517A117Cd012798b8B386", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "213", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "266", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:69" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:104" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "faf1d17536e85a08e7d60558bad476aeae45f0a8181cc5de431fa5cad8cf4ba4": { - "address": "0x6e16fc22013e07B8C8e6d4b30280F44d42A60a97", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:241" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f90ac7973f0fa5fe9f806919227cd32d03b23b4c001f3fc7c80ffb44bdfbdf1a": { - "address": "0x23c85111045b3db22aEe822DAA3C09b7fBAFa437", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11788_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:243" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "413", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "414", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "464", - "type": "t_array(t_uint256)50_storage", - "contract": "EthFoxVault", - "src": "contracts/vaults/ethereum/custom/EthFoxVault.sol:144" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)64_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)188_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11782_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11782_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11788_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11782_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - }, - "allAddresses": [ - "0x23c85111045b3db22aEe822DAA3C09b7fBAFa437", - "0x16c35CC583b35c301D1884D4cdFb6e06A2dF45f2" - ] - }, - "27f5d513b53807c228c2988ea1508b3e70c1b003890e53cfe9832f40699497ef": { - "address": "0x355AB27BC05f6f54632cFA5A7168219DF72ae727", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "631ec5276b1b06a921da2df6817347ddf8bc4781b9e78eec1930c680f78d9b79": { - "address": "0xEBCBADedbd0Dd909B87BBAC44e522aD00E37F075", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:120" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "659be184ebbc63ddf8f368dd1871c9729a194d8597a68aed5e4257045e4fa302": { - "address": "0xE00512e3F38Ec4f4e79152474DA215506b5b1902", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:115" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "648983e739fe48226487c4f224af106eef32ec081f2b7563e47b882326c37daa": { - "address": "0x849DA65aFEd8483152f8Baa75F776c6f2C02E540", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "068ba63027bd6ca2ed4756a5404ff5786f8e00c6ab62485918a3fb96b1f050b6": { - "address": "0xF0C1670364d4b5c4e9dc8062cDd45068D9c678d6", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:128" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "808ad96fb97a256384cee95b9e4d523972003c9d112efe0a0f093bcc8af6b7e2": { - "address": "0x01d34aeE72325F1d4A748f13C2169404523eCEE0", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:128" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "6218823b2d9374cabd46f3389d0a05d6d9ec2a5d8a560f619b74ea2d72ec3633": { - "address": "0x35dC754f157b32Ba0941ffCD89d16d3D0B2cA6CF", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:264" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "295ab656c218d61652acceda8183568f83c8f7340e757c243368508476fdcaca": { - "address": "0x90190b037148Bf25BB1cEEfE717ea320bb594F70", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "vault", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "EigenPodOwner", - "src": "contracts/vaults/ethereum/restake/EigenPodOwner.sol:37" - }, - { - "label": "eigenPod", - "offset": 0, - "slot": "1", - "type": "t_address", - "contract": "EigenPodOwner", - "src": "contracts/vaults/ethereum/restake/EigenPodOwner.sol:41" - }, - { - "label": "__gap", - "offset": 0, - "slot": "2", - "type": "t_array(t_uint256)50_storage", - "contract": "EigenPodOwner", - "src": "contracts/vaults/ethereum/restake/EigenPodOwner.sol:244" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "88a35bdbe67ae08f46e1de95169f50f1e1a8f77aa892a3719c759d1f7248b821": { - "address": "0x288F9dc773Dd0E3DC94F975BD24e5018FFc55293", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "413", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "414", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "416", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeVault.sol:164" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "ee845e867ae6eaacbd9c981cb1cd2a777e2f81b7c674f017f07dacfd7d9d0783": { - "address": "0x89EA6d8000f7925c4765cC1374FAD4423A557eB5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "413", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "414", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "416", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeVault.sol:164" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "519", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "520", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "570", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakePrivVault", - "src": "contracts/vaults/ethereum/restake/EthRestakePrivVault.sol:118" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "2159592b84444512c40efe677428a9703387fe376407ce34a82bdb89694fe714": { - "address": "0xA60Cc45A4841c59a3de35a46289DFaEed49f547E", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "413", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "414", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "416", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeVault.sol:164" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "519", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "520", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "570", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeBlocklistVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol:115" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "0ff5d999e106bf4c771ff6f563556084d362dada730150c4b439f19a90a4b171": { - "address": "0x9A6102b03be3E64c98eB80Aa9D3187cAA17755f7", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "366", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "417", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "467", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "517", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "519", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "521", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "523", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "573", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol:194" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "5ae9b33c84254f85b3d5a5479f1c1c74498f20400518ab334668c138b2c65358": { - "address": "0xA0328cbb10F501755d841a8a4AD2a3Ac439103e8", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "366", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "417", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "467", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "517", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "519", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "521", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "523", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "573", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol:194" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "623", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "624", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "625", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "675", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakePrivErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol:138" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f56bd2b36948624c63b4f776ff43fb40366cca94d172e16bd6aa97a06f46038e": { - "address": "0x3919E9B0E3912eE7b72A1f1AF97d07f6dCFEFFea", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "366", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "417", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "467", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "517", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "519", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "521", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "523", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "573", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol:194" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "623", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "624", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "625", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "675", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol:138" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c4d95638bc41b2e31db47a011dff939c5007e00a6984eacb2d02468263a03623": { - "address": "0x2a0335fb13Cbf86A76A7f9D9d038389788667960", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f46aefa45733eec95152ef9130ff6d8ecda963332f9dbb728951fc4310865098": { - "address": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "8b9ae6b272bcf7e7052a0ebc5a29c862e33ce07b73eccaabb4ccf133e86f8be2": { - "address": "0x5518052f2d898f062ee59964004A560F24E2eE7d", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "cb5050f5dfb907f313b434ae1ddf364d787208be66584c6a7e2aff598d444940": { - "address": "0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "515a67f446d38d9440d58a85201fb95394fa5b47999a92c1d7643e358161d195": { - "address": "0xB48E508a78CAEF2325f8B813c153E81bc3Ed44f4", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:132" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c8331feb65390166f465cac78733e5d466e27659090a9dd35d2267e0935468b3": { - "address": "0x135f45e0179dd928E73422B40Bdc6C5d7047a035", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:137" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "b1a4bfcc92c9b94ae1207f347e3e12b15ec87a73accdaa80140a05a53208ce73": { - "address": "0x7E5198DF09fED891e7AecD623cD2231443cEb5d5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:298" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "adf60612d2944a421b7bd563850e0e9df36b4cb632a392b11f87fa4e91e0a14c": { - "address": "0x850fa495ED898067c35AC3E49504c0c4C19b0BD9", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "649dcac3b9d1d84b778c737a97e23be5694ed2b96717ee6796ab8d40743d528c": { - "address": "0x6D5957e075fd93b3B9F36Da93d7462F14387706d", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:123" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "e6cccb87a26ac2578137d87c2f2debaf23313d55de0cba928a3507327dd6b346": { - "address": "0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:123" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "852444e6af5ff8526bcf0baf860c645c02bba5ef81e5914772936a9fe6b76686": { - "address": "0x35B119c61B3Bb97f324423Ef5D3A82243daBb1B6", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c288bf232034b9c8f0ee1ba57ef8665032f9fe5aacc0399c7082d7bb94916db8": { - "address": "0xCCA9FE40f1653f87A6dC021E2E7E65f0D0429B8e", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:131" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "5ff2c8167318acc73e5d31224ee0b10fa62a6bbd8adbca6b9336ffa470a2ca66": { - "address": "0x3517FD486D275FD3A49128E50e67FFb24a537B26", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:136" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "708687ebf770b842537bbf54a7e8cc0b04fd2a39a792af8382a6fdd9f0cc9736": { - "address": "0x94fae7fe801E6Ab95F2A52F339E6EE1F1E222DEc", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:297" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - } - } -} diff --git a/.openzeppelin/mainnet.json b/.openzeppelin/mainnet.json deleted file mode 100644 index 46452577..00000000 --- a/.openzeppelin/mainnet.json +++ /dev/null @@ -1,15569 +0,0 @@ -{ - "manifestVersion": "3.2", - "proxies": [], - "impls": { - "bedf02c447fcfdfc53297b81213a2bd8b7ada5b9de387842ba1bbdfbbb967d30": { - "address": "0xba0B5ba961B108BFf8D761A256e9763a4FccFF23", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c9268f50f3d40ac94541ba336628311aa47be2aeb97ed6f83b56114cd5370533": { - "address": "0xB53a6c402b0d4fb6c7AA59B7d8FBD2e884FbF3bC", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:69" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:104" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f1938524cd5789e100890a394b6b15c04a119b2f0e2b5084536320129481d9e5": { - "address": "0x8EE00C149299DD1b051a7cA9cC2A7a1d706773DE", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "213", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "266", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "ee0d9cc78e578d54672d947f5dc3fde33bb3774d4bbd4f991e466f7c18044ce9": { - "address": "0x28F325dD287a5984B754d34CfCA38af3A8429e71", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "213", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "266", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:69" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:104" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "ded279c66e8b986ac9d6f27d3715248b1b0e931547e5b7f3dbef1da05a5c4a19": { - "address": "0x124C33d07F94B31aDF87C12F7cA3a586d3510928", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:241" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "2b55cd7649b671f125bccef8da8a004f02712557960cc324dd5186447320c036": { - "address": "0xAEaE7d602b537b2065f3dA05DCCE754fB23A968d", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11795_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:243" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "413", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "414", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "464", - "type": "t_array(t_uint256)50_storage", - "contract": "EthFoxVault", - "src": "contracts/vaults/ethereum/custom/EthFoxVault.sol:145" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)64_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)188_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11789_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11789_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11795_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11789_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - }, - "allAddresses": [ - "0xAEaE7d602b537b2065f3dA05DCCE754fB23A968d" - ] - }, - "9ca02fae8617864b4e190510546945f5644c01a2d3a8bce1bf4c8417ffc9fc88": { - "address": "0x35dC754f157b32Ba0941ffCD89d16d3D0B2cA6CF", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "94ba9080bb38996751ef33822ea8b287677c661a8dd606b5d18f01bbaf0968ef": { - "address": "0x81Ab00dD782492D62105B8fa9B03E82d4B57798C", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:120" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "bcac981f3eac378bac1555068e4e36855dd4f9adcb4223d22dfc4b5473342fc8": { - "address": "0x00e3af59e2496d030E5B2c629784Db284FD4CD3c", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:115" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "a6a5eba566ccbeb693dc796d635ada13d770b87c0f3d60760a48101e3c2c7cc8": { - "address": "0xca866585EcFdfCc98348ef2717B811626ED98207", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f252e07f924e8fb49426a13662666675850d7ede9061956d7dbcdd2982f10163": { - "address": "0xF5F20572186d2FAB233dADD753C053ab581ba69A", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:128" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "707cb34cab3dcab48860275645109fa4f334610c79f19a22bc5a66789945bd14": { - "address": "0xc25529B4ee01cc6262146433B6509E9e6e30F14a", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:128" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "29c45bd405954f999d8061490d794c15d11be5e8ebb920de0782240f1ee2a4d4": { - "address": "0x2D491bb32610A0ef1DE017e49f949b3799135F31", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:264" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "43d482d729f9b08993092c2f16e54cf5c30ff737ee5b87940a6ed26be1d1132a": { - "address": "0x3573a482D0e50f85F6B09E4DB404Ce94Da760033", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "vault", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "EigenPodOwner", - "src": "contracts/vaults/ethereum/restake/EigenPodOwner.sol:37" - }, - { - "label": "eigenPod", - "offset": 0, - "slot": "1", - "type": "t_address", - "contract": "EigenPodOwner", - "src": "contracts/vaults/ethereum/restake/EigenPodOwner.sol:41" - }, - { - "label": "__gap", - "offset": 0, - "slot": "2", - "type": "t_array(t_uint256)50_storage", - "contract": "EigenPodOwner", - "src": "contracts/vaults/ethereum/restake/EigenPodOwner.sol:244" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "33ef1e5bcece4588ca49909a1e62f1856a9792ff62d9b9697f1e2c50bf472ead": { - "address": "0x59ADB46407EBF4cba923f91F2C06acc4b2e073Bb", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "413", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "414", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "416", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeVault.sol:164" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "3155fa122df9656b0ad6d4d56556fe7dd9d725edb2d15be3a311a0c1fc4408fb": { - "address": "0x792ff341e1dB4AB20FbFB93c0fC071501525E353", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "413", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "414", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "416", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeVault.sol:164" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "519", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "520", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "570", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakePrivVault", - "src": "contracts/vaults/ethereum/restake/EthRestakePrivVault.sol:118" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "cf2b7edce53a45f377d52309fa733896af9d169bd68e5cbcf1ff8aae7bd19667": { - "address": "0x3e30370cabD4B4D95Be17706D840FF9de1ADdb67", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "413", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "414", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "416", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeVault.sol:164" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "519", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "520", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "570", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeBlocklistVault", - "src": "contracts/vaults/ethereum/restake/EthRestakeBlocklistVault.sol:115" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "d6464aeddce81de66f0d6fda07c7a0114683cde7f7b6e578cc24f1c28f351cf1": { - "address": "0x215f4c69c3d1461c7aA38c9c73c27e10cFB0eeE4", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "366", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "417", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "467", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "517", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "519", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "521", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "523", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "573", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol:194" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "8d97257a5225ec294dd9b8d75fba9f2dbc32e1005101df6a16bcbaef2441ccd0": { - "address": "0xedeBE792C6190Be612Cbe97F628137fAa8C36ee5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "366", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "417", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "467", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "517", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "519", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "521", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "523", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "573", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol:194" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "623", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "624", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "625", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "675", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakePrivErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakePrivErc20Vault.sol:138" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "cb0f128f633bece7c6cb6c6bafe0aa0116930d23d50a0df0c6290e5c45a0dff0": { - "address": "0x5FCd8Bb2e3DDE5809b2106039B741C041bd49E4e", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "366", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "417", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "467", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "_restakeOperatorsManager", - "offset": 0, - "slot": "517", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:25" - }, - { - "label": "_restakeWithdrawalsManager", - "offset": 0, - "slot": "518", - "type": "t_address", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:26" - }, - { - "label": "_eigenPods", - "offset": 0, - "slot": "519", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:28" - }, - { - "label": "_eigenPodOwners", - "offset": 0, - "slot": "521", - "type": "t_struct(AddressSet)8377_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "523", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthRestaking", - "src": "contracts/vaults/modules/VaultEthRestaking.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "573", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeErc20Vault.sol:194" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "623", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "624", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "625", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "675", - "type": "t_array(t_uint256)50_storage", - "contract": "EthRestakeBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/restake/EthRestakeBlocklistErc20Vault.sol:138" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_bytes32)dyn_storage": { - "label": "bytes32[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(AddressSet)8377_storage": { - "label": "struct EnumerableSet.AddressSet", - "members": [ - { - "label": "_inner", - "type": "t_struct(Set)8062_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "64" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Set)8062_storage": { - "label": "struct EnumerableSet.Set", - "members": [ - { - "label": "_values", - "type": "t_array(t_bytes32)dyn_storage", - "offset": 0, - "slot": "0" - }, - { - "label": "_positions", - "type": "t_mapping(t_bytes32,t_uint256)", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "b49d283a0cad85d4859305a8f2f4c5a4f23f74d589964af0eab663521d376c92": { - "address": "0x9747e1fF73f1759217AFD212Dd36d21360D0880A", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c247f5a367fa50db2d04e9bbd539ca229249ec451665e5066784a2974b1d7a1d": { - "address": "0xfe076029B7D46fbe2ad4B9CBf377aA10B309e560", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "3f8fae094e3af0cdef2a0b1a32d5399dc6351991f486c428e4e70e20c5d62455": { - "address": "0xF2f5A23f849e02001da0DfdeC0F4CD3c3a79337e", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "982c27153c11201eb2d09646f5ed95471483d2e6796c462f960913777fdf92e2": { - "address": "0xC68FFbF358D6Ba32Ac86C7bE6cd037fbD15D0D46", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "1db15294ea69bcd819d6c810293630b6c8d311845c90065debea4e44aad17823": { - "address": "0x8638068a8C0440595cb5a29D245c6ec79d54A09c", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:132" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "5a06d80c07fe9b148f32eb06fa12a9de9745b0fdda4ffea00a20e4da25fa5bdd": { - "address": "0x9D2fb07c3D04f54b332b43dAa9dA982163Ba0775", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:137" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "53136cb358ba6ac20a68a0206822724af4b6fdcfc58f6a240fabd2894adba970": { - "address": "0x64375C9A7305edb7bbA757319AA4C20e6000bB8c", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:298" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "2927087c532b7ac390c83f626cddcf98241837d5bf701b14d206836be9d0d1af": { - "address": "0xDecb606ee9140f229Df78F9E40041EAD61610F8f", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "febaeaa21f64e343ef06e4ecd3fc2da322cfcbf8ba377c981be7e7417da22dc6": { - "address": "0x135f45e0179dd928E73422B40Bdc6C5d7047a035", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:123" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c1ee6926ccebe26923c62bf14f0bca2a2c06f683e994b338519a9269c17d0a71": { - "address": "0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:123" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "7b8e8cfeaf029da595bd775f84f16be9f248840e8e460e93bb443f25ad26c394": { - "address": "0x7E5198DF09fED891e7AecD623cD2231443cEb5d5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "5bead74e866723ec4f4b10c8e4d13df40075f90d9bae638c914e1337748a8ee8": { - "address": "0x9488A7dd178F0D927707eEc61A7D8C0ae9558c88", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:131" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "9e0f6b457b03e3891768dd50c4f0092fb9511ec6aa2c30f106b99ec577e0a635": { - "address": "0x84d44A696539B3eF4162184fb8ab97596A311e9E", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:136" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "e9b1a88911a1b226e4e2b07590e423bba65da07c60a547498e142479f66902f6": { - "address": "0x9481A47c5650A868839c6511f0Eef8bF962FABD7", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:297" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - } - } -} diff --git a/.openzeppelin/unknown-100.json b/.openzeppelin/unknown-100.json deleted file mode 100644 index c8d96224..00000000 --- a/.openzeppelin/unknown-100.json +++ /dev/null @@ -1,3896 +0,0 @@ -{ - "manifestVersion": "3.2", - "proxies": [], - "impls": { - "2bacb694bc8fa84bc703920b1ca965d776d796d745a96228bbd2c047eb7f766e": { - "address": "0x96FFf3A26b29bF7700dBB475730B373AFeE175Ee", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "balancerPoolId", - "offset": 0, - "slot": "0", - "type": "t_bytes32", - "contract": "XdaiExchange", - "src": "contracts/misc/XdaiExchange.sol:50" - }, - { - "label": "maxSlippage", - "offset": 0, - "slot": "1", - "type": "t_uint128", - "contract": "XdaiExchange", - "src": "contracts/misc/XdaiExchange.sol:53" - }, - { - "label": "stalePriceTimeDelta", - "offset": 16, - "slot": "1", - "type": "t_uint128", - "contract": "XdaiExchange", - "src": "contracts/misc/XdaiExchange.sol:56" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Ownable2StepStorage)14_storage": { - "label": "struct Ownable2StepUpgradeable.Ownable2StepStorage", - "members": [ - { - "label": "_pendingOwner", - "type": "t_address", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OwnableStorage)55_storage": { - "label": "struct OwnableUpgradeable.OwnableStorage", - "members": [ - { - "label": "_owner", - "type": "t_address", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.Ownable2Step": [ - { - "contract": "Ownable2StepUpgradeable", - "label": "_pendingOwner", - "type": "t_address", - "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:23", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Ownable": [ - { - "contract": "OwnableUpgradeable", - "label": "_owner", - "type": "t_address", - "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:24", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "bdd30d818ce6c8ab77e00d89b96e54f92f3949ff8440e4ebac109058ec24e3d3": { - "address": "0x00c3C5227402BC4cF383Ae2E6931394dD1e720B4", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "8638cafde9c272e3f5bd4a9d07f5f2dfb2b608fb737640a640f569d13eb408b4": { - "address": "0xb1eB5e946A8B580eF46b4B6b4Cd26abe80C01C2C", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoPrivVault", - "src": "contracts/vaults/gnosis/GnoPrivVault.sol:116" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "72bb9daa74240c05f3d63243d06d380e3a8885e6a0189271cd48f73b03f3e29f": { - "address": "0x6C9d30800C8ABb6CcfB214ECff4b28EfE275E89E", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoBlocklistVault", - "src": "contracts/vaults/gnosis/GnoBlocklistVault.sol:116" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "a45ec20d356a30d71db3211fa306c2eac93f8ff0a6d29d1a97d95a21fdb3d10f": { - "address": "0x8C512Fc12Bd55A074444cE3E0b2e1dD0638b1DBA", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoErc20Vault", - "src": "contracts/vaults/gnosis/GnoErc20Vault.sol:190" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "4b2d30e220a984e28ba0ce427c1b21fe23eefb77373c2c5ae3eaa600ff6f1e24": { - "address": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoErc20Vault", - "src": "contracts/vaults/gnosis/GnoErc20Vault.sol:190" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoPrivErc20Vault", - "src": "contracts/vaults/gnosis/GnoPrivErc20Vault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "59dc64d9f1349ba6b6e9b15af175a69eddfae4b6a430f8d16c2ed9d31e57420a": { - "address": "0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoErc20Vault", - "src": "contracts/vaults/gnosis/GnoErc20Vault.sol:190" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoBlocklistErc20Vault", - "src": "contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol:129" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "2ea79dd914c3f2ba432a77e2d822e022b8081ce9d5a81eac77a13f827bd4dcf5": { - "address": "0x42Aebbc34555E7D3249481305aBe206E80C01C49", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoGenesisVault", - "src": "contracts/vaults/gnosis/GnoGenesisVault.sol:229" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "fb84fa3d440720f5dc9c584e769141149097024e470dbd787763dcbceb6dca02": { - "address": "0x5f9ee59Ad0ECb38A2F584956286311796fED12C6", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoGenesisVault", - "src": "contracts/vaults/gnosis/GnoGenesisVault.sol:233" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - } - } -} diff --git a/.openzeppelin/unknown-10200.json b/.openzeppelin/unknown-10200.json deleted file mode 100644 index 72e826c4..00000000 --- a/.openzeppelin/unknown-10200.json +++ /dev/null @@ -1,3896 +0,0 @@ -{ - "manifestVersion": "3.2", - "proxies": [], - "impls": { - "4254aae6a7368e5cf45284c238d50ea6d671e8c6f2cf6ffb2d9f168c15ef226c": { - "address": "0xCCA9FE40f1653f87A6dC021E2E7E65f0D0429B8e", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "balancerPoolId", - "offset": 0, - "slot": "0", - "type": "t_bytes32", - "contract": "XdaiExchange", - "src": "contracts/misc/XdaiExchange.sol:50" - }, - { - "label": "maxSlippage", - "offset": 0, - "slot": "1", - "type": "t_uint128", - "contract": "XdaiExchange", - "src": "contracts/misc/XdaiExchange.sol:53" - }, - { - "label": "stalePriceTimeDelta", - "offset": 16, - "slot": "1", - "type": "t_uint128", - "contract": "XdaiExchange", - "src": "contracts/misc/XdaiExchange.sol:56" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(Ownable2StepStorage)14_storage": { - "label": "struct Ownable2StepUpgradeable.Ownable2StepStorage", - "members": [ - { - "label": "_pendingOwner", - "type": "t_address", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OwnableStorage)55_storage": { - "label": "struct OwnableUpgradeable.OwnableStorage", - "members": [ - { - "label": "_owner", - "type": "t_address", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.Ownable2Step": [ - { - "contract": "Ownable2StepUpgradeable", - "label": "_pendingOwner", - "type": "t_address", - "src": "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol:23", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Ownable": [ - { - "contract": "OwnableUpgradeable", - "label": "_owner", - "type": "t_address", - "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:24", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "40bcd6a9f6812ada84bca0061f792aa9e75b0c8598f3eaebefdf10b1f3b3f4a0": { - "address": "0x94fae7fe801E6Ab95F2A52F339E6EE1F1E222DEc", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f41792aa964d386c6d0a92487712e1d86a8378ab880b25d200ddc4d7f14ca36e": { - "address": "0xd49e39C2b2510091C09A93d025CA9E0088D39A95", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoPrivVault", - "src": "contracts/vaults/gnosis/GnoPrivVault.sol:116" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "485f195d39d3bc01aba34850216d520741da54af0c122c95000d156257d29c65": { - "address": "0x346ae6c763F517Dab4ab67563bEa043d922D644d", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoBlocklistVault", - "src": "contracts/vaults/gnosis/GnoBlocklistVault.sol:116" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "073a5fa62cd900f0d890ed8af0f7b0ebd43366ae084c344c28f411739abed8b1": { - "address": "0x3E2282ec7d94B7Ff4D06fBf96044887090CB4958", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoErc20Vault", - "src": "contracts/vaults/gnosis/GnoErc20Vault.sol:190" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "963b20f093e5d1ab15e61a5d58e6f2b6bce43536d2be87e6a7407f0f548b6af1": { - "address": "0x3E27B69CC92Ee7cE638cA8c2A1875dD03FF742B2", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoErc20Vault", - "src": "contracts/vaults/gnosis/GnoErc20Vault.sol:190" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoPrivErc20Vault", - "src": "contracts/vaults/gnosis/GnoPrivErc20Vault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "4039e3cd4edb8805c226bb350b587f85126e05315d2563e53d4fd3b008efaf40": { - "address": "0x180231ae09a527656741501F2F7B840A46Cc2816", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoErc20Vault", - "src": "contracts/vaults/gnosis/GnoErc20Vault.sol:190" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoBlocklistErc20Vault", - "src": "contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol:129" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "3fbed199cd7fbf508419a68f3fe0c5cd42109a9cf21c43744dfbee43b33c728a": { - "address": "0x2d69aD8523d1D54970aBb9ABce45762e1D477E03", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoGenesisVault", - "src": "contracts/vaults/gnosis/GnoGenesisVault.sol:229" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "3c077bb04c0450635865be5e5a4779f71caae84a44a8f9a09f4232320971d58a": { - "address": "0x2e27110bA825dF484bC7b0Ea9F0C50D276583F12", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultGnoStaking", - "src": "contracts/vaults/modules/VaultGnoStaking.sol:202" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoVault", - "src": "contracts/vaults/gnosis/GnoVault.sol:138" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "GnoGenesisVault", - "src": "contracts/vaults/gnosis/GnoGenesisVault.sol:233" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - } - } -} diff --git a/.openzeppelin/unknown-560048.json b/.openzeppelin/unknown-560048.json deleted file mode 100644 index bf8bf983..00000000 --- a/.openzeppelin/unknown-560048.json +++ /dev/null @@ -1,12394 +0,0 @@ -{ - "manifestVersion": "3.2", - "proxies": [], - "impls": { - "276380239a8703a10aa03afde862b5ae86f7a4d1709f20dc1381d9ccc4d72e76": { - "address": "0x16c35CC583b35c301D1884D4cdFb6e06A2dF45f2", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "67ebb0a156674a06e0516fed634b8deb7ee072ac2b4a2b3aca86e9b1a3a240d6": { - "address": "0x3c4ae629bf823475192124E02b9879D3C1fd4538", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:69" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:104" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "4155fcddea6e92a813cd4b072ef9dd9f3c13a77452c463cfb01f768f21f2386c": { - "address": "0xdeCC5732c21be460017FEE770022A34ac291f3CC", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "213", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "266", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "325b626d76800db58b2f2dcbf4805624ec5d83c98f3b92c63416c425a7816420": { - "address": "0x7571Bda0eB8028419f7b195230E966D42a27A005", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "213", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "266", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:196" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:69" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:104" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "4068b882d4fa3f1df7923f801ac7a2c41f0855df3160e328b62bfa285fafb50a": { - "address": "0x2CBF6995d5cd13744e91Cae01B5B2bAF19b6B94d", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11653_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:212" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:313" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:142" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:241" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)45_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)101_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11647_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)9945_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11647_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11653_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11647_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)9945_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "abf4d6d9349b3c6b6cbaf813f1615c8857e77679edf711ebc27d46fc62efdecd": { - "address": "0xd57c19f20168406d162852515030e00e49bB7781", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:48" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)11795_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:30" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "158", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:268" - }, - { - "label": "validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:29" - }, - { - "label": "validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:32" - }, - { - "label": "_keysManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:34" - }, - { - "label": "__gap", - "offset": 0, - "slot": "211", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:199" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:243" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "311", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "362", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:153" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "412", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "413", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "414", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "464", - "type": "t_array(t_uint256)50_storage", - "contract": "EthFoxVault", - "src": "contracts/vaults/ethereum/custom/EthFoxVault.sol:145" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)64_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)188_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)11789_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)11789_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)11795_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)11789_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - }, - "allAddresses": [ - "0xd57c19f20168406d162852515030e00e49bB7781", - "0xcf28acEF84c2279873Fc4bc02029123a3739e60b" - ] - }, - "e2810c87d956a41326a89cb41ca3e96534786393fd9f63b050fc293ee52bce8f": { - "address": "0xFe974c6502E59d760B3a27e6D5a4315DC668d716", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "1835a32672daa763d92d447cf5eb450cfae3b06b9fa73d08ee4ea6d35947a4a1": { - "address": "0x3BEc3c1cf81A1176c12550B4315bdd53A2B4Fd5D", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:120" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "fcbcf8e057b337dfe10014f3fa9cd62a20003755f328d48a423c8872e8c20ed1": { - "address": "0xD506fE0B3dDF9e685C16E000514a835D3a511b26", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:115" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "b1e262b3be8e8fc964972e9c48d810a83ee9a5156f1806f16ea45b3f0d0dd876": { - "address": "0x0C2eC14603Ad9c14a820ad0C91122210Ab84A9e5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "320fbb484ce92bccaf4ff85a86beeb8da0f5b6d7664e1f6db06fd2df87907dcd": { - "address": "0x60CE7c5547Ada69042Df8aC4f40B74ED0031E90d", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:128" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c3ef2951989f1c1b60d210d887b9f9af92c43cdf79596955e434e2bfb3e94c61": { - "address": "0x028DbA0cA8C761C7831fA0A681b8B61bA04ce939", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:227" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:128" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c2774cbb16a5c2235092a7c2aed838ebdbf064fb10300823b4fddfa548678550": { - "address": "0xBe89b8a90018f1bD458803e713575287E23CA04a", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14077_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:331" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:228" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:270" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:32" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:296" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:175" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:264" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)105_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)229_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14071_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12309_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14071_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14077_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14071_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12309_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "530b5b57509b99022a4edb5165c3480290bb0d15dff8572473d32ab3a99a5dc3": { - "address": "0x2B3Fd45831BBe53230a5f7E068ca75cd2a8DfaF3", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "3841f1064bf286d24700aaa0510af6ddc2ac7f2b7508a4829f743b84a6bdb8f3": { - "address": "0xc43A7b16A7a167c0318390Cba16787C11e9e1FD0", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c291e7de6aa4ed44b6abd963714442c31d5c6276b4c60e5356941f0d59a1b814": { - "address": "0x3cc1bde89640E0D32b2D2D66D3098d9Bc11b17Ee", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:124" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "b9b55735d238ae0309e8be4150ed268fa5cccd589d97741fbbc4f343c37b4b24": { - "address": "0xfc81D3369fBEAa6E0926eedA71E5C91724f2c079", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "417427cee50fe0558a4226b7ff573a50d4ba39091344ad29a7642437b97b484b": { - "address": "0xD935a9f586dFa83Df20553b40Ce24f3746b258E2", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:132" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "59a5c0fa78da9c59cd2bbb95c024be83447f68cc4419929395ec663916970474": { - "address": "0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:226" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:137" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "3349c7ddbf2d19e1d6462fb4321bb521c6692293b30d7457d68092f3bf76365a": { - "address": "0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)14418_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:173" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:298" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)14412_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)12646_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)14412_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)14418_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)14412_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)12646_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:40", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "b4791db8afac621222d022e3bd4d4f016abfc4d7aca4807fb6174fa42bbceeab": { - "address": "0xeBF52C2d940F46f2dbFB4982447D15cf589711AD", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "f9daa7652b8e2ae1be69802ce9ab4df0b22668605885c3ce36ae44bd8ac9068f": { - "address": "0x3F2c0a621369fc54f6DeEC6C9534e980fd2E98d5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivVault", - "src": "contracts/vaults/ethereum/EthPrivVault.sol:123" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "b884e823d94cb3da62e28a6bdde4ceff771fceac639195abdca4487c4938e570": { - "address": "0x70E1238e3eb4bda45C0E93e114bD5C7d9c512126", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "513", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "514", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "515", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "565", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistVault", - "src": "contracts/vaults/ethereum/EthBlocklistVault.sol:123" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "8f6fcae43d0254af70196968374a7c5c74f991dfae51ff576c497844658c73de": { - "address": "0xE51eE4200510498d5964627B25FE7D4685CB858c", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "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(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "9f4b1e57e47e2924962c6d5802991805bcff854ae0213a0eb411cf667e0906d9": { - "address": "0x42427acFf6DdC93f73Fcb53d1a03AA26A292bA1A", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - }, - { - "label": "whitelister", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:17" - }, - { - "label": "whitelistedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultWhitelist", - "src": "contracts/vaults/modules/VaultWhitelist.sol:67" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthPrivErc20Vault", - "src": "contracts/vaults/ethereum/EthPrivErc20Vault.sol:131" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "c7313f2b7fa8046ce5816b81d7d3f1ebb209fdba5a1a1fa567af3d09eed60dcb": { - "address": "0xCd191DfDF52ae7aa2B1AD7B4a6A9D4d4FFB837B5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "name", - "offset": 0, - "slot": "0", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:21" - }, - { - "label": "symbol", - "offset": 0, - "slot": "1", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:24" - }, - { - "label": "allowance", - "offset": 0, - "slot": "2", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:30" - }, - { - "label": "nonces", - "offset": 0, - "slot": "3", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:33" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "4", - "type": "t_bytes32", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "5", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC20Upgradeable", - "src": "contracts/base/ERC20Upgradeable.sol:173" - }, - { - "label": "admin", - "offset": 0, - "slot": "55", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "106", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "156", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "156", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "157", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "207", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "208", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "209", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "210", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "211", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "212", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "213", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "214", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "215", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "263", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "264", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "265", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "266", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "267", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "316", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "366", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "367", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "417", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "418", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "468", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultToken", - "src": "contracts/vaults/modules/VaultToken.sol:76" - }, - { - "label": "__gap", - "offset": 0, - "slot": "518", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "568", - "type": "t_array(t_uint256)50_storage", - "contract": "EthErc20Vault", - "src": "contracts/vaults/ethereum/EthErc20Vault.sol:217" - }, - { - "label": "blocklistManager", - "offset": 0, - "slot": "618", - "type": "t_address", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:17" - }, - { - "label": "blockedAccounts", - "offset": 0, - "slot": "619", - "type": "t_mapping(t_address,t_bool)", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "620", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultBlocklist", - "src": "contracts/vaults/modules/VaultBlocklist.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "670", - "type": "t_array(t_uint256)50_storage", - "contract": "EthBlocklistErc20Vault", - "src": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol:136" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "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(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - }, - "779ee9708dbbc090754973d832c1d5c372f65cf7d46993746ba6208fb8013ad0": { - "address": "0x8f347eb308707DC1FA1acCF3ea889CF554b6B8A5", - "layout": { - "solcVersion": "0.8.22", - "storage": [ - { - "label": "admin", - "offset": 0, - "slot": "0", - "type": "t_address", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:16" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultAdmin", - "src": "contracts/vaults/modules/VaultAdmin.sol:49" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultVersion", - "src": "contracts/vaults/modules/VaultVersion.sol:66" - }, - { - "label": "feeRecipient", - "offset": 0, - "slot": "101", - "type": "t_address", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:21" - }, - { - "label": "feePercent", - "offset": 20, - "slot": "101", - "type": "t_uint16", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:24" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultFee", - "src": "contracts/vaults/modules/VaultFee.sol:62" - }, - { - "label": "_totalShares", - "offset": 0, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:23" - }, - { - "label": "_totalAssets", - "offset": 16, - "slot": "152", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:24" - }, - { - "label": "queuedShares", - "offset": 0, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:27" - }, - { - "label": "_unclaimedAssets", - "offset": 16, - "slot": "153", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:28" - }, - { - "label": "_exitQueue", - "offset": 0, - "slot": "154", - "type": "t_struct(History)17288_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:29" - }, - { - "label": "_exitRequests", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:31" - }, - { - "label": "_balances", - "offset": 0, - "slot": "156", - "type": "t_mapping(t_address,t_uint256)", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:32" - }, - { - "label": "_capacity", - "offset": 0, - "slot": "157", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:34" - }, - { - "label": "totalExitingAssets", - "offset": 0, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:37" - }, - { - "label": "_totalExitingTickets", - "offset": 16, - "slot": "158", - "type": "t_uint128", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:38" - }, - { - "label": "_totalExitedTickets", - "offset": 0, - "slot": "159", - "type": "t_uint256", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:39" - }, - { - "label": "__gap", - "offset": 0, - "slot": "160", - "type": "t_array(t_uint256)48_storage", - "contract": "VaultState", - "src": "contracts/vaults/modules/VaultState.sol:353" - }, - { - "label": "_validatorsRoot", - "offset": 0, - "slot": "208", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:39" - }, - { - "label": "_validatorIndex", - "offset": 0, - "slot": "209", - "type": "t_uint256", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:42" - }, - { - "label": "_validatorsManager", - "offset": 0, - "slot": "210", - "type": "t_address", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:44" - }, - { - "label": "_initialDomainSeparator", - "offset": 0, - "slot": "211", - "type": "t_bytes32", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:46" - }, - { - "label": "__gap", - "offset": 0, - "slot": "212", - "type": "t_array(t_uint256)49_storage", - "contract": "VaultValidators", - "src": "contracts/vaults/modules/VaultValidators.sol:239" - }, - { - "label": "__gap", - "offset": 0, - "slot": "261", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEnterExit", - "src": "contracts/vaults/modules/VaultEnterExit.sol:219" - }, - { - "label": "_positions", - "offset": 0, - "slot": "311", - "type": "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "312", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultOsToken", - "src": "contracts/vaults/modules/VaultOsToken.sol:375" - }, - { - "label": "_ownMevEscrow", - "offset": 0, - "slot": "362", - "type": "t_address", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:20" - }, - { - "label": "__gap", - "offset": 0, - "slot": "363", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultMev", - "src": "contracts/vaults/modules/VaultMev.sol:77" - }, - { - "label": "__gap", - "offset": 0, - "slot": "413", - "type": "t_array(t_uint256)50_storage", - "contract": "VaultEthStaking", - "src": "contracts/vaults/modules/VaultEthStaking.sol:152" - }, - { - "label": "__gap", - "offset": 0, - "slot": "463", - "type": "t_array(t_uint256)50_storage", - "contract": "EthVault", - "src": "contracts/vaults/ethereum/EthVault.sol:164" - }, - { - "label": "__gap", - "offset": 0, - "slot": "513", - "type": "t_array(t_uint256)50_storage", - "contract": "EthGenesisVault", - "src": "contracts/vaults/ethereum/EthGenesisVault.sol:297" - } - ], - "types": { - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_struct(InitializableStorage)128_storage": { - "label": "struct Initializable.InitializableStorage", - "members": [ - { - "label": "_initialized", - "type": "t_uint64", - "offset": 0, - "slot": "0" - }, - { - "label": "_initializing", - "type": "t_bool", - "offset": 8, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(ReentrancyGuardStorage)276_storage": { - "label": "struct ReentrancyGuardUpgradeable.ReentrancyGuardStorage", - "members": [ - { - "label": "_status", - "type": "t_uint256", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "label": "uint64", - "numberOfBytes": "8" - }, - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(Checkpoint)17282_storage)dyn_storage": { - "label": "struct ExitQueue.Checkpoint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)48_storage": { - "label": "uint256[48]", - "numberOfBytes": "1536" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_struct(OsTokenPosition)15516_storage)": { - "label": "mapping(address => struct IVaultOsToken.OsTokenPosition)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_uint256)": { - "label": "mapping(bytes32 => uint256)", - "numberOfBytes": "32" - }, - "t_struct(Checkpoint)17282_storage": { - "label": "struct ExitQueue.Checkpoint", - "members": [ - { - "label": "totalTickets", - "type": "t_uint160", - "offset": 0, - "slot": "0" - }, - { - "label": "exitedAssets", - "type": "t_uint96", - "offset": 20, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(History)17288_storage": { - "label": "struct ExitQueue.History", - "members": [ - { - "label": "checkpoints", - "type": "t_array(t_struct(Checkpoint)17282_storage)dyn_storage", - "offset": 0, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_struct(OsTokenPosition)15516_storage": { - "label": "struct IVaultOsToken.OsTokenPosition", - "members": [ - { - "label": "shares", - "type": "t_uint128", - "offset": 0, - "slot": "0" - }, - { - "label": "cumulativeFeePerShare", - "type": "t_uint128", - "offset": 16, - "slot": "0" - } - ], - "numberOfBytes": "32" - }, - "t_uint128": { - "label": "uint128", - "numberOfBytes": "16" - }, - "t_uint16": { - "label": "uint16", - "numberOfBytes": "2" - }, - "t_uint160": { - "label": "uint160", - "numberOfBytes": "20" - }, - "t_uint96": { - "label": "uint96", - "numberOfBytes": "12" - } - }, - "namespaces": { - "erc7201:openzeppelin.storage.ReentrancyGuard": [ - { - "contract": "ReentrancyGuardUpgradeable", - "label": "_status", - "type": "t_uint256", - "src": "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol:43", - "offset": 0, - "slot": "0" - } - ], - "erc7201:openzeppelin.storage.Initializable": [ - { - "contract": "Initializable", - "label": "_initialized", - "type": "t_uint64", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", - "offset": 0, - "slot": "0" - }, - { - "contract": "Initializable", - "label": "_initializing", - "type": "t_bool", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", - "offset": 8, - "slot": "0" - } - ] - } - } - } - } -} diff --git a/.solcover.js b/.solcover.js deleted file mode 100644 index 24820fe4..00000000 --- a/.solcover.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - skipFiles: ['/interfaces', '/mocks'], -} diff --git a/abi/Errors.json b/abi/Errors.json deleted file mode 100644 index cf8739e4..00000000 --- a/abi/Errors.json +++ /dev/null @@ -1,232 +0,0 @@ -[ - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [], - "name": "AlreadyAdded", - "type": "error" - }, - { - "inputs": [], - "name": "AlreadyRemoved", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FlashLoanFailed", - "type": "error" - }, - { - "inputs": [], - "name": "HarvestFailed", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAvgRewardPerSecond", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidLiqBonusPercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidLiqThresholdPercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidLtvPercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidOracle", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidOracles", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidProof", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidRewardsRoot", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSignatures", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidatorsRegistryRoot", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidVault", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidWithdrawalCredentialsPrefix", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MaxOraclesExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotEnoughSignatures", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "TooEarlyUpdate", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ValueNotChanged", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - } -] diff --git a/abi/IBalancerRateProvider.json b/abi/IBalancerRateProvider.json deleted file mode 100644 index 6ef7bf65..00000000 --- a/abi/IBalancerRateProvider.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "inputs": [], - "name": "getRate", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IBalancerVault.json b/abi/IBalancerVault.json deleted file mode 100644 index 422eda57..00000000 --- a/abi/IBalancerVault.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - }, - { - "internalType": "enum IBalancerVault.SwapKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "address", - "name": "assetIn", - "type": "address" - }, - { - "internalType": "address", - "name": "assetOut", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "internalType": "struct IBalancerVault.SingleSwap", - "name": "singleSwap", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "bool", - "name": "fromInternalBalance", - "type": "bool" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - }, - { - "internalType": "bool", - "name": "toInternalBalance", - "type": "bool" - } - ], - "internalType": "struct IBalancerVault.FundManagement", - "name": "funds", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "limit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swap", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - } -] diff --git a/abi/IChainlinkAggregator.json b/abi/IChainlinkAggregator.json deleted file mode 100644 index 4d9cc0e6..00000000 --- a/abi/IChainlinkAggregator.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "inputs": [], - "name": "latestAnswer", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "latestTimestamp", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IChainlinkV3Aggregator.json b/abi/IChainlinkV3Aggregator.json deleted file mode 100644 index b34166d3..00000000 --- a/abi/IChainlinkV3Aggregator.json +++ /dev/null @@ -1,74 +0,0 @@ -[ - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "description", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "latestRoundData", - "outputs": [ - { - "internalType": "uint80", - "name": "roundId", - "type": "uint80" - }, - { - "internalType": "int256", - "name": "answer", - "type": "int256" - }, - { - "internalType": "uint256", - "name": "startedAt", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "updatedAt", - "type": "uint256" - }, - { - "internalType": "uint80", - "name": "answeredInRound", - "type": "uint80" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IConsolidationsChecker.json b/abi/IConsolidationsChecker.json deleted file mode 100644 index f81f2150..00000000 --- a/abi/IConsolidationsChecker.json +++ /dev/null @@ -1,103 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "name": "isValidSignatures", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "name": "verifySignatures", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IDepositDataRegistry.json b/abi/IDepositDataRegistry.json deleted file mode 100644 index dbc2a33a..00000000 --- a/abi/IDepositDataRegistry.json +++ /dev/null @@ -1,356 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "depositDataManager", - "type": "address" - } - ], - "name": "DepositDataManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "depositDataRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "validatorIndex", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "depositDataManager", - "type": "address" - } - ], - "name": "DepositDataMigrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "depositDataRoot", - "type": "bytes32" - } - ], - "name": "DepositDataRootUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "depositDataIndexes", - "outputs": [ - { - "internalType": "uint256", - "name": "validatorIndex", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "depositDataRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "depositDataRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "getDepositDataManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "depositDataRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "validatorIndex", - "type": "uint256" - }, - { - "internalType": "address", - "name": "depositDataManager", - "type": "address" - } - ], - "name": "migrate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "name": "registerValidator", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "uint256[]", - "name": "indexes", - "type": "uint256[]" - }, - { - "internalType": "bool[]", - "name": "proofFlags", - "type": "bool[]" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataManager", - "type": "address" - } - ], - "name": "setDepositDataManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "depositDataRoot", - "type": "bytes32" - } - ], - "name": "setDepositDataRoot", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateVaultState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IERC1155Errors.json b/abi/IERC1155Errors.json deleted file mode 100644 index f2d2b1dc..00000000 --- a/abi/IERC1155Errors.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ERC1155InsufficientBalance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC1155InvalidApprover", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "idsLength", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "valuesLength", - "type": "uint256" - } - ], - "name": "ERC1155InvalidArrayLength", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "ERC1155InvalidOperator", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC1155InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC1155InvalidSender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ERC1155MissingApprovalForAll", - "type": "error" - } -] diff --git a/abi/IERC1271.json b/abi/IERC1271.json deleted file mode 100644 index bebcf03b..00000000 --- a/abi/IERC1271.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "isValidSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "magicValue", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IERC1363.json b/abi/IERC1363.json deleted file mode 100644 index af4691b3..00000000 --- a/abi/IERC1363.json +++ /dev/null @@ -1,373 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approveAndCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "approveAndCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferAndCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "transferAndCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "transferFromAndCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFromAndCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IERC1822Proxiable.json b/abi/IERC1822Proxiable.json deleted file mode 100644 index b1a67dc5..00000000 --- a/abi/IERC1822Proxiable.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IERC1967.json b/abi/IERC1967.json deleted file mode 100644 index 0855e48e..00000000 --- a/abi/IERC1967.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - } -] diff --git a/abi/IERC20Errors.json b/abi/IERC20Errors.json deleted file mode 100644 index d2e35dd4..00000000 --- a/abi/IERC20Errors.json +++ /dev/null @@ -1,88 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "allowance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientAllowance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientBalance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC20InvalidApprover", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC20InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC20InvalidSender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "ERC20InvalidSpender", - "type": "error" - } -] diff --git a/abi/IERC5267.json b/abi/IERC5267.json deleted file mode 100644 index ae7ca785..00000000 --- a/abi/IERC5267.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IERC721Errors.json b/abi/IERC721Errors.json deleted file mode 100644 index 719d8f9c..00000000 --- a/abi/IERC721Errors.json +++ /dev/null @@ -1,105 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ERC721IncorrectOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ERC721InsufficientApproval", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC721InvalidApprover", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "ERC721InvalidOperator", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ERC721InvalidOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC721InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC721InvalidSender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ERC721NonexistentToken", - "type": "error" - } -] diff --git a/abi/IEthBlocklistErc20Vault.json b/abi/IEthBlocklistErc20Vault.json deleted file mode 100644 index e2ee6afd..00000000 --- a/abi/IEthBlocklistErc20Vault.json +++ /dev/null @@ -1,1954 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthBlocklistVault.json b/abi/IEthBlocklistVault.json deleted file mode 100644 index 328668a9..00000000 --- a/abi/IEthBlocklistVault.json +++ /dev/null @@ -1,1657 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthErc20Vault.json b/abi/IEthErc20Vault.json deleted file mode 100644 index 9149f12f..00000000 --- a/abi/IEthErc20Vault.json +++ /dev/null @@ -1,1847 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthFoxVault.json b/abi/IEthFoxVault.json deleted file mode 100644 index 0d22bf10..00000000 --- a/abi/IEthFoxVault.json +++ /dev/null @@ -1,1361 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "ownMevEscrow", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "capacity", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "EthFoxVaultCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "UserEjected", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "ejectUser", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthGenesisVault.json b/abi/IEthGenesisVault.json deleted file mode 100644 index 1d5a91ca..00000000 --- a/abi/IEthGenesisVault.json +++ /dev/null @@ -1,1630 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "capacity", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "GenesisVaultCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Migrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "migrate", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthPoolEscrow.json b/abi/IEthPoolEscrow.json deleted file mode 100644 index b2f34e03..00000000 --- a/abi/IEthPoolEscrow.json +++ /dev/null @@ -1,129 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferApplied", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "currentOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "futureOwner", - "type": "address" - } - ], - "name": "OwnershipTransferCommitted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "payee", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "Withdrawn", - "type": "event" - }, - { - "inputs": [], - "name": "applyOwnershipTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "commitOwnershipTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "futureOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "payee", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IEthPrivErc20Vault.json b/abi/IEthPrivErc20Vault.json deleted file mode 100644 index a05f0f12..00000000 --- a/abi/IEthPrivErc20Vault.json +++ /dev/null @@ -1,1954 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthPrivVault.json b/abi/IEthPrivVault.json deleted file mode 100644 index 7cce9d82..00000000 --- a/abi/IEthPrivVault.json +++ /dev/null @@ -1,1657 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthValidatorsRegistry.json b/abi/IEthValidatorsRegistry.json deleted file mode 100644 index ea2131ec..00000000 --- a/abi/IEthValidatorsRegistry.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "amount", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "index", - "type": "bytes" - } - ], - "name": "DepositEvent", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "deposit_data_root", - "type": "bytes32" - } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "get_deposit_root", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthVault.json b/abi/IEthVault.json deleted file mode 100644 index da1739d5..00000000 --- a/abi/IEthVault.json +++ /dev/null @@ -1,1550 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IEthVaultFactory.json b/abi/IEthVaultFactory.json deleted file mode 100644 index 174749e5..00000000 --- a/abi/IEthVaultFactory.json +++ /dev/null @@ -1,96 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "ownMevEscrow", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "VaultCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "isOwnMevEscrow", - "type": "bool" - } - ], - "name": "createVault", - "outputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ownMevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoBlocklistErc20Vault.json b/abi/IGnoBlocklistErc20Vault.json deleted file mode 100644 index 3b43554d..00000000 --- a/abi/IGnoBlocklistErc20Vault.json +++ /dev/null @@ -1,1835 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoBlocklistVault.json b/abi/IGnoBlocklistVault.json deleted file mode 100644 index 7b689079..00000000 --- a/abi/IGnoBlocklistVault.json +++ /dev/null @@ -1,1538 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoDaiDistributor.json b/abi/IGnoDaiDistributor.json deleted file mode 100644 index bb8e94e9..00000000 --- a/abi/IGnoDaiDistributor.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "DaiDistributed", - "type": "event" - }, - { - "inputs": [], - "name": "distributeDai", - "outputs": [], - "stateMutability": "payable", - "type": "function" - } -] diff --git a/abi/IGnoErc20Vault.json b/abi/IGnoErc20Vault.json deleted file mode 100644 index a90731d6..00000000 --- a/abi/IGnoErc20Vault.json +++ /dev/null @@ -1,1728 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoGenesisVault.json b/abi/IGnoGenesisVault.json deleted file mode 100644 index e9d90aa5..00000000 --- a/abi/IGnoGenesisVault.json +++ /dev/null @@ -1,1511 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "capacity", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "GenesisVaultCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Migrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "migrate", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoPoolEscrow.json b/abi/IGnoPoolEscrow.json deleted file mode 100644 index 640cf937..00000000 --- a/abi/IGnoPoolEscrow.json +++ /dev/null @@ -1,152 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferApplied", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "currentOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "futureOwner", - "type": "address" - } - ], - "name": "OwnershipTransferCommitted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "payee", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "Withdrawn", - "type": "event" - }, - { - "inputs": [], - "name": "applyOwnershipTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "commitOwnershipTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "futureOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "payee", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "payee", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "withdrawTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IGnoPrivErc20Vault.json b/abi/IGnoPrivErc20Vault.json deleted file mode 100644 index e278eed9..00000000 --- a/abi/IGnoPrivErc20Vault.json +++ /dev/null @@ -1,1835 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoPrivVault.json b/abi/IGnoPrivVault.json deleted file mode 100644 index 1b308a5b..00000000 --- a/abi/IGnoPrivVault.json +++ /dev/null @@ -1,1538 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoValidatorsRegistry.json b/abi/IGnoValidatorsRegistry.json deleted file mode 100644 index d0dc1e63..00000000 --- a/abi/IGnoValidatorsRegistry.json +++ /dev/null @@ -1,145 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "amount", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "index", - "type": "bytes" - } - ], - "name": "DepositEvent", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "pubkeys", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "bytes32[]", - "name": "deposit_data_roots", - "type": "bytes32[]" - } - ], - "name": "batchDeposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_address", - "type": "address" - } - ], - "name": "claimWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "deposit_data_root", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "stake_amount", - "type": "uint256" - } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "get_deposit_root", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_address", - "type": "address" - } - ], - "name": "withdrawableAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoVault.json b/abi/IGnoVault.json deleted file mode 100644 index fcc5064c..00000000 --- a/abi/IGnoVault.json +++ /dev/null @@ -1,1431 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IGnoVaultFactory.json b/abi/IGnoVaultFactory.json deleted file mode 100644 index 7f62a879..00000000 --- a/abi/IGnoVaultFactory.json +++ /dev/null @@ -1,96 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "ownMevEscrow", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "VaultCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "isOwnMevEscrow", - "type": "bool" - } - ], - "name": "createVault", - "outputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ownMevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IKeeper.json b/abi/IKeeper.json deleted file mode 100644 index 3f89a724..00000000 --- a/abi/IKeeper.json +++ /dev/null @@ -1,737 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "ConfigUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "name": "ExitSignaturesUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "int256", - "name": "totalAssetsDelta", - "type": "int256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "unlockedMevDelta", - "type": "uint256" - } - ], - "name": "Harvested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oracles", - "type": "uint256" - } - ], - "name": "RewardsMinOraclesUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "updateTimestamp", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - } - ], - "name": "RewardsUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "name": "ValidatorsApproval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oracles", - "type": "uint256" - } - ], - "name": "ValidatorsMinOraclesUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "addOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "params", - "type": "tuple" - } - ], - "name": "approveValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "canHarvest", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "canUpdateRewards", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "exitSignaturesNonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "params", - "type": "tuple" - } - ], - "name": "harvest", - "outputs": [ - { - "internalType": "int256", - "name": "totalAssetsDelta", - "type": "int256" - }, - { - "internalType": "uint256", - "name": "unlockedMevDelta", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "harvested", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_owner", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "isCollateralized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "isHarvestRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "isOracle", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastRewardsTimestamp", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "prevRewardsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "removeOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "rewards", - "outputs": [ - { - "internalType": "int192", - "name": "assets", - "type": "int192" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsMinOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsNonce", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rewardsMinOracles", - "type": "uint256" - } - ], - "name": "setRewardsMinOracles", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_validatorsMinOracles", - "type": "uint256" - } - ], - "name": "setValidatorsMinOracles", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "unlockedMevRewards", - "outputs": [ - { - "internalType": "uint192", - "name": "assets", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "updateConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - }, - { - "internalType": "bytes", - "name": "oraclesSignatures", - "type": "bytes" - } - ], - "name": "updateExitSignatures", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "updateTimestamp", - "type": "uint64" - }, - { - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "internalType": "struct IKeeperRewards.RewardsUpdateParams", - "name": "params", - "type": "tuple" - } - ], - "name": "updateRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsMinOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IKeeperOracles.json b/abi/IKeeperOracles.json deleted file mode 100644 index 62a8e5b3..00000000 --- a/abi/IKeeperOracles.json +++ /dev/null @@ -1,161 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "ConfigUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleRemoved", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "addOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "isOracle", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "removeOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "updateConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IKeeperRewards.json b/abi/IKeeperRewards.json deleted file mode 100644 index 04cc0fea..00000000 --- a/abi/IKeeperRewards.json +++ /dev/null @@ -1,548 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "ConfigUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "int256", - "name": "totalAssetsDelta", - "type": "int256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "unlockedMevDelta", - "type": "uint256" - } - ], - "name": "Harvested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oracles", - "type": "uint256" - } - ], - "name": "RewardsMinOraclesUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "updateTimestamp", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - } - ], - "name": "RewardsUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "addOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "canHarvest", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "canUpdateRewards", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "params", - "type": "tuple" - } - ], - "name": "harvest", - "outputs": [ - { - "internalType": "int256", - "name": "totalAssetsDelta", - "type": "int256" - }, - { - "internalType": "uint256", - "name": "unlockedMevDelta", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "harvested", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "isCollateralized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "isHarvestRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "isOracle", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastRewardsTimestamp", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "prevRewardsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "removeOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "rewards", - "outputs": [ - { - "internalType": "int192", - "name": "assets", - "type": "int192" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsMinOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsNonce", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rewardsMinOracles", - "type": "uint256" - } - ], - "name": "setRewardsMinOracles", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "unlockedMevRewards", - "outputs": [ - { - "internalType": "uint192", - "name": "assets", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "updateConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "updateTimestamp", - "type": "uint64" - }, - { - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "internalType": "struct IKeeperRewards.RewardsUpdateParams", - "name": "params", - "type": "tuple" - } - ], - "name": "updateRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IKeeperValidators.json b/abi/IKeeperValidators.json deleted file mode 100644 index 03df6233..00000000 --- a/abi/IKeeperValidators.json +++ /dev/null @@ -1,724 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "ConfigUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "name": "ExitSignaturesUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "int256", - "name": "totalAssetsDelta", - "type": "int256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "unlockedMevDelta", - "type": "uint256" - } - ], - "name": "Harvested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "OracleRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oracles", - "type": "uint256" - } - ], - "name": "RewardsMinOraclesUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "updateTimestamp", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - } - ], - "name": "RewardsUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "name": "ValidatorsApproval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oracles", - "type": "uint256" - } - ], - "name": "ValidatorsMinOraclesUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "addOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "params", - "type": "tuple" - } - ], - "name": "approveValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "canHarvest", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "canUpdateRewards", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "exitSignaturesNonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "params", - "type": "tuple" - } - ], - "name": "harvest", - "outputs": [ - { - "internalType": "int256", - "name": "totalAssetsDelta", - "type": "int256" - }, - { - "internalType": "uint256", - "name": "unlockedMevDelta", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "harvested", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "isCollateralized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "isHarvestRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "isOracle", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastRewardsTimestamp", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "prevRewardsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "removeOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "rewards", - "outputs": [ - { - "internalType": "int192", - "name": "assets", - "type": "int192" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsMinOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsNonce", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rewardsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rewardsMinOracles", - "type": "uint256" - } - ], - "name": "setRewardsMinOracles", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_validatorsMinOracles", - "type": "uint256" - } - ], - "name": "setValidatorsMinOracles", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "unlockedMevRewards", - "outputs": [ - { - "internalType": "uint192", - "name": "assets", - "type": "uint192" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "configIpfsHash", - "type": "string" - } - ], - "name": "updateConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - }, - { - "internalType": "bytes", - "name": "oraclesSignatures", - "type": "bytes" - } - ], - "name": "updateExitSignatures", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "updateTimestamp", - "type": "uint64" - }, - { - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "internalType": "struct IKeeperRewards.RewardsUpdateParams", - "name": "params", - "type": "tuple" - } - ], - "name": "updateRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsMinOracles", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IMerkleDistributor.json b/abi/IMerkleDistributor.json deleted file mode 100644 index c9a13e9b..00000000 --- a/abi/IMerkleDistributor.json +++ /dev/null @@ -1,61 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "string", - "name": "rewardsIpfsHash", - "type": "string" - }, - { - "internalType": "bytes", - "name": "extraData", - "type": "bytes" - } - ], - "name": "distributeOneTime", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "distributor", - "type": "address" - }, - { - "internalType": "bool", - "name": "isEnabled", - "type": "bool" - } - ], - "name": "setDistributor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IMulticall.json b/abi/IMulticall.json deleted file mode 100644 index 5a0bc3db..00000000 --- a/abi/IMulticall.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsToken.json b/abi/IOsToken.json deleted file mode 100644 index ae5f701c..00000000 --- a/abi/IOsToken.json +++ /dev/null @@ -1,440 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "controller", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "registered", - "type": "bool" - } - ], - "name": "ControllerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "controller", - "type": "address" - } - ], - "name": "controllers", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "mint", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "controller", - "type": "address" - }, - { - "internalType": "bool", - "name": "registered", - "type": "bool" - } - ], - "name": "setController", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsTokenConfig.json b/abi/IOsTokenConfig.json deleted file mode 100644 index 9c393eeb..00000000 --- a/abi/IOsTokenConfig.json +++ /dev/null @@ -1,143 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint128", - "name": "liqBonusPercent", - "type": "uint128" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "liqThresholdPercent", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "ltvPercent", - "type": "uint64" - } - ], - "name": "OsTokenConfigUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newRedeemer", - "type": "address" - } - ], - "name": "RedeemerUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "getConfig", - "outputs": [ - { - "components": [ - { - "internalType": "uint128", - "name": "liqBonusPercent", - "type": "uint128" - }, - { - "internalType": "uint64", - "name": "liqThresholdPercent", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "ltvPercent", - "type": "uint64" - } - ], - "internalType": "struct IOsTokenConfig.Config", - "name": "config", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "redeemer", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRedeemer", - "type": "address" - } - ], - "name": "setRedeemer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "components": [ - { - "internalType": "uint128", - "name": "liqBonusPercent", - "type": "uint128" - }, - { - "internalType": "uint64", - "name": "liqThresholdPercent", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "ltvPercent", - "type": "uint64" - } - ], - "internalType": "struct IOsTokenConfig.Config", - "name": "config", - "type": "tuple" - } - ], - "name": "updateConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsTokenFlashLoanRecipient.json b/abi/IOsTokenFlashLoanRecipient.json deleted file mode 100644 index 30db5fbd..00000000 --- a/abi/IOsTokenFlashLoanRecipient.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "name": "receiveFlashLoan", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsTokenFlashLoans.json b/abi/IOsTokenFlashLoans.json deleted file mode 100644 index dc1e8414..00000000 --- a/abi/IOsTokenFlashLoans.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "OsTokenFlashLoan", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "name": "flashLoan", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsTokenVaultController.json b/abi/IOsTokenVaultController.json deleted file mode 100644 index dddfcb2c..00000000 --- a/abi/IOsTokenVaultController.json +++ /dev/null @@ -1,416 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "avgRewardPerSecond", - "type": "uint256" - } - ], - "name": "AvgRewardPerSecondUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Burn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "capacity", - "type": "uint256" - } - ], - "name": "CapacityUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "keeper", - "type": "address" - } - ], - "name": "KeeperUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Mint", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "profitAccrued", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "treasuryShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "treasuryAssets", - "type": "uint256" - } - ], - "name": "StateUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "treasury", - "type": "address" - } - ], - "name": "TreasuryUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "avgRewardPerSecond", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "burnShares", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "cumulativeFeePerShare", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "keeper", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "mintShares", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_avgRewardPerSecond", - "type": "uint256" - } - ], - "name": "setAvgRewardPerSecond", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_capacity", - "type": "uint256" - } - ], - "name": "setCapacity", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - } - ], - "name": "setKeeper", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_treasury", - "type": "address" - } - ], - "name": "setTreasury", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "treasury", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsTokenVaultEscrow.json b/abi/IOsTokenVaultEscrow.json deleted file mode 100644 index f0b68f13..00000000 --- a/abi/IOsTokenVaultEscrow.json +++ /dev/null @@ -1,489 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newAuthenticator", - "type": "address" - } - ], - "name": "AuthenticatorUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsProcessed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "liqThresholdPercent", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "liqBonusPercent", - "type": "uint256" - } - ], - "name": "LiqConfigUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "cumulativeFeePerShare", - "type": "uint256" - } - ], - "name": "PositionCreated", - "type": "event" - }, - { - "inputs": [], - "name": "authenticator", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "claimedAssets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getPosition", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "liqBonusPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "liqThresholdPercent", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "processExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "cumulativeFeePerShare", - "type": "uint256" - } - ], - "name": "register", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAuthenticator", - "type": "address" - } - ], - "name": "setAuthenticator", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_liqThresholdPercent", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "_liqBonusPercent", - "type": "uint256" - } - ], - "name": "updateLiqConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IOsTokenVaultEscrowAuth.json b/abi/IOsTokenVaultEscrowAuth.json deleted file mode 100644 index fe76fe9f..00000000 --- a/abi/IOsTokenVaultEscrowAuth.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "canRegister", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IOwnMevEscrow.json b/abi/IOwnMevEscrow.json deleted file mode 100644 index db962ba4..00000000 --- a/abi/IOwnMevEscrow.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "Harvested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "MevReceived", - "type": "event" - }, - { - "inputs": [], - "name": "harvest", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "vault", - "outputs": [ - { - "internalType": "address payable", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IRewardEthToken.json b/abi/IRewardEthToken.json deleted file mode 100644 index 69183d1f..00000000 --- a/abi/IRewardEthToken.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalPenalty", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalRewards", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "int256", - "name": "rewardsDelta", - "type": "int256" - } - ], - "name": "updateTotalRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IRewardGnoToken.json b/abi/IRewardGnoToken.json deleted file mode 100644 index 69183d1f..00000000 --- a/abi/IRewardGnoToken.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalPenalty", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalRewards", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "int256", - "name": "rewardsDelta", - "type": "int256" - } - ], - "name": "updateTotalRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IRewardSplitter.json b/abi/IRewardSplitter.json deleted file mode 100644 index ed9cb858..00000000 --- a/abi/IRewardSplitter.json +++ /dev/null @@ -1,496 +0,0 @@ -[ - { - "inputs": [], - "name": "InvalidAccount", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAmount", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "ClaimOnBehalfUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "onBehalf", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ExitQueueEnteredOnBehalf", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "onBehalf", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimedOnBehalf", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "totalRewards", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "rewardPerShare", - "type": "uint256" - } - ], - "name": "RewardsSynced", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "RewardsWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "SharesDecreased", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "SharesIncreased", - "type": "event" - }, - { - "inputs": [], - "name": "canSyncRewards", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssetsOnBehalf", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "rewards", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimVaultTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - } - ], - "name": "decreaseShares", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "rewards", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "rewards", - "type": "uint256" - }, - { - "internalType": "address", - "name": "onBehalf", - "type": "address" - } - ], - "name": "enterExitQueueOnBehalf", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "exitPosition", - "type": "uint256" - } - ], - "name": "exitPositions", - "outputs": [ - { - "internalType": "address", - "name": "onBehalf", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - } - ], - "name": "increaseShares", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_vault", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isClaimOnBehalfEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "rewardsOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "setClaimOnBehalf", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "sharesOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "syncRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalRewards", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateVaultState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "vault", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IRewardSplitterFactory.json b/abi/IRewardSplitterFactory.json deleted file mode 100644 index 5cf62d15..00000000 --- a/abi/IRewardSplitterFactory.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "rewardSplitter", - "type": "address" - } - ], - "name": "RewardSplitterCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "createRewardSplitter", - "outputs": [ - { - "internalType": "address", - "name": "rewardSplitter", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/ISavingsXDaiAdapter.json b/abi/ISavingsXDaiAdapter.json deleted file mode 100644 index 269542b3..00000000 --- a/abi/ISavingsXDaiAdapter.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "depositXDAI", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - } -] diff --git a/abi/ISharedMevEscrow.json b/abi/ISharedMevEscrow.json deleted file mode 100644 index 87913d0d..00000000 --- a/abi/ISharedMevEscrow.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "Harvested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "MevReceived", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "harvest", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IValidatorsChecker.json b/abi/IValidatorsChecker.json deleted file mode 100644 index 4e02a50a..00000000 --- a/abi/IValidatorsChecker.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - }, - { - "internalType": "bool[]", - "name": "proofFlags", - "type": "bool[]" - }, - { - "internalType": "uint256[]", - "name": "proofIndexes", - "type": "uint256[]" - } - ], - "name": "checkDepositDataRoot", - "outputs": [ - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "enum IValidatorsChecker.Status", - "name": "status", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "checkValidatorsManagerSignature", - "outputs": [ - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "enum IValidatorsChecker.Status", - "name": "status", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IValidatorsRegistry.json b/abi/IValidatorsRegistry.json deleted file mode 100644 index c7e8347a..00000000 --- a/abi/IValidatorsRegistry.json +++ /dev/null @@ -1,52 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "amount", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "index", - "type": "bytes" - } - ], - "name": "DepositEvent", - "type": "event" - }, - { - "inputs": [], - "name": "get_deposit_root", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultAdmin.json b/abi/IVaultAdmin.json deleted file mode 100644 index 4db86e03..00000000 --- a/abi/IVaultAdmin.json +++ /dev/null @@ -1,79 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IVaultBlocklist.json b/abi/IVaultBlocklist.json deleted file mode 100644 index 4c5545af..00000000 --- a/abi/IVaultBlocklist.json +++ /dev/null @@ -1,186 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IVaultEnterExit.json b/abi/IVaultEnterExit.json deleted file mode 100644 index e4cf9fd5..00000000 --- a/abi/IVaultEnterExit.json +++ /dev/null @@ -1,686 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultEthStaking.json b/abi/IVaultEthStaking.json deleted file mode 100644 index 7ebc5bb6..00000000 --- a/abi/IVaultEthStaking.json +++ /dev/null @@ -1,1101 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultFee.json b/abi/IVaultFee.json deleted file mode 100644 index f6d7da36..00000000 --- a/abi/IVaultFee.json +++ /dev/null @@ -1,169 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/abi/IVaultGnoStaking.json b/abi/IVaultGnoStaking.json deleted file mode 100644 index 4d2694c2..00000000 --- a/abi/IVaultGnoStaking.json +++ /dev/null @@ -1,1054 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultMev.json b/abi/IVaultMev.json deleted file mode 100644 index cc7af01a..00000000 --- a/abi/IVaultMev.json +++ /dev/null @@ -1,422 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultOsToken.json b/abi/IVaultOsToken.json deleted file mode 100644 index 881e1c3f..00000000 --- a/abi/IVaultOsToken.json +++ /dev/null @@ -1,966 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultState.json b/abi/IVaultState.json deleted file mode 100644 index c62d3452..00000000 --- a/abi/IVaultState.json +++ /dev/null @@ -1,409 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultToken.json b/abi/IVaultToken.json deleted file mode 100644 index a2695644..00000000 --- a/abi/IVaultToken.json +++ /dev/null @@ -1,983 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultValidators.json b/abi/IVaultValidators.json deleted file mode 100644 index 3e3edf14..00000000 --- a/abi/IVaultValidators.json +++ /dev/null @@ -1,729 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - } - ], - "name": "FeePercentUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "fromPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "toPublicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorConsolidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorFunded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "feePaid", - "type": "uint256" - } - ], - "name": "ValidatorWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "oracleSignatures", - "type": "bytes" - } - ], - "name": "consolidateValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "fundValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - } - ], - "name": "setFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validatorsManager", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "publicKeyHash", - "type": "bytes32" - } - ], - "name": "trackedValidators", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManagerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "withdrawValidators", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultVersion.json b/abi/IVaultVersion.json deleted file mode 100644 index c4c5ab89..00000000 --- a/abi/IVaultVersion.json +++ /dev/null @@ -1,131 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - } -] diff --git a/abi/IVaultWhitelist.json b/abi/IVaultWhitelist.json deleted file mode 100644 index 8467bf6f..00000000 --- a/abi/IVaultWhitelist.json +++ /dev/null @@ -1,186 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "setAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/IVaultsRegistry.json b/abi/IVaultsRegistry.json deleted file mode 100644 index 1e05bfb3..00000000 --- a/abi/IVaultsRegistry.json +++ /dev/null @@ -1,208 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "factory", - "type": "address" - } - ], - "name": "FactoryAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "factory", - "type": "address" - } - ], - "name": "FactoryRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "VaultAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "impl", - "type": "address" - } - ], - "name": "VaultImplAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "impl", - "type": "address" - } - ], - "name": "VaultImplRemoved", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "factory", - "type": "address" - } - ], - "name": "addFactory", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "addVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImpl", - "type": "address" - } - ], - "name": "addVaultImpl", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "factory", - "type": "address" - } - ], - "name": "factories", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_owner", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "factory", - "type": "address" - } - ], - "name": "removeFactory", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "impl", - "type": "address" - } - ], - "name": "removeVaultImpl", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "impl", - "type": "address" - } - ], - "name": "vaultImpls", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "name": "vaults", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/deployments/chiado-upgrade-v3-tx.json b/deployments/chiado-upgrade-v3-tx.json deleted file mode 100644 index 8b58abb8..00000000 --- a/deployments/chiado-upgrade-v3-tx.json +++ /dev/null @@ -1,213 +0,0 @@ -[ - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x256b5a0200000000000000000000000000aa8a78d88a9865b5b0f4ce50c3bb018c93fba7", - "method": "addVault(address)", - "params": [ - "0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7" - ] - }, - { - "to": "0x0b4F6bFB694790051E0203Db83edbB5888099556", - "operation": "0", - "value": "0.0", - "data": "0xe0dba60f0000000000000000000000007bc48037433d610c6069a873bea8cf7d3ce1ff010000000000000000000000000000000000000000000000000000000000000001", - "method": "setController(address,bool)", - "params": [ - "0x7bC48037433d610C6069a873beA8CF7D3cE1Ff01", - true - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000007fefdc8375e84adb0be5e4ba5e238c021f1858fe", - "method": "removeFactory(address)", - "params": [ - "0x7fEFdC8375E84Adb0bE5e4Ba5E238c021F1858fE" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000014892a30be63a7ecb56300357c77b7c9f1760193", - "method": "addFactory(address)", - "params": [ - "0x14892a30Be63A7ecB56300357C77B7c9f1760193" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000671238a366503414328b05e20c4304cb595d40b5", - "method": "addVaultImpl(address)", - "params": [ - "0x671238a366503414328b05e20c4304cB595d40b5" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000a67d62f8d26fe034426b512a6621d4e8fc8b2ab3", - "method": "removeFactory(address)", - "params": [ - "0xA67D62F8D26Fe034426B512A6621D4e8fc8B2aB3" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000ef693eccd1904279ae05248f1349d5848948aab2", - "method": "addFactory(address)", - "params": [ - "0xeF693eCCd1904279aE05248f1349D5848948AAB2" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000009d4a0f998a2ec7dde748dd1aa6c9d318751eab94", - "method": "addVaultImpl(address)", - "params": [ - "0x9d4a0f998a2eC7ddE748dd1aA6C9d318751EAb94" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000002bc7968461c51525433b9dce504a543b26a2f31b", - "method": "removeFactory(address)", - "params": [ - "0x2bC7968461c51525433b9DcE504a543b26a2f31B" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000b0db872d2f1f6cc807e09e65f7c0dfcca5f5f2b0", - "method": "addFactory(address)", - "params": [ - "0xB0db872d2F1F6cC807e09e65F7c0dFcCA5F5f2B0" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000000eca951c6d5305ab03f8e1a6ed1b6f81372d6559", - "method": "addVaultImpl(address)", - "params": [ - "0x0ecA951c6D5305aB03f8E1a6ed1b6F81372d6559" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000007ea0d7db6cf2402eb2b1a56bfbf6c2c88e6c8284", - "method": "removeFactory(address)", - "params": [ - "0x7eA0D7dB6cf2402eB2B1A56bfBf6c2C88e6c8284" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000d97a5a24c05a0c068fb0277879f4a1fc7bdaf5d8", - "method": "addFactory(address)", - "params": [ - "0xd97a5a24c05A0C068fB0277879f4a1Fc7bdaF5d8" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000001f8c5679c511a8dc049562538a12fd4128c9aaaa", - "method": "addVaultImpl(address)", - "params": [ - "0x1f8C5679C511A8dc049562538A12FD4128C9AaAA" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000588102eb5e387956b8067f4948bca34893e89597", - "method": "removeFactory(address)", - "params": [ - "0x588102eB5E387956b8067F4948BcA34893E89597" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000002cc4e3410039082fb91a7aacb693d2b96fdfb052", - "method": "addFactory(address)", - "params": [ - "0x2cC4E3410039082Fb91a7aACB693d2B96FdFb052" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000bef7f37c441bb9ab170e7191ac7263c94b9a3ab1", - "method": "addVaultImpl(address)", - "params": [ - "0xbEf7f37c441Bb9aB170e7191Ac7263c94b9a3Ab1" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000035482a11e21157e0c706d1a562483902421db341", - "method": "removeFactory(address)", - "params": [ - "0x35482A11E21157E0C706d1A562483902421dB341" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000045c9d93f786c71a08b10477f1eb8c42753616ebe", - "method": "addFactory(address)", - "params": [ - "0x45C9D93F786C71A08B10477f1eB8c42753616EBe" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000eefb07fb1aa31fbe6af50c01acb607ebb57a17cb", - "method": "addVaultImpl(address)", - "params": [ - "0xEeFB07Fb1aA31FbE6Af50c01acB607Ebb57A17cB" - ] - }, - { - "to": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000fc37d01f796cbf6fce62f70badd723c50bd02231", - "method": "addVaultImpl(address)", - "params": [ - "0xfc37D01F796cBF6fCe62f70badd723C50BD02231" - ] - } -] \ No newline at end of file diff --git a/deployments/chiado-vault-v3-upgrades.json b/deployments/chiado-vault-v3-upgrades.json deleted file mode 100644 index 29f31553..00000000 --- a/deployments/chiado-vault-v3-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0x92db5a150616972630ec6ff109fcce78f8559cc5594d540f16cd3cfa3fc86bcc": { - "3": "0x671238a366503414328b05e20c4304cB595d40b5" - }, - "0x9cf76a6c724b9ed90bd013cdce64a987a6e02c4220305b4a140a89d55a1ee023": { - "3": "0x9d4a0f998a2eC7ddE748dd1aA6C9d318751EAb94" - }, - "0x6c3152ed991a2a6ec7359c31f742e79dd206dc9d7378f631119a96bee15f8b86": { - "3": "0x0ecA951c6D5305aB03f8E1a6ed1b6F81372d6559" - }, - "0xd7358ee43135ceaf16fc3a6da49b8f2795ad16de0cf7f569aa7b9b1e67532fc4": { - "3": "0x1f8C5679C511A8dc049562538A12FD4128C9AaAA" - }, - "0x81812efbf43b69af38830f31dcb806af2764ff4398ba7ce084500c10160479b1": { - "3": "0xbEf7f37c441Bb9aB170e7191Ac7263c94b9a3Ab1" - }, - "0xc77e768dab534fa678edc458b42a344df0e260a0905ed4b4c3727a271a465cd0": { - "3": "0xEeFB07Fb1aA31FbE6Af50c01acB607Ebb57A17cB" - }, - "0x017d4155da73718dbec8960abca1d9f85d2dc8a31aa06e2d8e4410b4b093144a": { - "4": "0xfc37D01F796cBF6fCe62f70badd723C50BD02231" - } -} \ No newline at end of file diff --git a/deployments/chiado.json b/deployments/chiado.json deleted file mode 100644 index bf8ce114..00000000 --- a/deployments/chiado.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "VaultsRegistry": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", - "Keeper": "0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988", - "DepositDataRegistry": "0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D", - "GnoValidatorsChecker": "0x35B119c61B3Bb97f324423Ef5D3A82243daBb1B6", - "XdaiExchange": "0x3517FD486D275FD3A49128E50e67FFb24a537B26", - "GnoGenesisVault": "0xF82f6E46d0d0a9536b9CA4bc480372EeaFcd9E6c", - "GnoVaultFactory": "0x14892a30Be63A7ecB56300357C77B7c9f1760193", - "GnoPrivVaultFactory": "0xeF693eCCd1904279aE05248f1349D5848948AAB2", - "GnoBlocklistVaultFactory": "0xB0db872d2F1F6cC807e09e65F7c0dFcCA5F5f2B0", - "GnoErc20VaultFactory": "0xd97a5a24c05A0C068fB0277879f4a1Fc7bdaF5d8", - "GnoPrivErc20VaultFactory": "0x2cC4E3410039082Fb91a7aACB693d2B96FdFb052", - "GnoBlocklistErc20VaultFactory": "0x45C9D93F786C71A08B10477f1eB8c42753616EBe", - "SharedMevEscrow": "0x453056f0bc4631abB15eEC656139f88067668E3E", - "OsToken": "0x0b4F6bFB694790051E0203Db83edbB5888099556", - "OsTokenConfig": "0x6D5957e075fd93b3B9F36Da93d7462F14387706d", - "OsTokenVaultController": "0x5518052f2d898f062ee59964004A560F24E2eE7d", - "GnoOsTokenVaultEscrow": "0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7", - "OsTokenFlashLoans": "0x7bC48037433d610C6069a873beA8CF7D3cE1Ff01", - "PriceFeed": "0x3CC131e6f6b975423151E5aaE8C466f4f81A8A4c", - "RewardSplitterFactory": "0x6EE912596DCC3a8b7308164A65Af529a4276737C" -} \ No newline at end of file diff --git a/deployments/gnosis-upgrade-v3-tx.json b/deployments/gnosis-upgrade-v3-tx.json deleted file mode 100644 index 675fd269..00000000 --- a/deployments/gnosis-upgrade-v3-tx.json +++ /dev/null @@ -1,213 +0,0 @@ -[ - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x256b5a0200000000000000000000000028f325dd287a5984b754d34cfca38af3a8429e71", - "method": "addVault(address)", - "params": [ - "0x28F325dD287a5984B754d34CfCA38af3A8429e71" - ] - }, - { - "to": "0xF490c80aAE5f2616d3e3BDa2483E30C4CB21d1A0", - "operation": "0", - "value": "0.0", - "data": "0xe0dba60f000000000000000000000000e84183effbcc76d022cccc31b95eaa332bb5bb110000000000000000000000000000000000000000000000000000000000000001", - "method": "setController(address,bool)", - "params": [ - "0xe84183EfFbcc76D022Cccc31b95EAa332bB5Bb11", - true - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000c2ecc7620416bd65bfab7010b0db955a0e49579a", - "method": "removeFactory(address)", - "params": [ - "0xC2ecc7620416bd65bfab7010B0db955a0e49579a" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000078c54fefab5dab75ee7461565b85341dd8b92e30", - "method": "addFactory(address)", - "params": [ - "0x78c54FEfAB5DAb75ee7461565b85341dd8b92e30" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000064375c9a7305edb7bba757319aa4c20e6000bb8c", - "method": "addVaultImpl(address)", - "params": [ - "0x64375C9A7305edb7bbA757319AA4C20e6000bB8c" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000574952ec88b2fc271d0c0db130794c86ea42139a", - "method": "removeFactory(address)", - "params": [ - "0x574952EC88b2fC271d0C0dB130794c86Ea42139A" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000079168e105a72b97aa95fc8496e3b5d5f96f90491", - "method": "addFactory(address)", - "params": [ - "0x79168E105a72b97AA95FC8496e3B5D5F96f90491" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000075c57bd50a3eb7291da3429956d3566e0153a38f", - "method": "addVaultImpl(address)", - "params": [ - "0x75c57bd50A3EB7291Da3429956D3566E0153A38f" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000078fbfbd1dd38892476ac469325df36604a27f5b7", - "method": "removeFactory(address)", - "params": [ - "0x78FbfBd1DD38892476Ac469325df36604A27F5B7" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000016b7ef24ef7a85b49f77ff4c7fff819da9c1e236", - "method": "addFactory(address)", - "params": [ - "0x16B7Ef24eF7a85b49F77fF4c7fff819DA9c1E236" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000a593948a0bc611fc6945ea013806b0191ae79b47", - "method": "addVaultImpl(address)", - "params": [ - "0xA593948a0bC611fC6945eA013806b0191aE79B47" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000f6bbbc05536ab198d4b7ab74a93f8e2d4cad5354", - "method": "removeFactory(address)", - "params": [ - "0xF6BBBc05536Ab198d4b7Ab74a93f8e2d4cAd5354" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000000aaa2b3cf5f14ef24afb2cd7cf4cccc065be108b", - "method": "addFactory(address)", - "params": [ - "0x0aaa2b3Cf5F14eF24Afb2CD7Cf4CcCC065Be108B" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000e684ed3e740a3fd62e86b6bd6a8865e070568bca", - "method": "addVaultImpl(address)", - "params": [ - "0xe684eD3e740A3fD62e86b6bD6a8865e070568BCa" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000048319f97e5da1233c21c48b80097c0fb7a20ff86", - "method": "removeFactory(address)", - "params": [ - "0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000051fd45baefb12f54766b5c4d639b360ea50063bd", - "method": "addFactory(address)", - "params": [ - "0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000f16fea93d3253a401c3f73b0de890c6586740b25", - "method": "addVaultImpl(address)", - "params": [ - "0xf16fea93D3253A401C3f73B0De890C6586740B25" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000099e4300326867fe3f97864a74e500d19654c19e9", - "method": "removeFactory(address)", - "params": [ - "0x99E4300326867FE3f97864a74e500d19654c19e9" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000007345fc8268459413bee9e9dd327f31283c65ee7e", - "method": "addFactory(address)", - "params": [ - "0x7345fC8268459413beE9e9dd327f31283C65Ee7e" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000140fc69eabd77fff91d9852b612b2323256f7ac1", - "method": "addVaultImpl(address)", - "params": [ - "0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1" - ] - }, - { - "to": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000a7d1ac9d6f32b404c75626874ba56f7654c1dc0f", - "method": "addVaultImpl(address)", - "params": [ - "0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f" - ] - } -] \ No newline at end of file diff --git a/deployments/gnosis-vault-v3-upgrades.json b/deployments/gnosis-vault-v3-upgrades.json deleted file mode 100644 index 2669e39f..00000000 --- a/deployments/gnosis-vault-v3-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0x92db5a150616972630ec6ff109fcce78f8559cc5594d540f16cd3cfa3fc86bcc": { - "3": "0x64375C9A7305edb7bbA757319AA4C20e6000bB8c" - }, - "0x9cf76a6c724b9ed90bd013cdce64a987a6e02c4220305b4a140a89d55a1ee023": { - "3": "0x75c57bd50A3EB7291Da3429956D3566E0153A38f" - }, - "0x6c3152ed991a2a6ec7359c31f742e79dd206dc9d7378f631119a96bee15f8b86": { - "3": "0xA593948a0bC611fC6945eA013806b0191aE79B47" - }, - "0xd7358ee43135ceaf16fc3a6da49b8f2795ad16de0cf7f569aa7b9b1e67532fc4": { - "3": "0xe684eD3e740A3fD62e86b6bD6a8865e070568BCa" - }, - "0x81812efbf43b69af38830f31dcb806af2764ff4398ba7ce084500c10160479b1": { - "3": "0xf16fea93D3253A401C3f73B0De890C6586740B25" - }, - "0xc77e768dab534fa678edc458b42a344df0e260a0905ed4b4c3727a271a465cd0": { - "3": "0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1" - }, - "0x017d4155da73718dbec8960abca1d9f85d2dc8a31aa06e2d8e4410b4b093144a": { - "4": "0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f" - } -} \ No newline at end of file diff --git a/deployments/gnosis.json b/deployments/gnosis.json deleted file mode 100644 index c602aa22..00000000 --- a/deployments/gnosis.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "VaultsRegistry": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", - "Keeper": "0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa", - "DepositDataRegistry": "0x58e16621B5c0786D6667D2d54E28A20940269E16", - "GnoValidatorsChecker": "0x3E2CC1584a2fB4FB2D4f4aF68AE47B57BE76dC65", - "XdaiExchange": "0x000108f8dFc532263C307242cF6773312b28f855", - "GnoGenesisVault": "0x4b4406Ed8659D03423490D8b62a1639206dA0A7a", - "GnoVaultFactory": "0x78c54FEfAB5DAb75ee7461565b85341dd8b92e30", - "GnoPrivVaultFactory": "0x79168E105a72b97AA95FC8496e3B5D5F96f90491", - "GnoBlocklistVaultFactory": "0x16B7Ef24eF7a85b49F77fF4c7fff819DA9c1E236", - "GnoErc20VaultFactory": "0x0aaa2b3Cf5F14eF24Afb2CD7Cf4CcCC065Be108B", - "GnoPrivErc20VaultFactory": "0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd", - "GnoBlocklistErc20VaultFactory": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", - "SharedMevEscrow": "0x30db0d10d3774e78f8cB214b9e8B72D4B402488a", - "OsToken": "0xF490c80aAE5f2616d3e3BDa2483E30C4CB21d1A0", - "OsTokenConfig": "0xd6672fbE1D28877db598DC0ac2559A15745FC3ec", - "OsTokenVaultController": "0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a", - "GnoOsTokenVaultEscrow": "0x28F325dD287a5984B754d34CfCA38af3A8429e71", - "OsTokenFlashLoans": "0xe84183EfFbcc76D022Cccc31b95EAa332bB5Bb11", - "PriceFeed": "0x9B1b13afA6a57e54C03AD0428a4766C39707D272", - "RewardSplitterFactory": "0x4c6306BA1821D88803e27A115433520F2d6276Fb" -} \ No newline at end of file diff --git a/deployments/holesky-upgrade-v4-tx.json b/deployments/holesky-upgrade-v4-tx.json deleted file mode 100644 index 486ab9be..00000000 --- a/deployments/holesky-upgrade-v4-tx.json +++ /dev/null @@ -1,72 +0,0 @@ -[ - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000850fa495ed898067c35ac3e49504c0c4c19b0bd9", - "method": "addVaultImpl(address)", - "params": [ - "0x850fa495ED898067c35AC3E49504c0c4C19b0BD9" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000006d5957e075fd93b3b9f36da93d7462f14387706d", - "method": "addVaultImpl(address)", - "params": [ - "0x6D5957e075fd93b3B9F36Da93d7462F14387706d" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000face8504462aeb9bb6ae7ecb206bd7b1edf7956d", - "method": "addVaultImpl(address)", - "params": [ - "0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000035b119c61b3bb97f324423ef5d3a82243dabb1b6", - "method": "addVaultImpl(address)", - "params": [ - "0x35B119c61B3Bb97f324423Ef5D3A82243daBb1B6" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000cca9fe40f1653f87a6dc021e2e7e65f0d0429b8e", - "method": "addVaultImpl(address)", - "params": [ - "0xCCA9FE40f1653f87A6dC021E2E7E65f0D0429B8e" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000003517fd486d275fd3a49128e50e67ffb24a537b26", - "method": "addVaultImpl(address)", - "params": [ - "0x3517FD486D275FD3A49128E50e67FFb24a537B26" - ] - }, - { - "to": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000094fae7fe801e6ab95f2a52f339e6ee1f1e222dec", - "method": "addVaultImpl(address)", - "params": [ - "0x94fae7fe801E6Ab95F2A52F339E6EE1F1E222DEc" - ] - } -] \ No newline at end of file diff --git a/deployments/holesky-vault-v4-upgrades.json b/deployments/holesky-vault-v4-upgrades.json deleted file mode 100644 index 34dca13e..00000000 --- a/deployments/holesky-vault-v4-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "4": "0x850fa495ED898067c35AC3E49504c0c4C19b0BD9" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "4": "0x6D5957e075fd93b3B9F36Da93d7462F14387706d" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "4": "0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "4": "0x35B119c61B3Bb97f324423Ef5D3A82243daBb1B6" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "4": "0xCCA9FE40f1653f87A6dC021E2E7E65f0D0429B8e" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "4": "0x3517FD486D275FD3A49128E50e67FFb24a537B26" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "4": "0x94fae7fe801E6Ab95F2A52F339E6EE1F1E222DEc" - } -} \ No newline at end of file diff --git a/deployments/holesky.json b/deployments/holesky.json deleted file mode 100644 index 730ff7fa..00000000 --- a/deployments/holesky.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "VaultsRegistry": "0xAa773c035Af95721C518eCd8250CadAC0AAB7ed0", - "Keeper": "0xB580799Bf7d62721D1a523f0FDF2f5Ed7BA4e259", - "DepositDataRegistry": "0xAC0F906E433d58FA868F936E8A43230473652885", - "EthValidatorsChecker": "0x3a633173b90362D89656432452Bf2BD8D6786856", - "EthGenesisVault": "0x8A94e1d22D83990205843cda08376d16F150c9bb", - "EthFoxVault": "0x3c4ae629bf823475192124E02b9879D3C1fd4538", - "EthVaultFactory": "0x3acDBdbf0459d376dF9378c02Af50c83dc7646e9", - "EthPrivVaultFactory": "0x453056f0bc4631abB15eEC656139f88067668E3E", - "EthBlocklistVaultFactory": "0x0b4F6bFB694790051E0203Db83edbB5888099556", - "EthErc20VaultFactory": "0x7aa02B4Cf39f98FfEB324325775f840d18549733", - "EthPrivErc20VaultFactory": "0xDecb606ee9140f229Df78F9E40041EAD61610F8f", - "EthBlocklistErc20VaultFactory": "0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478", - "SharedMevEscrow": "0xc98F25BcAA6B812a07460f18da77AF8385be7b56", - "OsToken": "0xF603c5A3F774F05d4D848A9bB139809790890864", - "OsTokenConfig": "0x124C33d07F94B31aDF87C12F7cA3a586d3510928", - "OsTokenVaultController": "0x7BbC1733ee018f103A9a9052a18fA9273255Cf36", - "EthOsTokenVaultEscrow": "0x807305c086A99cbDBff07cB4256cE556d9d6F0af", - "OsTokenFlashLoans": "0x3e30370cabD4B4D95Be17706D840FF9de1ADdb67", - "PriceFeed": "0xe31FAf135A6047Cbe595F91B4b6802cDB9B46E2b", - "RewardSplitterFactory": "0x2Ed24638b3aB48cF0076f19199c78A62bfEb5889" -} \ No newline at end of file diff --git a/deployments/hoodi-upgrade-v2-tx.json b/deployments/hoodi-upgrade-v2-tx.json deleted file mode 100644 index 9aa4fbf4..00000000 --- a/deployments/hoodi-upgrade-v2-tx.json +++ /dev/null @@ -1,172 +0,0 @@ -[ - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000002a49951faffcfe3bf5247834ead8a5df8638ad9e", - "method": "removeFactory(address)", - "params": [ - "0x2A49951FafFcfe3Bf5247834eAd8A5dF8638Ad9e" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000f0f07383f621370eb59a794f36b7d80063d06147", - "method": "addFactory(address)", - "params": [ - "0xf0F07383F621370Eb59A794f36b7D80063d06147" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000fe974c6502e59d760b3a27e6d5a4315dc668d716", - "method": "addVaultImpl(address)", - "params": [ - "0xFe974c6502E59d760B3a27e6D5a4315DC668d716" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000075cfa03086f4832d7ed238dbba59b1c6cba01cfe", - "method": "removeFactory(address)", - "params": [ - "0x75CFa03086F4832D7eD238dbba59B1c6CBa01CFe" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000000f8c209445282d937dac0ea0a6706590250f9afd", - "method": "addFactory(address)", - "params": [ - "0x0F8c209445282d937DaC0eA0a6706590250F9aFD" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000003bec3c1cf81a1176c12550b4315bdd53a2b4fd5d", - "method": "addVaultImpl(address)", - "params": [ - "0x3BEc3c1cf81A1176c12550B4315bdd53A2B4Fd5D" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000b4fea836cdd93ac900100bb6462fe73872e5b524", - "method": "addFactory(address)", - "params": [ - "0xB4FEA836CDd93Ac900100bB6462fE73872E5B524" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000d506fe0b3ddf9e685c16e000514a835d3a511b26", - "method": "addVaultImpl(address)", - "params": [ - "0xD506fE0B3dDF9e685C16E000514a835D3a511b26" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000a321619a6232bdc03ab1a82affb5783518a9f5bb", - "method": "removeFactory(address)", - "params": [ - "0xa321619a6232BdC03Ab1a82aFFb5783518A9f5BB" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000068d17efa7cf9e1d121e9ff6138f2336bdb1ccbca", - "method": "addFactory(address)", - "params": [ - "0x68D17eFa7cf9e1d121e9ff6138f2336bDB1CcBcA" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000000c2ec14603ad9c14a820ad0c91122210ab84a9e5", - "method": "addVaultImpl(address)", - "params": [ - "0x0C2eC14603Ad9c14a820ad0C91122210Ab84A9e5" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000f9d18fc3d4f917e87400c445429440ca73d970e4", - "method": "removeFactory(address)", - "params": [ - "0xf9D18Fc3D4F917E87400C445429440CA73D970E4" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000ac40b56e7bb98c2be5ee5b3e8b28568b33fa76ce", - "method": "addFactory(address)", - "params": [ - "0xac40b56E7Bb98C2Be5Ee5b3E8B28568b33Fa76CE" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000060ce7c5547ada69042df8ac4f40b74ed0031e90d", - "method": "addVaultImpl(address)", - "params": [ - "0x60CE7c5547Ada69042Df8aC4f40B74ED0031E90d" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000076747fee60601be298e84a8a3d4d2d0dc82555f4", - "method": "addFactory(address)", - "params": [ - "0x76747FeE60601be298E84A8a3D4D2D0dc82555F4" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000028dba0ca8c761c7831fa0a681b8b61ba04ce939", - "method": "addVaultImpl(address)", - "params": [ - "0x028DbA0cA8C761C7831fA0A681b8B61bA04ce939" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000be89b8a90018f1bd458803e713575287e23ca04a", - "method": "addVaultImpl(address)", - "params": [ - "0xBe89b8a90018f1bD458803e713575287E23CA04a" - ] - } -] \ No newline at end of file diff --git a/deployments/hoodi-upgrade-v3-tx.json b/deployments/hoodi-upgrade-v3-tx.json deleted file mode 100644 index a6f695d2..00000000 --- a/deployments/hoodi-upgrade-v3-tx.json +++ /dev/null @@ -1,213 +0,0 @@ -[ - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x256b5a02000000000000000000000000dc1347cc04d4a8945b98a09c3c5585286bba5c2b", - "method": "addVault(address)", - "params": [ - "0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B" - ] - }, - { - "to": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", - "operation": "0", - "value": "0.0", - "data": "0xe0dba60f000000000000000000000000cd5f3c1ba0342e1de907eee09aec52183ef5d99e0000000000000000000000000000000000000000000000000000000000000001", - "method": "setController(address,bool)", - "params": [ - "0xCd5F3C1BA0342e1de907eEE09aeC52183ef5D99e", - true - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000f0f07383f621370eb59a794f36b7d80063d06147", - "method": "removeFactory(address)", - "params": [ - "0xf0F07383F621370Eb59A794f36b7D80063d06147" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000508e82b5119ccfb923c387d62d2ae7b56df79906", - "method": "addFactory(address)", - "params": [ - "0x508e82B5119CCfB923C387d62D2Ae7B56Df79906" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000002b3fd45831bbe53230a5f7e068ca75cd2a8dfaf3", - "method": "addVaultImpl(address)", - "params": [ - "0x2B3Fd45831BBe53230a5f7E068ca75cd2a8DfaF3" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000000f8c209445282d937dac0ea0a6706590250f9afd", - "method": "removeFactory(address)", - "params": [ - "0x0F8c209445282d937DaC0eA0a6706590250F9aFD" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000009115e176c3d034339036194c3eb7014ef04a2e4b", - "method": "addFactory(address)", - "params": [ - "0x9115E176C3d034339036194c3EB7014Ef04A2e4b" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000c43a7b16a7a167c0318390cba16787c11e9e1fd0", - "method": "addVaultImpl(address)", - "params": [ - "0xc43A7b16A7a167c0318390Cba16787C11e9e1FD0" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000b4fea836cdd93ac900100bb6462fe73872e5b524", - "method": "removeFactory(address)", - "params": [ - "0xB4FEA836CDd93Ac900100bB6462fE73872E5B524" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000e2121568066c0a9d794bbb95d0ade0ebd81ccaf9", - "method": "addFactory(address)", - "params": [ - "0xE2121568066C0a9d794bbB95D0Ade0ebd81cCaf9" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000003cc1bde89640e0d32b2d2d66d3098d9bc11b17ee", - "method": "addVaultImpl(address)", - "params": [ - "0x3cc1bde89640E0D32b2D2D66D3098d9Bc11b17Ee" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000068d17efa7cf9e1d121e9ff6138f2336bdb1ccbca", - "method": "removeFactory(address)", - "params": [ - "0x68D17eFa7cf9e1d121e9ff6138f2336bDB1CcBcA" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000bb1b3e55315967c65133a0e942d8ea7a992af6c7", - "method": "addFactory(address)", - "params": [ - "0xBb1B3E55315967c65133A0e942d8EA7a992aF6C7" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000fc81d3369fbeaa6e0926eeda71e5c91724f2c079", - "method": "addVaultImpl(address)", - "params": [ - "0xfc81D3369fBEAa6E0926eedA71E5C91724f2c079" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000ac40b56e7bb98c2be5ee5b3e8b28568b33fa76ce", - "method": "removeFactory(address)", - "params": [ - "0xac40b56E7Bb98C2Be5Ee5b3E8B28568b33Fa76CE" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000076d90928645065b4d4212ee62ce1ba8f90718f14", - "method": "addFactory(address)", - "params": [ - "0x76D90928645065b4D4212eE62ce1ba8f90718f14" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000d935a9f586dfa83df20553b40ce24f3746b258e2", - "method": "addVaultImpl(address)", - "params": [ - "0xD935a9f586dFa83Df20553b40Ce24f3746b258E2" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000076747fee60601be298e84a8a3d4d2d0dc82555f4", - "method": "removeFactory(address)", - "params": [ - "0x76747FeE60601be298E84A8a3D4D2D0dc82555F4" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000004e3de90882b3d10d067b8954909d4a4b0bb390d0", - "method": "addFactory(address)", - "params": [ - "0x4E3dE90882B3d10D067b8954909D4A4b0Bb390D0" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000001e86e620567bb877f5ed13607a1a7b7dbcb6be66", - "method": "addVaultImpl(address)", - "params": [ - "0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000e14fa9bbdb7813025309f71ddc0fa8faae1b9141", - "method": "addVaultImpl(address)", - "params": [ - "0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141" - ] - } -] \ No newline at end of file diff --git a/deployments/hoodi-upgrade-v4-tx.json b/deployments/hoodi-upgrade-v4-tx.json deleted file mode 100644 index ed8dc2da..00000000 --- a/deployments/hoodi-upgrade-v4-tx.json +++ /dev/null @@ -1,72 +0,0 @@ -[ - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000ebf52c2d940f46f2dbfb4982447d15cf589711ad", - "method": "addVaultImpl(address)", - "params": [ - "0xeBF52C2d940F46f2dbFB4982447D15cf589711AD" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000003f2c0a621369fc54f6deec6c9534e980fd2e98d5", - "method": "addVaultImpl(address)", - "params": [ - "0x3F2c0a621369fc54f6DeEC6C9534e980fd2E98d5" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000070e1238e3eb4bda45c0e93e114bd5c7d9c512126", - "method": "addVaultImpl(address)", - "params": [ - "0x70E1238e3eb4bda45C0E93e114bD5C7d9c512126" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000e51ee4200510498d5964627b25fe7d4685cb858c", - "method": "addVaultImpl(address)", - "params": [ - "0xE51eE4200510498d5964627B25FE7D4685CB858c" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000042427acff6ddc93f73fcb53d1a03aa26a292ba1a", - "method": "addVaultImpl(address)", - "params": [ - "0x42427acFf6DdC93f73Fcb53d1a03AA26A292bA1A" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000cd191dfdf52ae7aa2b1ad7b4a6a9d4d4ffb837b5", - "method": "addVaultImpl(address)", - "params": [ - "0xCd191DfDF52ae7aa2B1AD7B4a6A9D4d4FFB837B5" - ] - }, - { - "to": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000008f347eb308707dc1fa1accf3ea889cf554b6b8a5", - "method": "addVaultImpl(address)", - "params": [ - "0x8f347eb308707DC1FA1acCF3ea889CF554b6B8A5" - ] - } -] \ No newline at end of file diff --git a/deployments/hoodi-vault-v2-upgrades.json b/deployments/hoodi-vault-v2-upgrades.json deleted file mode 100644 index 82c4dd78..00000000 --- a/deployments/hoodi-vault-v2-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "2": "0xFe974c6502E59d760B3a27e6D5a4315DC668d716" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "2": "0x3BEc3c1cf81A1176c12550B4315bdd53A2B4Fd5D" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "2": "0xD506fE0B3dDF9e685C16E000514a835D3a511b26" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "2": "0x0C2eC14603Ad9c14a820ad0C91122210Ab84A9e5" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "2": "0x60CE7c5547Ada69042Df8aC4f40B74ED0031E90d" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "2": "0x028DbA0cA8C761C7831fA0A681b8B61bA04ce939" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "2": "0xBe89b8a90018f1bD458803e713575287E23CA04a" - } -} \ No newline at end of file diff --git a/deployments/hoodi-vault-v3-upgrades.json b/deployments/hoodi-vault-v3-upgrades.json deleted file mode 100644 index f4067ab3..00000000 --- a/deployments/hoodi-vault-v3-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "3": "0x2B3Fd45831BBe53230a5f7E068ca75cd2a8DfaF3" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "3": "0xc43A7b16A7a167c0318390Cba16787C11e9e1FD0" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "3": "0x3cc1bde89640E0D32b2D2D66D3098d9Bc11b17Ee" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "3": "0xfc81D3369fBEAa6E0926eedA71E5C91724f2c079" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "3": "0xD935a9f586dFa83Df20553b40Ce24f3746b258E2" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "3": "0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "3": "0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141" - } -} \ No newline at end of file diff --git a/deployments/hoodi-vault-v4-upgrades.json b/deployments/hoodi-vault-v4-upgrades.json deleted file mode 100644 index 44390d35..00000000 --- a/deployments/hoodi-vault-v4-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "4": "0xeBF52C2d940F46f2dbFB4982447D15cf589711AD" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "4": "0x3F2c0a621369fc54f6DeEC6C9534e980fd2E98d5" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "4": "0x70E1238e3eb4bda45C0E93e114bD5C7d9c512126" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "4": "0xE51eE4200510498d5964627B25FE7D4685CB858c" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "4": "0x42427acFf6DdC93f73Fcb53d1a03AA26A292bA1A" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "4": "0xCd191DfDF52ae7aa2B1AD7B4a6A9D4d4FFB837B5" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "4": "0x8f347eb308707DC1FA1acCF3ea889CF554b6B8A5" - } -} \ No newline at end of file diff --git a/deployments/hoodi.json b/deployments/hoodi.json deleted file mode 100644 index 060bd073..00000000 --- a/deployments/hoodi.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "VaultsRegistry": "0xf16fea93D3253A401C3f73B0De890C6586740B25", - "Keeper": "0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f", - "DepositDataRegistry": "0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487", - "EthValidatorsChecker": "0xB790391ee99b9193Ebb80022bf127d24Bac586c4", - "EthGenesisVault": "0xba447498DC4c169f2b4f427B2c4D532320457E89", - "EthFoxVault": "0x468FD65EfA48650F660456a71DC5be32D27D0B46", - "EthVaultFactory": "0x508e82B5119CCfB923C387d62D2Ae7B56Df79906", - "EthPrivVaultFactory": "0x9115E176C3d034339036194c3EB7014Ef04A2e4b", - "EthBlocklistVaultFactory": "0xE2121568066C0a9d794bbB95D0Ade0ebd81cCaf9", - "EthErc20VaultFactory": "0xBb1B3E55315967c65133A0e942d8EA7a992aF6C7", - "EthPrivErc20VaultFactory": "0x76D90928645065b4D4212eE62ce1ba8f90718f14", - "EthBlocklistErc20VaultFactory": "0x4E3dE90882B3d10D067b8954909D4A4b0Bb390D0", - "SharedMevEscrow": "0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd", - "OsToken": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", - "OsTokenConfig": "0x5b817621EBE00622b9a71b53c942b392751c8197", - "OsTokenVaultController": "0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1", - "EthOsTokenVaultEscrow": "0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B", - "OsTokenFlashLoans": "0xCd5F3C1BA0342e1de907eEE09aeC52183ef5D99e", - "PriceFeed": "0xe8a222D887b468a71Ee8a27df4fa3b886A4B7BA1", - "RewardSplitterFactory": "0x80353898B72417AC5701a9809A9eF63F691BdE86", - "CumulativeMerkleDrop": "0xA3bdb3a57626900E4Dd9cC1C2c07bA60F4A44Fbc", - "EthFoxVault1": "0xFb534BB912Eb83b7b629329195b8DF798Ea325b2", - "EthFoxVault2": "0x468FD65EfA48650F660456a71DC5be32D27D0B46" -} diff --git a/deployments/mainnet-upgrade-v2-tx.json b/deployments/mainnet-upgrade-v2-tx.json deleted file mode 100644 index 0b485a43..00000000 --- a/deployments/mainnet-upgrade-v2-tx.json +++ /dev/null @@ -1,186 +0,0 @@ -[ - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000dada5a8e3703b1e3ea2bae5ab704627eb2659fcc", - "method": "removeFactory(address)", - "params": ["0xDada5a8E3703B1e3EA2bAe5Ab704627eb2659fCC"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000faa05900019f6e465086bce16bb3f06992715d53", - "method": "addFactory(address)", - "params": ["0xfaa05900019f6E465086bcE16Bb3F06992715D53"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000035dc754f157b32ba0941ffcd89d16d3d0b2ca6cf", - "method": "addVaultImpl(address)", - "params": ["0x35dC754f157b32Ba0941ffCD89d16d3D0B2cA6CF"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000170618936cd96b1ed8112ec3d3778374b38dfe5e", - "method": "removeFactory(address)", - "params": ["0x170618936cd96B1eD8112eC3D3778374B38DFe5e"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000b7832c9e93e54661354c8b88f3ce7c0915f4c896", - "method": "addFactory(address)", - "params": ["0xb7832C9e93e54661354C8B88F3Ce7c0915f4C896"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000081ab00dd782492d62105b8fa9b03e82d4b57798c", - "method": "addVaultImpl(address)", - "params": ["0x81Ab00dD782492D62105B8fa9B03E82d4B57798C"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000004e3d8197c2cb9bcd29e3dceae3670d3d5e774017", - "method": "addFactory(address)", - "params": ["0x4E3D8197c2cb9bCd29e3DCeAE3670d3d5e774017"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000000e3af59e2496d030e5b2c629784db284fd4cd3c", - "method": "addVaultImpl(address)", - "params": ["0x00e3af59e2496d030E5B2c629784Db284FD4CD3c"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000006ddc10eeeebbbcf00e784ba44fe4b038af26cb53", - "method": "removeFactory(address)", - "params": ["0x6DDc10eEeEBbBcF00E784bA44Fe4B038af26cB53"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000007a4f9912a812d932da57d73cb5e5784b2c1cba4a", - "method": "addFactory(address)", - "params": ["0x7a4F9912a812d932da57d73Cb5E5784B2c1cBA4A"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000ca866585ecfdfcc98348ef2717b811626ed98207", - "method": "addVaultImpl(address)", - "params": ["0xca866585EcFdfCc98348ef2717B811626ED98207"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000e84183effbcc76d022cccc31b95eaa332bb5bb11", - "method": "removeFactory(address)", - "params": ["0xe84183EfFbcc76D022Cccc31b95EAa332bB5Bb11"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000058fdd303ab66722130c01533e7a1177f2b3a2949", - "method": "addFactory(address)", - "params": ["0x58FDD303ab66722130C01533e7A1177f2b3a2949"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000f5f20572186d2fab233dadd753c053ab581ba69a", - "method": "addVaultImpl(address)", - "params": ["0xF5F20572186d2FAB233dADD753C053ab581ba69A"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000001be3ad178d85ce1b6a7fcf5baefe68f26541b07c", - "method": "addFactory(address)", - "params": ["0x1bE3Ad178d85CE1b6a7fCF5baEFe68F26541b07C"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000c25529b4ee01cc6262146433b6509e9e6e30f14a", - "method": "addVaultImpl(address)", - "params": ["0xc25529B4ee01cc6262146433B6509E9e6e30F14a"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000002d491bb32610a0ef1de017e49f949b3799135f31", - "method": "addVaultImpl(address)", - "params": ["0x2D491bb32610A0ef1DE017e49f949b3799135F31"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000032634dec69d4523d2f980be92494dc03bd4c9fce", - "method": "addFactory(address)", - "params": ["0x32634dEc69D4523D2f980Be92494dC03bD4C9fce"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000807305c086a99cbdbff07cb4256ce556d9d6f0af", - "method": "addFactory(address)", - "params": ["0x807305c086A99cbDBff07cB4256cE556d9d6F0af"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000f63666399aa1af203bfc9171147edcb21a6bf3a2", - "method": "addFactory(address)", - "params": ["0xF63666399aA1af203BfC9171147EDcB21A6Bf3A2"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000044ecc30bcc64b832a2cb5d1ff44260b1fcc565e1", - "method": "addFactory(address)", - "params": ["0x44ECC30Bcc64b832A2cB5d1ff44260B1fCC565e1"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000026df36ec050e7f473cbfc30aa42946d3ed11b2c", - "method": "addFactory(address)", - "params": ["0x026dF36Ec050E7f473cbfc30aA42946D3Ed11b2c"] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000006a2835087c6809902a2f39b86fe64ef5dacc31e1", - "method": "addFactory(address)", - "params": ["0x6a2835087C6809902a2f39b86fe64Ef5daCc31e1"] - } -] diff --git a/deployments/mainnet-upgrade-v3-tx.json b/deployments/mainnet-upgrade-v3-tx.json deleted file mode 100644 index c5f682e8..00000000 --- a/deployments/mainnet-upgrade-v3-tx.json +++ /dev/null @@ -1,213 +0,0 @@ -[ - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x256b5a0200000000000000000000000009e84205df7c68907e619d07afd90143c5763605", - "method": "addVault(address)", - "params": [ - "0x09e84205DF7c68907e619D07aFD90143c5763605" - ] - }, - { - "to": "0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38", - "operation": "0", - "value": "0.0", - "data": "0xe0dba60f000000000000000000000000ebe12d858e55ddc5fc5a8153dc3e117824fbf5d20000000000000000000000000000000000000000000000000000000000000001", - "method": "setController(address,bool)", - "params": [ - "0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2", - true - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000faa05900019f6e465086bce16bb3f06992715d53", - "method": "removeFactory(address)", - "params": [ - "0xfaa05900019f6E465086bcE16Bb3F06992715D53" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000df82e5d27e175618e5bc4581ee336f59adabfbb2", - "method": "addFactory(address)", - "params": [ - "0xDF82E5D27E175618e5bC4581ee336F59AdabfBB2" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000009747e1ff73f1759217afd212dd36d21360d0880a", - "method": "addVaultImpl(address)", - "params": [ - "0x9747e1fF73f1759217AFD212Dd36d21360D0880A" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f000000000000000000000000b7832c9e93e54661354c8b88f3ce7c0915f4c896", - "method": "removeFactory(address)", - "params": [ - "0xb7832C9e93e54661354C8B88F3Ce7c0915f4C896" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec500000000000000000000000080fc05f62c35c1b1361bc8908ea0af06c510d390", - "method": "addFactory(address)", - "params": [ - "0x80fC05f62C35C1b1361bc8908ea0aF06C510D390" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000fe076029b7d46fbe2ad4b9cbf377aa10b309e560", - "method": "addVaultImpl(address)", - "params": [ - "0xfe076029B7D46fbe2ad4B9CBf377aA10B309e560" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000004e3d8197c2cb9bcd29e3dceae3670d3d5e774017", - "method": "removeFactory(address)", - "params": [ - "0x4E3D8197c2cb9bCd29e3DCeAE3670d3d5e774017" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec50000000000000000000000008b6c2c9e09c6022780d164f3cfd882808b8bdbf0", - "method": "addFactory(address)", - "params": [ - "0x8b6c2C9E09c6022780D164F3cFd882808b8bDBF0" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000f2f5a23f849e02001da0dfdec0f4cd3c3a79337e", - "method": "addVaultImpl(address)", - "params": [ - "0xF2f5A23f849e02001da0DfdeC0F4CD3c3a79337e" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000007a4f9912a812d932da57d73cb5e5784b2c1cba4a", - "method": "removeFactory(address)", - "params": [ - "0x7a4F9912a812d932da57d73Cb5E5784B2c1cBA4A" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000978302cacadede5d503390e176e86f3889df6ce6", - "method": "addFactory(address)", - "params": [ - "0x978302cAcAdEDE5d503390E176e86F3889Df6Ce6" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000c68ffbf358d6ba32ac86c7be6cd037fbd15d0d46", - "method": "addVaultImpl(address)", - "params": [ - "0xC68FFbF358D6Ba32Ac86C7bE6cd037fbD15D0D46" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f00000000000000000000000058fdd303ab66722130c01533e7a1177f2b3a2949", - "method": "removeFactory(address)", - "params": [ - "0x58FDD303ab66722130C01533e7A1177f2b3a2949" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000291fa5849215847081b475450cbe5de46cfd4fae", - "method": "addFactory(address)", - "params": [ - "0x291Fa5849215847081B475450cBE5De46CfD4fAE" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000008638068a8c0440595cb5a29d245c6ec79d54a09c", - "method": "addVaultImpl(address)", - "params": [ - "0x8638068a8C0440595cb5a29D245c6ec79d54A09c" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x4b37c73f0000000000000000000000001be3ad178d85ce1b6a7fcf5baefe68f26541b07c", - "method": "removeFactory(address)", - "params": [ - "0x1bE3Ad178d85CE1b6a7fCF5baEFe68F26541b07C" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0x29ce1ec5000000000000000000000000e487eddb7c5802e416385544f0a6a4426af4ae87", - "method": "addFactory(address)", - "params": [ - "0xe487EDDB7C5802e416385544f0A6a4426AF4AE87" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000009d2fb07c3d04f54b332b43daa9da982163ba0775", - "method": "addVaultImpl(address)", - "params": [ - "0x9D2fb07c3D04f54b332b43dAa9dA982163Ba0775" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000064375c9a7305edb7bba757319aa4c20e6000bb8c", - "method": "addVaultImpl(address)", - "params": [ - "0x64375C9A7305edb7bbA757319AA4C20e6000bB8c" - ] - } -] \ No newline at end of file diff --git a/deployments/mainnet-upgrade-v4-tx.json b/deployments/mainnet-upgrade-v4-tx.json deleted file mode 100644 index d4316ebc..00000000 --- a/deployments/mainnet-upgrade-v4-tx.json +++ /dev/null @@ -1,72 +0,0 @@ -[ - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000decb606ee9140f229df78f9e40041ead61610f8f", - "method": "addVaultImpl(address)", - "params": [ - "0xDecb606ee9140f229Df78F9E40041EAD61610F8f" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000135f45e0179dd928e73422b40bdc6c5d7047a035", - "method": "addVaultImpl(address)", - "params": [ - "0x135f45e0179dd928E73422B40Bdc6C5d7047a035" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d000000000000000000000000d19e4b1d680a6aa672b08ebf483381bc0c9c8478", - "method": "addVaultImpl(address)", - "params": [ - "0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000007e5198df09fed891e7aecd623cd2231443ceb5d5", - "method": "addVaultImpl(address)", - "params": [ - "0x7E5198DF09fED891e7AecD623cD2231443cEb5d5" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000009488a7dd178f0d927707eec61a7d8c0ae9558c88", - "method": "addVaultImpl(address)", - "params": [ - "0x9488A7dd178F0D927707eEc61A7D8C0ae9558c88" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d00000000000000000000000084d44a696539b3ef4162184fb8ab97596a311e9e", - "method": "addVaultImpl(address)", - "params": [ - "0x84d44A696539B3eF4162184fb8ab97596A311e9E" - ] - }, - { - "to": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "operation": "0", - "value": "0.0", - "data": "0xaff7947d0000000000000000000000009481a47c5650a868839c6511f0eef8bf962fabd7", - "method": "addVaultImpl(address)", - "params": [ - "0x9481A47c5650A868839c6511f0Eef8bF962FABD7" - ] - } -] \ No newline at end of file diff --git a/deployments/mainnet-vault-v2-upgrades.json b/deployments/mainnet-vault-v2-upgrades.json deleted file mode 100644 index 11df2852..00000000 --- a/deployments/mainnet-vault-v2-upgrades.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "2": "0x35dC754f157b32Ba0941ffCD89d16d3D0B2cA6CF" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "2": "0x81Ab00dD782492D62105B8fa9B03E82d4B57798C" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "2": "0x00e3af59e2496d030E5B2c629784Db284FD4CD3c" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "2": "0xca866585EcFdfCc98348ef2717B811626ED98207" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "2": "0xF5F20572186d2FAB233dADD753C053ab581ba69A" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "2": "0xc25529B4ee01cc6262146433B6509E9e6e30F14a" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "2": "0x2D491bb32610A0ef1DE017e49f949b3799135F31" - }, - "0x43d6c07ac63953f42a28f0366affe9895fd54f84336314dd012087bd0941df67": { - "2": "0x59ADB46407EBF4cba923f91F2C06acc4b2e073Bb" - }, - "0x333122211e64a98ebf9b5890e3a33144b1208484d235be41b9d0a827eb1b5b0c": { - "2": "0x792ff341e1dB4AB20FbFB93c0fC071501525E353" - }, - "0x903c7cfddba46ee63384d0bf7016d55c117fc01332779257355a1400c68e97d1": { - "2": "0x3e30370cabD4B4D95Be17706D840FF9de1ADdb67" - }, - "0x778168b2049c66a50853dfa28c8d05dfb083907876871d6640cd612be7e580f2": { - "2": "0x215f4c69c3d1461c7aA38c9c73c27e10cFB0eeE4" - }, - "0x737a47bb3e695a159ef397f75d47c2ca71c770e380ac29b104d3b82ee61be3c8": { - "2": "0xedeBE792C6190Be612Cbe97F628137fAa8C36ee5" - }, - "0x813d21398e0f42fde0737b550f7475616bb950f32cd3f6012ad8b7d81b6c415f": { - "2": "0x5FCd8Bb2e3DDE5809b2106039B741C041bd49E4e" - } -} diff --git a/deployments/mainnet-vault-v3-upgrades.json b/deployments/mainnet-vault-v3-upgrades.json deleted file mode 100644 index 66e1600a..00000000 --- a/deployments/mainnet-vault-v3-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "3": "0x9747e1fF73f1759217AFD212Dd36d21360D0880A" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "3": "0xfe076029B7D46fbe2ad4B9CBf377aA10B309e560" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "3": "0xF2f5A23f849e02001da0DfdeC0F4CD3c3a79337e" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "3": "0xC68FFbF358D6Ba32Ac86C7bE6cd037fbD15D0D46" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "3": "0x8638068a8C0440595cb5a29D245c6ec79d54A09c" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "3": "0x9D2fb07c3D04f54b332b43dAa9dA982163Ba0775" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "3": "0x64375C9A7305edb7bbA757319AA4C20e6000bB8c" - } -} \ No newline at end of file diff --git a/deployments/mainnet-vault-v4-upgrades.json b/deployments/mainnet-vault-v4-upgrades.json deleted file mode 100644 index d0f290cc..00000000 --- a/deployments/mainnet-vault-v4-upgrades.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "0xd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b": { - "4": "0xDecb606ee9140f229Df78F9E40041EAD61610F8f" - }, - "0xa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9": { - "4": "0x135f45e0179dd928E73422B40Bdc6C5d7047a035" - }, - "0xa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20": { - "4": "0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478" - }, - "0x9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd": { - "4": "0x7E5198DF09fED891e7AecD623cD2231443cEb5d5" - }, - "0x3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d": { - "4": "0x9488A7dd178F0D927707eEc61A7D8C0ae9558c88" - }, - "0xad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c": { - "4": "0x84d44A696539B3eF4162184fb8ab97596A311e9E" - }, - "0x11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505": { - "4": "0x9481A47c5650A868839c6511f0Eef8bF962FABD7" - } -} \ No newline at end of file diff --git a/deployments/mainnet.json b/deployments/mainnet.json deleted file mode 100644 index f3b65867..00000000 --- a/deployments/mainnet.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "VaultsRegistry": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", - "Keeper": "0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5", - "DepositDataRegistry": "0x75AB6DdCe07556639333d3Df1eaa684F5735223e", - "EthValidatorsChecker": "0xaC9125646185Cb58e86E77d5f402eFa3fAfAFc84", - "EthGenesisVault": "0xAC0F906E433d58FA868F936E8A43230473652885", - "EthFoxVault": "0x4FEF9D741011476750A243aC70b9789a63dd47Df", - "EthVaultFactory": "0xDF82E5D27E175618e5bC4581ee336F59AdabfBB2", - "EthPrivVaultFactory": "0x80fC05f62C35C1b1361bc8908ea0aF06C510D390", - "EthBlocklistVaultFactory": "0x8b6c2C9E09c6022780D164F3cFd882808b8bDBF0", - "EthErc20VaultFactory": "0x978302cAcAdEDE5d503390E176e86F3889Df6Ce6", - "EthPrivErc20VaultFactory": "0x291Fa5849215847081B475450cBE5De46CfD4fAE", - "EthBlocklistErc20VaultFactory": "0xe487EDDB7C5802e416385544f0A6a4426AF4AE87", - "SharedMevEscrow": "0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86", - "OsToken": "0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38", - "OsTokenConfig": "0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59", - "OsTokenVaultController": "0x2A261e60FB14586B474C208b1B7AC6D0f5000306", - "EthOsTokenVaultEscrow": "0x09e84205DF7c68907e619D07aFD90143c5763605", - "OsTokenFlashLoans": "0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2", - "PriceFeed": "0x8023518b2192FB5384DAdc596765B3dD1cdFe471", - "RewardSplitterFactory": "0x256aF27ce81282A0491A5361172c1Db08f6cC5F8", -} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index d445d48a..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,44 +0,0 @@ -import typescriptEslint from '@typescript-eslint/eslint-plugin' -import globals from 'globals' -import tsParser from '@typescript-eslint/parser' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import js from '@eslint/js' -import { FlatCompat } from '@eslint/eslintrc' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all, -}) - -export default [ - ...compat.extends( - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - 'plugin:prettier/recommended' - ), - { - plugins: { - '@typescript-eslint': typescriptEslint, - }, - - languageOptions: { - globals: { - ...globals.node, - }, - - parser: tsParser, - ecmaVersion: 2020, - sourceType: 'module', - }, - - rules: { - semi: ['error', 'never'], - '@typescript-eslint/no-explicit-any': 'off', - }, - }, -] diff --git a/hardhat.config.ts b/hardhat.config.ts deleted file mode 100644 index b93df658..00000000 --- a/hardhat.config.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { HardhatUserConfig } from 'hardhat/types' -import dotenv from 'dotenv' -import glob from 'glob' -import path from 'path' -import '@nomicfoundation/hardhat-toolbox' -import '@nomicfoundation/hardhat-foundry' -import 'hardhat-contract-sizer' -import 'hardhat-log-remover' -import 'hardhat-spdx-license-identifier' -import 'hardhat-abi-exporter' -import '@openzeppelin/hardhat-upgrades' - -dotenv.config({ path: '.env' }) - -import { Networks } from './helpers/types' -import { MAINNET_FORK, NETWORKS } from './helpers/constants' - -if (!process.env.SKIP_LOAD) { - glob.sync('./tasks/*.ts').forEach((file) => { - // eslint-disable-next-line @typescript-eslint/no-require-imports - require(path.resolve(file)) - }) -} - -const DEFAULT_BLOCK_GAS_LIMIT = 12450000 -const MNEMONIC_PATH = "m/44'/60'/0'/0" -const MNEMONIC = process.env.MNEMONIC || '' -const TRACK_GAS = process.env.TRACK_GAS === 'true' -const BLOCK_EXPLORER_KEY = process.env.BLOCK_EXPLORER_KEY || '' -const HARDHATEVM_CHAINID = 31337 - -// fork -const mainnetFork = MAINNET_FORK.rpcUrl - ? { - blockNumber: MAINNET_FORK.blockNumber, - url: MAINNET_FORK.rpcUrl, - } - : undefined -if (mainnetFork) { - console.log(`Using mainnet fork at block ${mainnetFork.blockNumber}`) -} - -const getCommonNetworkConfig = (networkName) => { - return { - url: NETWORKS[networkName].url, - chainId: NETWORKS[networkName].chainId, - accounts: { - mnemonic: MNEMONIC, - path: MNEMONIC_PATH, - initialIndex: 0, - count: 20, - }, - } -} - -const config: HardhatUserConfig = { - solidity: { - compilers: [ - { - version: '0.8.22', - settings: { - viaIR: true, - optimizer: { - enabled: true, - runs: 200, - details: { - yul: true, - }, - }, - evmVersion: 'shanghai', - }, - }, - ], - }, - networks: { - hoodi: getCommonNetworkConfig(Networks.hoodi), - mainnet: getCommonNetworkConfig(Networks.mainnet), - chiado: getCommonNetworkConfig(Networks.chiado), - gnosis: getCommonNetworkConfig(Networks.gnosis), - hardhat: { - blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT, - gas: DEFAULT_BLOCK_GAS_LIMIT, - chainId: HARDHATEVM_CHAINID, - throwOnTransactionFailures: true, - throwOnCallFailures: true, - accounts: { - accountsBalance: '1000000000000000000000000', - }, - forking: mainnetFork, - }, - local: { - url: 'http://127.0.0.1:8545/', - }, - }, - mocha: { - timeout: 100000000, - }, - gasReporter: { - enabled: TRACK_GAS, - }, - spdxLicenseIdentifier: { - overwrite: false, - runOnCompile: false, - }, - abiExporter: { - path: './abi', - clear: true, - flat: true, - only: ['interfaces/', 'libraries/'], - spacing: 2, - }, - etherscan: { - apiKey: BLOCK_EXPLORER_KEY, - customChains: [ - { - network: 'hoodi', - chainId: 560048, - urls: { - apiURL: 'https://api-hoodi.etherscan.io/api', - browserURL: 'https://hoodi.etherscan.io', - }, - }, - ], - }, -} - -export default config diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index a9960301..00000000 --- a/package-lock.json +++ /dev/null @@ -1,11796 +0,0 @@ -{ - "name": "@stakewise/v3-core", - "version": "3.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@stakewise/v3-core", - "version": "3.0.1", - "license": "BUSL-1.1", - "dependencies": { - "@openzeppelin/contracts": "5.0.2", - "@openzeppelin/contracts-upgradeable": "5.0.2" - }, - "devDependencies": { - "@chainsafe/ssz": "0.18.0", - "@metamask/eth-sig-util": "7.0.3", - "@nomicfoundation/hardhat-foundry": "1.1.3", - "@nomicfoundation/hardhat-toolbox": "5.0.0", - "@openzeppelin/hardhat-upgrades": "3.5.0", - "@openzeppelin/merkle-tree": "1.0.7", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "bls-eth-wasm": "1.1.1", - "dotenv": "16.4.5", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-prettier": "5.2.1", - "ethereumjs-wallet": "1.0.2", - "hardhat-abi-exporter": "2.10.1", - "hardhat-contract-sizer": "2.10.0", - "hardhat-log-remover": "2.1.1", - "hardhat-spdx-license-identifier": "2.3.1", - "husky": "9.1.6", - "keccak256": "1.0.6", - "lint-staged": "15.2.10", - "mocha-chai-jest-snapshot": "1.1.6", - "prettier": "3.3.3", - "prettier-plugin-solidity": "1.4.1" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "dev": true, - "peer": true - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz", - "integrity": "sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==", - "dev": true, - "dependencies": { - "@aws-crypto/util": "^1.2.2", - "@aws-sdk/types": "^3.1.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/util": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-1.2.2.tgz", - "integrity": "sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "^3.1.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.664.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.664.0.tgz", - "integrity": "sha512-+GtXktvVgpreM2b+NJL9OqZGsOzHwlCUrO8jgQUvH/yA6Kd8QO2YFhQCp0C9sSzTteZJVqGBu8E0CQurxJHPbw==", - "dev": true, - "dependencies": { - "@smithy/types": "^3.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/types/node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true - }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dev": true, - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.25.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", - "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", - "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.8", - "@babel/template": "^7.25.7", - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.8", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-simple-access": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "@babel/traverse": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.8" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", - "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", - "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz", - "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@chainsafe/as-sha256": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.5.0.tgz", - "integrity": "sha512-dTIY6oUZNdC5yDTVP5Qc9hAlKAsn0QTQ2DnQvvsbTnKSTbYs3p5RPN0aIUqN0liXei/9h24c7V0dkV44cnWIQA==", - "dev": true - }, - "node_modules/@chainsafe/hashtree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@chainsafe/hashtree/-/hashtree-1.0.1.tgz", - "integrity": "sha512-bleu9FjqBeR/l6W1u2Lz+HsS0b0LLJX2eUt3hOPBN7VqOhidx8wzkVh2S7YurS+iTQtfdK4K5QU9tcTGNrGwDg==", - "dev": true, - "engines": { - "node": ">= 18" - }, - "optionalDependencies": { - "@chainsafe/hashtree-darwin-arm64": "1.0.1", - "@chainsafe/hashtree-linux-arm64-gnu": "1.0.1", - "@chainsafe/hashtree-linux-x64-gnu": "1.0.1" - } - }, - "node_modules/@chainsafe/hashtree-darwin-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@chainsafe/hashtree-darwin-arm64/-/hashtree-darwin-arm64-1.0.1.tgz", - "integrity": "sha512-+KmEgQMpO7FDL3klAcpXbQ4DPZvfCe0qSaBBrtT4vLF8V1JGm3sp+j7oibtxtOsLKz7nJMiK1pZExi7vjXu8og==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@chainsafe/hashtree-linux-arm64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@chainsafe/hashtree-linux-arm64-gnu/-/hashtree-linux-arm64-gnu-1.0.1.tgz", - "integrity": "sha512-p1hnhGq2aFY+Zhdn1Q6L/6yLYNKjqXfn/Pc8jiM0e3+Lf/hB+yCdqYVu1pto26BrZjugCFZfupHaL4DjUTDttw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@chainsafe/hashtree-linux-x64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@chainsafe/hashtree-linux-x64-gnu/-/hashtree-linux-x64-gnu-1.0.1.tgz", - "integrity": "sha512-uCIGuUWuWV0LiB4KLMy6JFa7Jp6NmPl3hKF5BYWu8TzUBe7vSXMZfqTzGxXPggFYN2/0KymfRdG9iDCOJfGRqg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@chainsafe/persistent-merkle-tree": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.8.0.tgz", - "integrity": "sha512-hh6C1JO6SKlr0QGNTNtTLqgGVMA/Bc20wD6CeMHp+wqbFKCULRJuBUxhF4WDx/7mX8QlqF3nFriF/Eo8oYJ4/A==", - "dev": true, - "dependencies": { - "@chainsafe/as-sha256": "0.5.0", - "@chainsafe/hashtree": "1.0.1", - "@noble/hashes": "^1.3.0" - } - }, - "node_modules/@chainsafe/ssz": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.18.0.tgz", - "integrity": "sha512-1ikTjk3JK6+fsGWiT5IvQU0AP6gF3fDzGmPfkKthbcbgTUR8fjB83Ywp9ko/ZoiDGfrSFkATgT4hvRzclu0IAA==", - "dev": true, - "dependencies": { - "@chainsafe/as-sha256": "0.5.0", - "@chainsafe/persistent-merkle-tree": "0.8.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", - "dev": true, - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@ethereumjs/common": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", - "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", - "dev": true, - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "crc-32": "^1.2.0" - } - }, - "node_modules/@ethereumjs/rlp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", - "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", - "dev": true, - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/tx": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", - "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", - "dev": true, - "dependencies": { - "@ethereumjs/common": "^3.2.0", - "@ethereumjs/rlp": "^4.0.1", - "@ethereumjs/util": "^8.1.0", - "ethereum-cryptography": "^2.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/util": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", - "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", - "dev": true, - "dependencies": { - "@ethereumjs/rlp": "^4.0.1", - "ethereum-cryptography": "^2.0.0", - "micro-ftch": "^0.3.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethersproject/abi": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", - "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", - "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", - "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", - "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/rlp": "^5.7.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", - "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0" - } - }, - "node_modules/@ethersproject/basex": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", - "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", - "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", - "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0" - } - }, - "node_modules/@ethersproject/contracts": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", - "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", - "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/hdnode": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", - "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "node_modules/@ethersproject/json-wallets": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", - "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true, - "peer": true - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", - "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@ethersproject/networks": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", - "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/pbkdf2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", - "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/providers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", - "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0", - "bech32": "1.1.4", - "ws": "7.4.6" - } - }, - "node_modules/@ethersproject/providers/node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@ethersproject/random": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", - "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", - "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/sha2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", - "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", - "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "bn.js": "^5.2.1", - "elliptic": "6.5.4", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", - "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", - "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0" - } - }, - "node_modules/@ethersproject/units": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", - "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/wallet": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", - "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", - "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/wordlists": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", - "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", - "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", - "dev": true, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", - "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", - "dev": true, - "dependencies": { - "@humanfs/core": "^0.19.0", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@metamask/abi-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@metamask/abi-utils/-/abi-utils-2.0.4.tgz", - "integrity": "sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ==", - "dev": true, - "dependencies": { - "@metamask/superstruct": "^3.1.0", - "@metamask/utils": "^9.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/eth-sig-util": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-7.0.3.tgz", - "integrity": "sha512-PAtGnOkYvh90k2lEZldq/FK7GTLF6WxE+2bV85PoA3pqlJnmJCAY62tuvxHSwnVngSKlc4mcNvjnUg2eYO6JGg==", - "dev": true, - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "@metamask/abi-utils": "^2.0.4", - "@metamask/utils": "^9.0.0", - "@scure/base": "~1.1.3", - "ethereum-cryptography": "^2.1.2", - "tweetnacl": "^1.0.3" - }, - "engines": { - "node": "^16.20 || ^18.16 || >=20" - } - }, - "node_modules/@metamask/superstruct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.1.0.tgz", - "integrity": "sha512-N08M56HdOgBfRKkrgCMZvQppkZGcArEop3kixNEtVbJKm6P9Cfg0YkI6X0s1g78sNrj2fWUwvJADdZuzJgFttA==", - "dev": true, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", - "dev": true, - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", - "dev": true, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nomicfoundation/edr": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.3.tgz", - "integrity": "sha512-hThe5ORR75WFYTXKL0K2AyLDxkTMrG+VQ1yL9BhQYsuh3OIH+3yNDxMz2LjfvrpOrMmJ4kk5NKdFewpqDojjXQ==", - "dev": true, - "peer": true, - "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.6.3", - "@nomicfoundation/edr-darwin-x64": "0.6.3", - "@nomicfoundation/edr-linux-arm64-gnu": "0.6.3", - "@nomicfoundation/edr-linux-arm64-musl": "0.6.3", - "@nomicfoundation/edr-linux-x64-gnu": "0.6.3", - "@nomicfoundation/edr-linux-x64-musl": "0.6.3", - "@nomicfoundation/edr-win32-x64-msvc": "0.6.3" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.3.tgz", - "integrity": "sha512-hqtI7tYDqKG5PDmZ//Z65EH5cgH8VL/SAAu50rpHP7WAVfJWkOCcYbecywwF6nhHdonJbRTDGAeG1/+VOy6zew==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.3.tgz", - "integrity": "sha512-4fGi79/lyOlRUORhCYsYb3sWqRHuHT7qqzyZfZuNOn8llaxmT1k36xNmvpyg37R8SzjnhT/DzoukSJrs23Ip9Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.3.tgz", - "integrity": "sha512-yFFTvGFMhfAvQ1Z2itUh1jpoUA+mVROyVELcaxjIq8fyg602lQmbS+NXkhQ+oaeDgJ+06mSENrHBg4fcfRf9cw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.3.tgz", - "integrity": "sha512-pOKmd0Fa3a6BHg5qbjbl/jMRELVi9oazbfiuU7Bvgn/dpTK+ID3jwT0SXiuC2zxjmPByWgXL6G9XRf5BPAM2rQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.3.tgz", - "integrity": "sha512-3AUferhkLIXtLV63w5GjpHttzdxZ36i656XMy+pkBZbbiqnzIVeKWg6DJv1A94fQY16gB4gqj9CLq4CWvbNN6w==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.3.tgz", - "integrity": "sha512-fr6bD872WIBXe9YnTDi0CzYepMcYRgSnkVqn0yK4wRnIvKrloWhxXNVY45GVIl51aNZguBnvoA4WEt6HIazs3A==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.3.tgz", - "integrity": "sha512-sn34MvN1ajw2Oq1+Drpxej78Z0HfIzI4p4WlolupAV9dOZKzp2JAIQeLVfZpjIFbF3zuyxLPP4dUBrQoFPEqhA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/ethereumjs-common": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", - "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", - "dev": true, - "peer": true, - "dependencies": { - "@nomicfoundation/ethereumjs-util": "9.0.4" - } - }, - "node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", - "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", - "dev": true, - "peer": true, - "bin": { - "rlp": "bin/rlp.cjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", - "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", - "dev": true, - "peer": true, - "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.4", - "@nomicfoundation/ethereumjs-rlp": "5.0.4", - "@nomicfoundation/ethereumjs-util": "9.0.4", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } - } - }, - "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "peer": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", - "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", - "dev": true, - "peer": true, - "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "5.0.4", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } - } - }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "peer": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@nomicfoundation/hardhat-chai-matchers": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz", - "integrity": "sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/chai-as-promised": "^7.1.3", - "chai-as-promised": "^7.1.1", - "deep-eql": "^4.0.1", - "ordinal": "^1.0.3" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "chai": "^4.2.0", - "ethers": "^6.1.0", - "hardhat": "^2.9.4" - } - }, - "node_modules/@nomicfoundation/hardhat-ethers": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz", - "integrity": "sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "^4.1.1", - "lodash.isequal": "^4.5.0" - }, - "peerDependencies": { - "ethers": "^6.1.0", - "hardhat": "^2.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-foundry": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.3.tgz", - "integrity": "sha512-30Ezc3hlZ4pC5Z/9W9euW5uoPKKQQKaecLETHJH8BPpd30zYOooy6HfjmcTY1/taOQjlwirOdNO7tHlje8Qcgw==", - "dev": true, - "dependencies": { - "picocolors": "^1.1.0" - }, - "peerDependencies": { - "hardhat": "^2.17.2" - } - }, - "node_modules/@nomicfoundation/hardhat-ignition": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.6.tgz", - "integrity": "sha512-PcMf4xlYvwHYej2jcuOd/rBNNMM5FO11vh9c+MF8+m7NxV4b6NOameL3uscoD7ghg0H2GNgnGXgQ67ryRqtdIQ==", - "dev": true, - "peer": true, - "dependencies": { - "@nomicfoundation/ignition-core": "^0.15.6", - "@nomicfoundation/ignition-ui": "^0.15.6", - "chalk": "^4.0.0", - "debug": "^4.3.2", - "fs-extra": "^10.0.0", - "json5": "^2.2.3", - "prompts": "^2.4.2" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-verify": "^2.0.1", - "hardhat": "^2.18.0" - } - }, - "node_modules/@nomicfoundation/hardhat-ignition-ethers": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.6.tgz", - "integrity": "sha512-+jXDGWdfkuIGm0W+aFEZ9SLQz2MIj7Cf4j7ANTXUIIbK8sUkvnVOhTTAQEdqa0KgGEb45XS88BPg0w8fixwrXQ==", - "dev": true, - "peer": true, - "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-ignition": "^0.15.6", - "@nomicfoundation/ignition-core": "^0.15.6", - "ethers": "^6.7.0", - "hardhat": "^2.18.0" - } - }, - "node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz", - "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==", - "dev": true, - "peer": true, - "dependencies": { - "ethereumjs-util": "^7.1.4" - }, - "peerDependencies": { - "hardhat": "^2.9.5" - } - }, - "node_modules/@nomicfoundation/hardhat-toolbox": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-5.0.0.tgz", - "integrity": "sha512-FnUtUC5PsakCbwiVNsqlXVIWG5JIb5CEZoSXbJUsEBun22Bivx2jhF1/q9iQbzuaGpJKFQyOhemPB2+XlEE6pQ==", - "dev": true, - "peerDependencies": { - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@nomicfoundation/hardhat-ignition-ethers": "^0.15.0", - "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-verify": "^2.0.0", - "@typechain/ethers-v6": "^0.5.0", - "@typechain/hardhat": "^9.0.0", - "@types/chai": "^4.2.0", - "@types/mocha": ">=9.1.0", - "@types/node": ">=18.0.0", - "chai": "^4.2.0", - "ethers": "^6.4.0", - "hardhat": "^2.11.0", - "hardhat-gas-reporter": "^1.0.8", - "solidity-coverage": "^0.8.1", - "ts-node": ">=8.0.0", - "typechain": "^8.3.0", - "typescript": ">=4.5.0" - } - }, - "node_modules/@nomicfoundation/hardhat-verify": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.11.tgz", - "integrity": "sha512-lGIo4dNjVQFdsiEgZp3KP6ntLiF7xJEJsbNHfSyIiFCyI0Yv0518ElsFtMC5uCuHEChiBBMrib9jWQvHHT+X3Q==", - "dev": true, - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@ethersproject/address": "^5.0.2", - "cbor": "^8.1.0", - "chalk": "^2.4.2", - "debug": "^4.1.1", - "lodash.clonedeep": "^4.5.0", - "semver": "^6.3.0", - "table": "^6.8.0", - "undici": "^5.14.0" - }, - "peerDependencies": { - "hardhat": "^2.0.4" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomicfoundation/ignition-core": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.6.tgz", - "integrity": "sha512-9eD1NJ2G4vh7IleRNmCz/3bGVoNEPYrRVPqx0uvWzG2xD226GGQcTgtK+NovyxsQOE/AcLF1xjX3/+8kNc1sSg==", - "dev": true, - "peer": true, - "dependencies": { - "@ethersproject/address": "5.6.1", - "@nomicfoundation/solidity-analyzer": "^0.1.1", - "cbor": "^9.0.0", - "debug": "^4.3.2", - "ethers": "^6.7.0", - "fs-extra": "^10.0.0", - "immer": "10.0.2", - "lodash": "4.17.21", - "ndjson": "2.0.0" - } - }, - "node_modules/@nomicfoundation/ignition-core/node_modules/@ethersproject/address": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz", - "integrity": "sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.6.2", - "@ethersproject/bytes": "^5.6.1", - "@ethersproject/keccak256": "^5.6.1", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.1" - } - }, - "node_modules/@nomicfoundation/ignition-core/node_modules/cbor": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.2.tgz", - "integrity": "sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==", - "dev": true, - "peer": true, - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@nomicfoundation/ignition-ui": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.6.tgz", - "integrity": "sha512-CW14g/BVcGZtBSF1K4eZSCjyvtz1fr9yppkFKC+Z0+sm/lXFWpwcwaVN+UiugQ/9wz9HAfSk4Y0gagdAMiSs0w==", - "dev": true, - "peer": true - }, - "node_modules/@nomicfoundation/slang": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-0.17.0.tgz", - "integrity": "sha512-1GlkGRcGpVnjFw9Z1vvDKOKo2mzparFt7qrl2pDxWp+jrVtlvej98yCMX52pVyrYE7ZeOSZFnx/DtsSgoukStQ==", - "dev": true, - "dependencies": { - "@nomicfoundation/slang-darwin-arm64": "0.17.0", - "@nomicfoundation/slang-darwin-x64": "0.17.0", - "@nomicfoundation/slang-linux-arm64-gnu": "0.17.0", - "@nomicfoundation/slang-linux-arm64-musl": "0.17.0", - "@nomicfoundation/slang-linux-x64-gnu": "0.17.0", - "@nomicfoundation/slang-linux-x64-musl": "0.17.0", - "@nomicfoundation/slang-win32-arm64-msvc": "0.17.0", - "@nomicfoundation/slang-win32-ia32-msvc": "0.17.0", - "@nomicfoundation/slang-win32-x64-msvc": "0.17.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-darwin-arm64": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-darwin-arm64/-/slang-darwin-arm64-0.17.0.tgz", - "integrity": "sha512-O0q94EUtoWy9A5kOTOa9/khtxXDYnLqmuda9pQELurSiwbQEVCPQL8kb34VbOW+ifdre66JM/05Xw9JWhIZ9sA==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-darwin-x64": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-darwin-x64/-/slang-darwin-x64-0.17.0.tgz", - "integrity": "sha512-IaDbHzvT08sBK2HyGzonWhq1uu8IxdjmTqAWHr25Oh/PYnamdi8u4qchZXXYKz/DHLoYN3vIpBXoqLQIomhD/g==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-linux-arm64-gnu": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-arm64-gnu/-/slang-linux-arm64-gnu-0.17.0.tgz", - "integrity": "sha512-Lj4anvOsQZxs1SycG8VyT2Rl2oqIhyLSUCgGepTt3CiJ/bM+8r8bLJIgh8vKkki4BWz49YsYIgaJB2IPv8FFTw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-linux-arm64-musl": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-arm64-musl/-/slang-linux-arm64-musl-0.17.0.tgz", - "integrity": "sha512-/xkTCa9d5SIWUBQE3BmLqDFfJRr4yUBwbl4ynPiGUpRXrD69cs6pWKkwjwz/FdBpXqVo36I+zY95qzoTj/YhOA==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-linux-x64-gnu": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-x64-gnu/-/slang-linux-x64-gnu-0.17.0.tgz", - "integrity": "sha512-oe5IO5vntOqYvTd67deCHPIWuSuWm6aYtT2/0Kqz2/VLtGz4ClEulBSRwfnNzBVtw2nksWipE1w8BzhImI7Syg==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-linux-x64-musl": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-x64-musl/-/slang-linux-x64-musl-0.17.0.tgz", - "integrity": "sha512-PpYCI5K/kgLAMXaPY0V4VST5gCDprEOh7z/47tbI8kJQumI5odjsj/Cs8MpTo7/uRH6flKYbVNgUzcocWVYrAQ==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-win32-arm64-msvc": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-arm64-msvc/-/slang-win32-arm64-msvc-0.17.0.tgz", - "integrity": "sha512-u/Mkf7OjokdBilP7QOJj6QYJU4/mjkbKnTX21wLyCIzeVWS7yafRPYpBycKIBj2pRRZ6ceAY5EqRpb0aiCq+0Q==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-win32-ia32-msvc": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-ia32-msvc/-/slang-win32-ia32-msvc-0.17.0.tgz", - "integrity": "sha512-XJBVQfNnZQUv0tP2JSJ573S+pmgrLWgqSZOGaMllnB/TL1gRci4Z7dYRJUF2s82GlRJE+FHSI2Ro6JISKmlXCg==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/slang-win32-x64-msvc": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-x64-msvc/-/slang-win32-x64-msvc-0.17.0.tgz", - "integrity": "sha512-zPGsAeiTfqfPNYHD8BfrahQmYzA78ZraoHKTGraq/1xwJwzBK4bu/NtvVA4pJjBV+B4L6DCxVhSbpn40q26JQA==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", - "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 12" - }, - "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", - "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", - "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", - "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", - "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", - "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", - "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", - "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@openzeppelin/contracts": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.2.tgz", - "integrity": "sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==" - }, - "node_modules/@openzeppelin/contracts-upgradeable": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.2.tgz", - "integrity": "sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ==", - "peerDependencies": { - "@openzeppelin/contracts": "5.0.2" - } - }, - "node_modules/@openzeppelin/defender-sdk-base-client": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.15.0.tgz", - "integrity": "sha512-nuf/xegMIuKCO0hMrxI1KQKTzQw1iCl/9kew2nJM9MrFIohhfEXItc5rbJRoV/jehmK/Jhi9ATF9OHH09StEsQ==", - "dev": true, - "dependencies": { - "amazon-cognito-identity-js": "^6.3.6", - "async-retry": "^1.3.3" - } - }, - "node_modules/@openzeppelin/defender-sdk-deploy-client": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.15.0.tgz", - "integrity": "sha512-2ODMN4j5pPYWyIOvA/zRQmJ0tJyqi6NV3S/PyvufBXa3oj/MDnVO5bMGSQFH0M2VE3bg+i/rcUb0hdbX9Rtm5Q==", - "dev": true, - "dependencies": { - "@openzeppelin/defender-sdk-base-client": "^1.15.0", - "axios": "^1.7.2", - "lodash": "^4.17.21" - } - }, - "node_modules/@openzeppelin/defender-sdk-network-client": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.15.0.tgz", - "integrity": "sha512-tNynCqFB1XYancq/8yGuj0HCSIyNLSRSuH53Hp2Tl+DpM7W5vIkzSRfvJJxC+8Sld83bVavyNJzTN9xid992Ag==", - "dev": true, - "dependencies": { - "@openzeppelin/defender-sdk-base-client": "^1.15.0", - "axios": "^1.7.2", - "lodash": "^4.17.21" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.5.0.tgz", - "integrity": "sha512-Ju/JnT7NRiOMi5m5Y0dGiz37d8wnjVBep1v5Vr7+6+MFNuQa1yddUEVWhWhoEw4udI3/mYwyw4Sfz3sq7vhicQ==", - "dev": true, - "dependencies": { - "@openzeppelin/defender-sdk-base-client": "^1.14.4", - "@openzeppelin/defender-sdk-deploy-client": "^1.14.4", - "@openzeppelin/defender-sdk-network-client": "^1.14.4", - "@openzeppelin/upgrades-core": "^1.40.0", - "chalk": "^4.1.0", - "debug": "^4.1.1", - "ethereumjs-util": "^7.1.5", - "proper-lockfile": "^4.1.1", - "undici": "^6.11.1" - }, - "bin": { - "migrate-oz-cli-project": "dist/scripts/migrate-oz-cli-project.js" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@nomicfoundation/hardhat-verify": "^2.0.0", - "ethers": "^6.6.0", - "hardhat": "^2.0.2" - }, - "peerDependenciesMeta": { - "@nomicfoundation/hardhat-verify": { - "optional": true - } - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/undici": { - "version": "6.20.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.20.1.tgz", - "integrity": "sha512-AjQF1QsmqfJys+LXfGTNum+qw4S88CojRInG/6t31W/1fk6G59s92bnAvGz5Cmur+kQv2SURXEvvudLmbrE8QA==", - "dev": true, - "engines": { - "node": ">=18.17" - } - }, - "node_modules/@openzeppelin/merkle-tree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@openzeppelin/merkle-tree/-/merkle-tree-1.0.7.tgz", - "integrity": "sha512-i93t0YYv6ZxTCYU3CdO5Q+DXK0JH10A4dCBOMlzYbX+ujTXm+k1lXiEyVqmf94t3sqmv8sm/XT5zTa0+efnPgQ==", - "dev": true, - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0" - } - }, - "node_modules/@openzeppelin/upgrades-core": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.40.0.tgz", - "integrity": "sha512-4bPSXdEqHsNRL5T1ybPLneWGYjzGl6XWGWkv7aUoFFgz8mOdarstRBX1Wi4XJFw6IeHPUI7mMSQr2jdz8Y2ypQ==", - "dev": true, - "dependencies": { - "@nomicfoundation/slang": "^0.17.0", - "cbor": "^9.0.0", - "chalk": "^4.1.0", - "compare-versions": "^6.0.0", - "debug": "^4.1.1", - "ethereumjs-util": "^7.0.3", - "minimatch": "^9.0.5", - "minimist": "^1.2.7", - "proper-lockfile": "^4.1.1", - "solidity-ast": "^0.4.51" - }, - "bin": { - "openzeppelin-upgrades-core": "dist/cli/cli.js" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/cbor": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.2.tgz", - "integrity": "sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==", - "dev": true, - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@sentry/core": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", - "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", - "dev": true, - "peer": true, - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/hub": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", - "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", - "dev": true, - "peer": true, - "dependencies": { - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/minimal": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", - "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", - "dev": true, - "peer": true, - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/node": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", - "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", - "dev": true, - "peer": true, - "dependencies": { - "@sentry/core": "5.30.0", - "@sentry/hub": "5.30.0", - "@sentry/tracing": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", - "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", - "dev": true, - "peer": true, - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", - "dev": true, - "peer": true, - "dependencies": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@smithy/types": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.5.0.tgz", - "integrity": "sha512-QN0twHNfe8mNJdH9unwsCK13GURU7oEAZqkBI+rsvpv1jrmserO+WnLE7jidR9W/1dxwZ0u/CB01mV2Gms/K2Q==", - "dev": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/types/node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true - }, - "node_modules/@solidity-parser/parser": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", - "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", - "dev": true, - "peer": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "peer": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "peer": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "peer": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "peer": true - }, - "node_modules/@typechain/ethers-v6": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", - "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", - "dev": true, - "peer": true, - "dependencies": { - "lodash": "^4.17.15", - "ts-essentials": "^7.0.1" - }, - "peerDependencies": { - "ethers": "6.x", - "typechain": "^8.3.2", - "typescript": ">=4.7.0" - } - }, - "node_modules/@typechain/hardhat": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-9.1.0.tgz", - "integrity": "sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA==", - "dev": true, - "peer": true, - "dependencies": { - "fs-extra": "^9.1.0" - }, - "peerDependencies": { - "@typechain/ethers-v6": "^0.5.1", - "ethers": "^6.1.0", - "hardhat": "^2.9.9", - "typechain": "^8.3.2" - } - }, - "node_modules/@typechain/hardhat/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "peer": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@types/bn.js": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", - "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/chai": { - "version": "4.3.20", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", - "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", - "dev": true, - "peer": true - }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/concat-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", - "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true - }, - "node_modules/@types/form-data": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", - "dev": true, - "peer": true - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "peer": true - }, - "node_modules/@types/mocha": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", - "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", - "dev": true, - "peer": true - }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", - "dev": true - }, - "node_modules/@types/node": { - "version": "22.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", - "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", - "dev": true, - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", - "dev": true, - "peer": true - }, - "node_modules/@types/qs": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", - "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", - "dev": true, - "peer": true - }, - "node_modules/@types/secp256k1": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", - "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz", - "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/type-utils": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.9.0.tgz", - "integrity": "sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz", - "integrity": "sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz", - "integrity": "sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.9.0.tgz", - "integrity": "sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz", - "integrity": "sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.9.0.tgz", - "integrity": "sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz", - "integrity": "sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", - "dev": true, - "peer": true - }, - "node_modules/acorn": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", - "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "peer": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/aes-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", - "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", - "dev": true - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "peer": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/amazon-cognito-identity-js": { - "version": "6.3.12", - "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.12.tgz", - "integrity": "sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-js": "1.2.2", - "buffer": "4.9.2", - "fast-base64-decode": "^1.0.0", - "isomorphic-unfetch": "^3.0.0", - "js-cookie": "^2.2.1" - } - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "peer": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "peer": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/antlr4ts": { - "version": "0.5.0-alpha.4", - "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", - "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", - "dev": true, - "peer": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "peer": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, - "peer": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", - "dev": true, - "peer": true - }, - "node_modules/async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dev": true, - "dependencies": { - "retry": "0.13.1" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base-x": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", - "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true, - "peer": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", - "dev": true - }, - "node_modules/bls-eth-wasm": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bls-eth-wasm/-/bls-eth-wasm-1.1.1.tgz", - "integrity": "sha512-yaoOHCgjICZc2qTpYCvIkJ6L4N2MXBNmdhIpTZGmKZOUc3mmU941EV95qMK02apyYRSKuCydPuCN3fK4o24C1g==", - "dev": true - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "peer": true - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "dev": true, - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "dev": true, - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "peer": true - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "peer": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true, - "peer": true - }, - "node_modules/cbor": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", - "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", - "dev": true, - "peer": true, - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "peer": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "peer": true, - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "peer": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", - "dev": true, - "peer": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true, - "peer": true - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", - "dev": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "peer": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", - "dev": true, - "peer": true - }, - "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-usage": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", - "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^4.0.2", - "chalk": "^2.4.2", - "table-layout": "^1.0.2", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/command-line-usage/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/command-line-usage/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/command-line-usage/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true - }, - "node_modules/command-line-usage/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/command-line-usage/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "peer": true - }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "peer": true - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "peer": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/death": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", - "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", - "dev": true, - "peer": true - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "peer": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "peer": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delete-empty": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/delete-empty/-/delete-empty-3.0.0.tgz", - "integrity": "sha512-ZUyiwo76W+DYnKsL3Kim6M/UOavPdBJgDYWOmuQhYaZvJH0AXAHbUNyEDtRbBra8wqqr686+63/0azfEk1ebUQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.0", - "minimist": "^1.2.0", - "path-starts-with": "^2.0.0", - "rimraf": "^2.6.2" - }, - "bin": { - "delete-empty": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/difflib": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", - "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", - "dev": true, - "peer": true, - "dependencies": { - "heap": ">= 0.2.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "peer": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.40", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.40.tgz", - "integrity": "sha512-LYm78o6if4zTasnYclgQzxEcgMoIcybWOhkATWepN95uwVVWV0/IW10v+2sIeHE+bIYWipLneTftVyQm45UY7g==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "peer": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", - "dev": true, - "peer": true, - "dependencies": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.12.0" - }, - "optionalDependencies": { - "source-map": "~0.2.0" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "peer": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", - "dev": true, - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eth-gas-reporter": { - "version": "0.2.27", - "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", - "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", - "dev": true, - "peer": true, - "dependencies": { - "@solidity-parser/parser": "^0.14.0", - "axios": "^1.5.1", - "cli-table3": "^0.5.0", - "colors": "1.4.0", - "ethereum-cryptography": "^1.0.3", - "ethers": "^5.7.2", - "fs-readdir-recursive": "^1.1.0", - "lodash": "^4.17.14", - "markdown-table": "^1.1.3", - "mocha": "^10.2.0", - "req-cwd": "^2.0.0", - "sha1": "^1.1.1", - "sync-request": "^6.0.0" - }, - "peerDependencies": { - "@codechecks/client": "^0.1.0" - }, - "peerDependenciesMeta": { - "@codechecks/client": { - "optional": true - } - } - }, - "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true - }, - "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-gas-reporter/node_modules/cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", - "dev": true, - "peer": true, - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/eth-gas-reporter/node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-gas-reporter/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "peer": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-gas-reporter/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ethereum-bloom-filters": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz", - "integrity": "sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "^1.4.0" - } - }, - "node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethereumjs-abi": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", - "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", - "dev": true, - "peer": true, - "dependencies": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - } - }, - "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/ethereumjs-abi/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true, - "peer": true - }, - "node_modules/ethereumjs-abi/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "peer": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/ethereumjs-util": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", - "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", - "dev": true, - "dependencies": { - "@types/bn.js": "^5.1.0", - "bn.js": "^5.1.2", - "create-hash": "^1.1.2", - "ethereum-cryptography": "^0.1.3", - "rlp": "^2.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/ethereumjs-wallet": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", - "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", - "dev": true, - "dependencies": { - "aes-js": "^3.1.2", - "bs58check": "^2.1.2", - "ethereum-cryptography": "^0.1.3", - "ethereumjs-util": "^7.1.2", - "randombytes": "^2.1.0", - "scrypt-js": "^3.0.1", - "utf8": "^3.0.0", - "uuid": "^8.3.2" - } - }, - "node_modules/ethereumjs-wallet/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/ethereumjs-wallet/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/ethers": { - "version": "6.13.4", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.4.tgz", - "integrity": "sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "dev": true, - "peer": true, - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ethers/node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "dev": true, - "peer": true - }, - "node_modules/ethers/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, - "peer": true - }, - "node_modules/ethjs-unit": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", - "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", - "dev": true, - "peer": true, - "dependencies": { - "bn.js": "4.11.6", - "number-to-bn": "1.7.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/ethjs-unit/node_modules/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", - "dev": true, - "peer": true - }, - "node_modules/ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "dev": true, - "peer": true, - "dependencies": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-base64-decode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", - "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", - "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", - "dev": true, - "peer": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-package-json": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-package-json/-/find-package-json-1.2.0.tgz", - "integrity": "sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==", - "dev": true - }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "peer": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fp-ts": { - "version": "1.19.3", - "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", - "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", - "dev": true, - "peer": true - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true, - "peer": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ghost-testrpc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", - "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", - "dev": true, - "peer": true, - "dependencies": { - "chalk": "^2.4.2", - "node-emoji": "^1.10.0" - }, - "bin": { - "testrpc-sc": "index.js" - } - }, - "node_modules/ghost-testrpc/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ghost-testrpc/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ghost-testrpc/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/ghost-testrpc/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true - }, - "node_modules/ghost-testrpc/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ghost-testrpc/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ghost-testrpc/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "peer": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "peer": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "peer": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "peer": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hardhat": { - "version": "2.22.13", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.13.tgz", - "integrity": "sha512-psVJX4FSXDpSXwsU8OcKTJN04pQEj9cFBMX5OPko+OFwbIoiOpvRmafa954/UaA1934npTj8sV3gaTSdx9bPbA==", - "dev": true, - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.6.3", - "@nomicfoundation/ethereumjs-common": "4.0.4", - "@nomicfoundation/ethereumjs-tx": "5.0.4", - "@nomicfoundation/ethereumjs-util": "9.0.4", - "@nomicfoundation/solidity-analyzer": "^0.1.0", - "@sentry/node": "^5.18.1", - "@types/bn.js": "^5.1.0", - "@types/lru-cache": "^5.1.0", - "adm-zip": "^0.4.16", - "aggregate-error": "^3.0.0", - "ansi-escapes": "^4.3.0", - "boxen": "^5.1.2", - "chalk": "^2.4.2", - "chokidar": "^4.0.0", - "ci-info": "^2.0.0", - "debug": "^4.1.1", - "enquirer": "^2.3.0", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^1.0.3", - "ethereumjs-abi": "^0.6.8", - "find-up": "^2.1.0", - "fp-ts": "1.19.3", - "fs-extra": "^7.0.1", - "glob": "7.2.0", - "immutable": "^4.0.0-rc.12", - "io-ts": "1.10.4", - "json-stream-stringify": "^3.1.4", - "keccak": "^3.0.2", - "lodash": "^4.17.11", - "mnemonist": "^0.38.0", - "mocha": "^10.0.0", - "p-map": "^4.0.0", - "raw-body": "^2.4.1", - "resolve": "1.17.0", - "semver": "^6.3.0", - "solc": "0.8.26", - "source-map-support": "^0.5.13", - "stacktrace-parser": "^0.1.10", - "tsort": "0.0.1", - "undici": "^5.14.0", - "uuid": "^8.3.2", - "ws": "^7.4.6" - }, - "bin": { - "hardhat": "internal/cli/bootstrap.js" - }, - "peerDependencies": { - "ts-node": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/hardhat-abi-exporter": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/hardhat-abi-exporter/-/hardhat-abi-exporter-2.10.1.tgz", - "integrity": "sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==", - "dev": true, - "dependencies": { - "@ethersproject/abi": "^5.5.0", - "delete-empty": "^3.0.0" - }, - "engines": { - "node": ">=14.14.0" - }, - "peerDependencies": { - "hardhat": "^2.0.0" - } - }, - "node_modules/hardhat-contract-sizer": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/hardhat-contract-sizer/-/hardhat-contract-sizer-2.10.0.tgz", - "integrity": "sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "cli-table3": "^0.6.0", - "strip-ansi": "^6.0.0" - }, - "peerDependencies": { - "hardhat": "^2.0.0" - } - }, - "node_modules/hardhat-gas-reporter": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.10.tgz", - "integrity": "sha512-02N4+So/fZrzJ88ci54GqwVA3Zrf0C9duuTyGt0CFRIh/CdNwbnTgkXkRfojOMLBQ+6t+lBIkgbsOtqMvNwikA==", - "dev": true, - "peer": true, - "dependencies": { - "array-uniq": "1.0.3", - "eth-gas-reporter": "^0.2.25", - "sha1": "^1.1.1" - }, - "peerDependencies": { - "hardhat": "^2.0.2" - } - }, - "node_modules/hardhat-log-remover": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/hardhat-log-remover/-/hardhat-log-remover-2.1.1.tgz", - "integrity": "sha512-XFv3JN3VsISDAy+vPaXrn0sviOfinlQIh109twzoH26l1g+VnH4jIlqQ7omA9/TP6klKshf3m4LJ7j6Hh4wKWQ==", - "dev": true, - "peerDependencies": { - "hardhat": "^2.0.0" - } - }, - "node_modules/hardhat-spdx-license-identifier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/hardhat-spdx-license-identifier/-/hardhat-spdx-license-identifier-2.3.1.tgz", - "integrity": "sha512-rKElrCfsnSNr+2IquNirWxtPixpUdPNBCFcGAh4Gn2F9BTfRO/rjpEDIQFt/SUl/wWJcQpqyMfx4sPuWcT2lEg==", - "dev": true, - "peerDependencies": { - "hardhat": "^2.0.0" - } - }, - "node_modules/hardhat/node_modules/@metamask/eth-sig-util": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", - "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", - "dev": true, - "peer": true, - "dependencies": { - "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^6.2.1", - "ethjs-util": "^0.1.6", - "tweetnacl": "^1.0.3", - "tweetnacl-util": "^0.15.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/hardhat/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true - }, - "node_modules/hardhat/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/hardhat/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/hardhat/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true, - "peer": true - }, - "node_modules/hardhat/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/hardhat/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true - }, - "node_modules/hardhat/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/hardhat/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/hardhat/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/hardhat/node_modules/ethereumjs-util/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/hardhat/node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "peer": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/hardhat/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "peer": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/hardhat/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "peer": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/hardhat/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "peer": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "peer": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "peer": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/hardhat/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/hardhat/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/hardhat/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "peer": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "peer": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "peer": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/heap": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", - "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", - "dev": true, - "peer": true - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/http-basic": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", - "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", - "dev": true, - "peer": true, - "dependencies": { - "caseless": "^0.12.0", - "concat-stream": "^1.6.2", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "peer": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-response-object": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", - "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "^10.0.3" - } - }, - "node_modules/http-response-object/node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true, - "peer": true - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/husky": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", - "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", - "dev": true, - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immer": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz", - "integrity": "sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==", - "dev": true, - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/immutable": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", - "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", - "dev": true, - "peer": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "peer": true - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/io-ts": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", - "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", - "dev": true, - "peer": true, - "dependencies": { - "fp-ts": "^1.0.0" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isomorphic-unfetch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", - "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", - "dev": true, - "dependencies": { - "node-fetch": "^2.6.1", - "unfetch": "^4.2.0" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-cookie": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", - "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", - "dev": true - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stream-stringify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", - "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", - "dev": true, - "peer": true, - "engines": { - "node": ">=7.10.1" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "peer": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "peer": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/keccak": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", - "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/keccak256": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", - "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", - "dev": true, - "dependencies": { - "bn.js": "^5.2.0", - "buffer": "^6.0.3", - "keccak": "^3.0.2" - } - }, - "node_modules/keccak256/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lint-staged": { - "version": "15.2.10", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", - "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==", - "dev": true, - "dependencies": { - "chalk": "~5.3.0", - "commander": "~12.1.0", - "debug": "~4.3.6", - "execa": "~8.0.1", - "lilconfig": "~3.1.2", - "listr2": "~8.2.4", - "micromatch": "~4.0.8", - "pidtree": "~0.6.0", - "string-argv": "~0.3.2", - "yaml": "~2.5.0" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/listr2": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", - "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", - "dev": true, - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true - }, - "node_modules/listr2/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true, - "peer": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true, - "peer": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true, - "peer": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "peer": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "peer": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", - "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", - "dev": true, - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true - }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", - "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", - "dev": true, - "dependencies": { - "get-east-asian-width": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "peer": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", - "dev": true, - "peer": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "peer": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/markdown-table": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", - "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", - "dev": true, - "peer": true - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micro-ftch": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", - "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "peer": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mnemonist": { - "version": "0.38.5", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", - "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", - "dev": true, - "peer": true, - "dependencies": { - "obliterator": "^2.0.0" - } - }, - "node_modules/mocha": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", - "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha-chai-jest-snapshot": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mocha-chai-jest-snapshot/-/mocha-chai-jest-snapshot-1.1.6.tgz", - "integrity": "sha512-DSPZ5PtY1Rome58XSeS2/mggDJ60BIXDMlh58wsdkGfm1VvqTjjpFkjmR3g1iCtFAtPDXDmR9mYck1MygUEArA==", - "dev": true, - "workspaces": [ - "test/chai-v5" - ], - "dependencies": { - "@jest/test-result": "^29.7.0", - "chalk": "^4.1.2", - "find-package-json": "^1.2.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "yargs": "^17.7.2" - } - }, - "node_modules/mocha-chai-jest-snapshot/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mocha-chai-jest-snapshot/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mocha-chai-jest-snapshot/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/mocha/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/ndjson": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", - "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", - "dev": true, - "peer": true, - "dependencies": { - "json-stringify-safe": "^5.0.1", - "minimist": "^1.2.5", - "readable-stream": "^3.6.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "ndjson": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "peer": true - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "dev": true - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dev": true, - "peer": true, - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", - "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", - "dev": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "node_modules/nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", - "dev": true, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", - "dev": true, - "peer": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/number-to-bn": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", - "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", - "dev": true, - "peer": true, - "dependencies": { - "bn.js": "4.11.6", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/number-to-bn/node_modules/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", - "dev": true, - "peer": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obliterator": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", - "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", - "dev": true, - "peer": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ordinal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", - "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", - "dev": true, - "peer": true - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "peer": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-cache-control": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", - "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", - "dev": true, - "peer": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "peer": true - }, - "node_modules/path-starts-with": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-2.0.1.tgz", - "integrity": "sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pony-cause": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", - "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/prettier-plugin-solidity": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.1.tgz", - "integrity": "sha512-Mq8EtfacVZ/0+uDKTtHZGW3Aa7vEbX/BNx63hmVg6YTiTXSiuKP0amj0G6pGwjmLaOfymWh3QgXEZkjQbU8QRg==", - "dev": true, - "dependencies": { - "@solidity-parser/parser": "^0.18.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "prettier": ">=2.3.0" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", - "dev": true - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "peer": true - }, - "node_modules/promise": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", - "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "dev": true, - "peer": true, - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "peer": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/proper-lockfile/node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/proper-lockfile/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "peer": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "peer": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "peer": true, - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/recursive-readdir/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/req-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", - "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", - "dev": true, - "peer": true, - "dependencies": { - "req-from": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/req-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", - "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", - "dev": true, - "peer": true, - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/req-from/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "peer": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rlp": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", - "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", - "dev": true, - "dependencies": { - "bn.js": "^5.2.0" - }, - "bin": { - "rlp": "bin/rlp" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "peer": true - }, - "node_modules/sc-istanbul": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", - "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", - "dev": true, - "peer": true, - "dependencies": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "istanbul": "lib/cli.js" - } - }, - "node_modules/sc-istanbul/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/sc-istanbul/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/sc-istanbul/node_modules/glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "peer": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sc-istanbul/node_modules/has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sc-istanbul/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sc-istanbul/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sc-istanbul/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true, - "peer": true - }, - "node_modules/sc-istanbul/node_modules/supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/sc-istanbul/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true - }, - "node_modules/secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "peer": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "peer": true - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/sha1": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", - "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", - "dev": true, - "peer": true, - "dependencies": { - "charenc": ">= 0.0.1", - "crypt": ">= 0.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "peer": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "peer": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/solc": { - "version": "0.8.26", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", - "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", - "dev": true, - "peer": true, - "dependencies": { - "command-exists": "^1.2.8", - "commander": "^8.1.0", - "follow-redirects": "^1.12.1", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "bin": { - "solcjs": "solc.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/solc/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/solc/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solidity-ast": { - "version": "0.4.59", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.59.tgz", - "integrity": "sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g==", - "dev": true - }, - "node_modules/solidity-coverage": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.13.tgz", - "integrity": "sha512-RiBoI+kF94V3Rv0+iwOj3HQVSqNzA9qm/qDP1ZDXK5IX0Cvho1qiz8hAXTsAo6KOIUeP73jfscq0KlLqVxzGWA==", - "dev": true, - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.0.9", - "@solidity-parser/parser": "^0.18.0", - "chalk": "^2.4.2", - "death": "^1.1.0", - "difflib": "^0.2.4", - "fs-extra": "^8.1.0", - "ghost-testrpc": "^0.0.2", - "global-modules": "^2.0.0", - "globby": "^10.0.1", - "jsonschema": "^1.2.4", - "lodash": "^4.17.21", - "mocha": "^10.2.0", - "node-emoji": "^1.10.0", - "pify": "^4.0.1", - "recursive-readdir": "^2.2.2", - "sc-istanbul": "^0.4.5", - "semver": "^7.3.4", - "shelljs": "^0.8.3", - "web3-utils": "^1.3.6" - }, - "bin": { - "solidity-coverage": "plugins/bin.js" - }, - "peerDependencies": { - "hardhat": "^2.11.0" - } - }, - "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", - "dev": true, - "peer": true - }, - "node_modules/solidity-coverage/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solidity-coverage/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solidity-coverage/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/solidity-coverage/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true - }, - "node_modules/solidity-coverage/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/solidity-coverage/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/solidity-coverage/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/solidity-coverage/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "peer": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/solidity-coverage/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solidity-coverage/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "peer": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/stacktrace-parser": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", - "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", - "dev": true, - "peer": true, - "dependencies": { - "type-fest": "^0.7.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/stacktrace-parser/node_modules/type-fest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", - "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", - "dev": true, - "peer": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", - "dev": true, - "peer": true, - "dependencies": { - "is-hex-prefixed": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sync-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", - "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", - "dev": true, - "peer": true, - "dependencies": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/sync-rpc": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", - "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", - "dev": true, - "peer": true, - "dependencies": { - "get-port": "^3.1.0" - } - }, - "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true - }, - "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", - "dev": true, - "peer": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table-layout": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", - "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table-layout/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "peer": true - }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/then-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", - "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^8.1.1", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/then-request/node_modules/@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", - "dev": true, - "peer": true - }, - "node_modules/then-request/node_modules/form-data": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz", - "integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==", - "dev": true, - "peer": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "peer": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "peer": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-command-line-args": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", - "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", - "dev": true, - "peer": true, - "dependencies": { - "chalk": "^4.1.0", - "command-line-args": "^5.1.1", - "command-line-usage": "^6.1.0", - "string-format": "^2.0.0" - }, - "bin": { - "write-markdown": "dist/write-markdown.js" - } - }, - "node_modules/ts-essentials": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", - "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", - "dev": true, - "peer": true, - "peerDependencies": { - "typescript": ">=3.7.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "peer": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsort": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", - "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", - "dev": true, - "peer": true - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "node_modules/tweetnacl-util": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", - "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", - "dev": true, - "peer": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typechain": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", - "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", - "dev": true, - "peer": true, - "dependencies": { - "@types/prettier": "^2.1.1", - "debug": "^4.3.1", - "fs-extra": "^7.0.0", - "glob": "7.1.7", - "js-sha3": "^0.8.0", - "lodash": "^4.17.15", - "mkdirp": "^1.0.4", - "prettier": "^2.3.1", - "ts-command-line-args": "^2.2.0", - "ts-essentials": "^7.0.1" - }, - "bin": { - "typechain": "dist/cli/cli.js" - }, - "peerDependencies": { - "typescript": ">=4.3.0" - } - }, - "node_modules/typechain/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/typechain/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/typechain/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typechain/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "peer": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/typechain/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/typechain/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "peer": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typechain/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "peer": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/typechain/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "peer": true - }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", - "dev": true, - "peer": true, - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true - }, - "node_modules/unfetch": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "peer": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/web3-utils": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", - "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", - "dev": true, - "peer": true, - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "bn.js": "^5.2.1", - "ethereum-bloom-filters": "^1.0.6", - "ethereum-cryptography": "^2.1.2", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "utf8": "3.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "peer": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "peer": true - }, - "node_modules/wordwrapjs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", - "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", - "dev": true, - "peer": true, - "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/wordwrapjs/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "peer": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "dev": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "peer": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "peer": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 7df797c8..00000000 --- a/package.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "name": "@stakewise/v3-core", - "version": "3.0.1", - "description": "Liquid staking protocol for Ethereum", - "main": "index.js", - "scripts": { - "compile": "SKIP_LOAD=true hardhat clean && SKIP_LOAD=true hardhat compile", - "lint": "npm run lint:js && npm run lint:sol", - "lint:fix": "npm run lint:js:fix && npm run lint:sol:fix", - "lint:js": "eslint --ignore-pattern .gitignore .", - "lint:js:fix": "eslint --ignore-pattern .gitignore --fix './**/*.ts'", - "lint:sol": "prettier -c 'contracts/**/*.sol'", - "lint:sol:fix": "prettier --write 'contracts/**/*.sol'", - "spdx": "hardhat prepend-spdx-license", - "export-abi": "hardhat export-abi", - "size": "npm run compile && hardhat size-contracts", - "slither": "npm run compile && SKIP_LOAD=true slither --fail-high --skip-clean .", - "quick-test": "hardhat test", - "quick-test:fork": "ENABLE_MAINNET_FORK=true hardhat test", - "test": "npm run compile && hardhat test", - "test:fork": "npm run compile && ENABLE_MAINNET_FORK=true hardhat test", - "test:gas": "npm run compile && TRACK_GAS=true hardhat test", - "coverage": "COVERAGE=true npm run compile && COVERAGE=true hardhat coverage", - "precommit": "lint-staged", - "node": "hardhat node", - "full-deploy:hoodi": "hardhat eth-full-deploy --network hoodi", - "full-deploy:mainnet": "hardhat eth-full-deploy --network mainnet", - "upgrade:hoodi": "hardhat eth-upgrade --network hoodi", - "execute-txs:hoodi": "hardhat execute-txs --network hoodi", - "upgrade:mainnet": "hardhat eth-upgrade --network mainnet", - "upgrade:chiado": "hardhat gno-upgrade --network chiado", - "upgrade:gnosis": "hardhat gno-upgrade --network gnosis", - "full-deploy:eth-local": "hardhat eth-full-deploy-local --network local", - "full-deploy:chiado": "hardhat gno-full-deploy --network chiado", - "full-deploy:gnosis": "hardhat gno-full-deploy --network gnosis" - }, - "repository": { - "type": "git", - "url": "https://github.com/stakewise/v3-core" - }, - "bugs": { - "url": "https://github.com/stakewise/v3-core/issues" - }, - "homepage": "https://github.com/stakewise/v3-core#readme", - "devDependencies": { - "@chainsafe/ssz": "0.18.0", - "@metamask/eth-sig-util": "7.0.3", - "@nomicfoundation/hardhat-foundry": "1.1.3", - "@nomicfoundation/hardhat-toolbox": "5.0.0", - "@openzeppelin/hardhat-upgrades": "3.5.0", - "@openzeppelin/merkle-tree": "1.0.7", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "bls-eth-wasm": "1.1.1", - "dotenv": "16.4.5", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-prettier": "5.2.1", - "ethereumjs-wallet": "1.0.2", - "hardhat-abi-exporter": "2.10.1", - "hardhat-contract-sizer": "2.10.0", - "hardhat-log-remover": "2.1.1", - "hardhat-spdx-license-identifier": "2.3.1", - "husky": "9.1.6", - "keccak256": "1.0.6", - "lint-staged": "15.2.10", - "mocha-chai-jest-snapshot": "1.1.6", - "prettier": "3.3.3", - "prettier-plugin-solidity": "1.4.1" - }, - "lint-staged": { - "test/**/*.ts": [ - "prettier --write", - "eslint --ignore-pattern .gitignore --fix './**/*.ts'" - ], - "contracts/**/*.sol": [ - "prettier --write" - ] - }, - "author": "StakeWise Labs ", - "license": "BUSL-1.1", - "keywords": [ - "stakewise", - "liquid staking", - "ethereum", - "protocol", - "solidity", - "evm", - "contracts", - "core" - ], - "dependencies": { - "@openzeppelin/contracts": "5.0.2", - "@openzeppelin/contracts-upgradeable": "5.0.2" - } -} diff --git a/slither.config.json b/slither.config.json deleted file mode 100644 index f3011039..00000000 --- a/slither.config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "filter_paths": "node_modules/@openzeppelin/contracts-upgradeable|node_modules/@openzeppelin/contracts|contracts/mocks", - "hardhat_ignore_compile": true, - "exclude_informational": true, - "exclude_low": true, - "exclude_medium": true -} diff --git a/test/Constants.t.sol b/test/Constants.t.sol deleted file mode 100644 index ee375056..00000000 --- a/test/Constants.t.sol +++ /dev/null @@ -1,27 +0,0 @@ -pragma solidity ^0.8.22; - -import {Test} from '../lib/forge-std/src/Test.sol'; - -abstract contract ConstantsTest is Test { - address ZERO_ADDRESS; - uint256 REWARDS_DELAY = 12 hours; - uint256 SECURITY_DEPOSIT = 1 gwei; - - enum PanicCode { - ARITHMETIC_UNDER_OR_OVERFLOW, - DIVISION_BY_ZERO, - OUT_OF_BOUND_INDEX - } - - mapping(PanicCode => uint8) public panicCodes; - - function setUp() public virtual { - panicCodes[PanicCode.ARITHMETIC_UNDER_OR_OVERFLOW] = 0x11; - panicCodes[PanicCode.DIVISION_BY_ZERO] = 0x12; - panicCodes[PanicCode.OUT_OF_BOUND_INDEX] = 0x32; - } - - function expectRevertWithPanic(PanicCode code) public { - vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", panicCodes[code])); - } -} diff --git a/test/EthOsTokenVaultEscrow.spec.ts b/test/EthOsTokenVaultEscrow.spec.ts deleted file mode 100644 index 67ef1259..00000000 --- a/test/EthOsTokenVaultEscrow.spec.ts +++ /dev/null @@ -1,792 +0,0 @@ -import { ethers } from 'hardhat' -import { parseEther, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { expect } from './shared/expect' -import { - EthVault, - IKeeperRewards, - Keeper, - OsToken, - OsTokenConfig, - OsTokenVaultController, - OsTokenVaultEscrow, - OsTokenVaultEscrowAuthMock, - OsTokenVaultEscrowAuthMock__factory, -} from '../typechain-types' -import { ethVaultFixture } from './shared/fixtures' -import { - EXITING_ASSETS_MIN_DELAY, - MAX_UINT256, - OSTOKEN_VAULT_ESCROW_LIQ_BONUS, - OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD, - PANIC_CODES, - ZERO_ADDRESS, -} from './shared/constants' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - setAvgRewardPerSecond, - updateRewards, -} from './shared/rewards' -import snapshotGasCost from './shared/snapshotGasCost' -import { - extractExitPositionTicket, - getBlockTimestamp, - getGasUsed, - increaseTime, - setBalance, -} from './shared/utils' - -describe('EthOsTokenVaultEscrow', () => { - const assets = ethers.parseEther('100') - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let dao: Signer, admin: Signer, owner: Wallet, other: Wallet, redeemer: Wallet, liquidator: Wallet - let vault: EthVault, - osToken: OsToken, - osTokenConfig: OsTokenConfig, - osTokenVaultEscrow: OsTokenVaultEscrow, - osTokenVaultController: OsTokenVaultController, - osTokenVaultEscrowAuth: OsTokenVaultEscrowAuthMock, - keeper: Keeper - let vaultAddr: string - let osTokenShares: bigint - - beforeEach('deploy fixture', async () => { - ;[dao, admin, owner, redeemer, liquidator, other] = await (ethers as any).getSigners() - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthVault(admin, vaultParams) - vaultAddr = await vault.getAddress() - admin = await ethers.getImpersonatedSigner(await vault.admin()) - osTokenVaultEscrow = fixture.osTokenVaultEscrow - osTokenVaultController = fixture.osTokenVaultController - keeper = fixture.keeper - osToken = fixture.osToken - osTokenConfig = fixture.osTokenConfig - osTokenVaultEscrowAuth = OsTokenVaultEscrowAuthMock__factory.connect( - await osTokenVaultEscrow.authenticator(), - dao - ) - await osTokenVaultEscrowAuth.setCanRegister(owner.address, true) - - // collateralize vault - await collateralizeEthVault( - vault, - fixture.keeper, - fixture.depositDataRegistry, - admin, - fixture.validatorsRegistry - ) - await vault - .connect(owner) - .depositAndMintOsToken(owner.address, MAX_UINT256, ZERO_ADDRESS, { value: assets }) - osTokenShares = await fixture.osToken.balanceOf(owner.address) - }) - - describe('register', () => { - it('cannot register when vault is not harvested', async () => { - await updateRewards( - keeper, - [ - { - vault: vaultAddr, - reward: 0n, - unlockedMevReward: 0n, - }, - ], - 0 - ) - await updateRewards( - keeper, - [ - { - vault: vaultAddr, - reward: 0n, - unlockedMevReward: 0n, - }, - ], - 0 - ) - await expect( - vault.connect(owner).transferOsTokenPositionToEscrow(osTokenShares) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('cannot register with invalid osToken position', async () => { - await expect( - vault.connect(other).transferOsTokenPositionToEscrow(osTokenShares) - ).to.be.revertedWithCustomError(vault, 'InvalidPosition') - await expect( - vault.connect(owner).transferOsTokenPositionToEscrow(0n) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - - await expect( - vault.connect(owner).transferOsTokenPositionToEscrow(osTokenShares * 2n) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - }) - - it('removes position if all the osToken shares transferred', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - const cumulativeFeePerShare = await osTokenVaultController.cumulativeFeePerShare() - const sharesToRegister = await vault.osTokenPositions(owner.address) - const tx = await vault.connect(owner).transferOsTokenPositionToEscrow(sharesToRegister) - const positionTicket = await extractExitPositionTicket(tx) - await expect(tx) - .to.emit(osTokenVaultEscrow, 'PositionCreated') - .withArgs(vaultAddr, positionTicket, owner.address, sharesToRegister, cumulativeFeePerShare) - expect(await vault.osTokenPositions(owner.address)).to.equal(0n) - expect(await vault.getShares(owner.address)).to.equal(0n) - - const escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - expect(escrowPosition[0]).to.equal(owner.address) - expect(escrowPosition[1]).to.equal(0n) - expect(escrowPosition[2]).to.equal(sharesToRegister) - await snapshotGasCost(tx) - }) - - it('keeps LTV for the position left', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - const cumulativeFeePerShare = await osTokenVaultController.cumulativeFeePerShare() - - let sharesToRegister = await vault.osTokenPositions(owner.address) - const stakedShares = await vault.getShares(owner.address) - const vaultLtvBefore = - ((await osTokenVaultController.convertToAssets(sharesToRegister)) * 1000n) / - (await vault.convertToAssets(stakedShares)) - - sharesToRegister /= 2n - const tx = await vault.connect(owner).transferOsTokenPositionToEscrow(sharesToRegister) - const positionTicket = await extractExitPositionTicket(tx) - await expect(tx) - .to.emit(osTokenVaultEscrow, 'PositionCreated') - .withArgs(vaultAddr, positionTicket, owner.address, sharesToRegister, cumulativeFeePerShare) - - expect(await vault.osTokenPositions(owner.address)).to.equal(sharesToRegister) - expect(await vault.getShares(owner.address)).to.equal(stakedShares / 2n) - - const vaultLtvAfter = - ((await osTokenVaultController.convertToAssets(sharesToRegister)) * 1000n) / - (await vault.convertToAssets(await vault.getShares(owner.address))) - expect(vaultLtvAfter).to.equal(vaultLtvBefore) - - const escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - expect(escrowPosition[0]).to.equal(owner.address) - expect(escrowPosition[1]).to.equal(0n) - expect(escrowPosition[2]).to.equal(sharesToRegister) - await snapshotGasCost(tx) - }) - - it('cannot register with failed authenticator check', async () => { - await osTokenVaultEscrowAuth.setCanRegister(owner.address, false) - await expect( - vault.connect(owner).transferOsTokenPositionToEscrow(osTokenShares) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'AccessDenied') - }) - - it('cannot register with zero owner address', async () => { - await osTokenVaultEscrowAuth.setCanRegister(ZERO_ADDRESS, true) - await expect( - osTokenVaultEscrow.connect(owner).register(ZERO_ADDRESS, 0n, osTokenShares, 0n) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'ZeroAddress') - }) - - it('cannot register with zero osToken shares', async () => { - await expect( - osTokenVaultEscrow.connect(owner).register(owner.address, 0n, 0n, 0n) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'InvalidShares') - }) - }) - - describe('process exited assets', () => { - let positionTicket: bigint - let timestamp: number - let exitOsTokenShares: bigint - - beforeEach('register position', async () => { - exitOsTokenShares = await vault.osTokenPositions(owner.address) - const tx = await vault.connect(owner).transferOsTokenPositionToEscrow(exitOsTokenShares) - positionTicket = await extractExitPositionTicket(tx) - timestamp = await getBlockTimestamp(tx) - }) - - it('cannot process with invalid position ticket', async () => { - await expect( - osTokenVaultEscrow.connect(owner).processExitedAssets(vaultAddr, 0n, timestamp, 0n) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'InvalidPosition') - }) - - it('cannot process with invalid index', async () => { - await expect( - osTokenVaultEscrow - .connect(owner) - .processExitedAssets(vaultAddr, positionTicket, timestamp, 0n) - ).to.be.revertedWithCustomError(vault, 'InvalidCheckpointIndex') - }) - - it('cannot process partially exited position', async () => { - await setBalance(vaultAddr, assets / 2n) - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - await expect( - osTokenVaultEscrow - .connect(owner) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'ExitRequestNotProcessed') - }) - - it('processes exited assets', async () => { - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - const exitPosition = await vault.calculateExitedAssets( - await osTokenVaultEscrow.getAddress(), - positionTicket, - timestamp, - index - ) - const tx = await osTokenVaultEscrow - .connect(other) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - await expect(tx) - .to.emit(osTokenVaultEscrow, 'ExitedAssetsProcessed') - .withArgs(vaultAddr, other.address, positionTicket, exitPosition.exitedAssets) - - const escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - expect(escrowPosition[0]).to.equal(owner.address) - // accumulates fee - expect(escrowPosition[1]).to.equal(exitPosition.exitedAssets) - expect(escrowPosition[2]).to.greaterThan(exitOsTokenShares) - await snapshotGasCost(tx) - }) - }) - - describe('claim exited assets', () => { - let positionTicket: bigint - let timestamp: number - let exitOsTokenShares: bigint - - beforeEach('register position', async () => { - exitOsTokenShares = await osToken.balanceOf(owner.address) - const tx = await vault.connect(owner).transferOsTokenPositionToEscrow(exitOsTokenShares) - positionTicket = await extractExitPositionTicket(tx) - timestamp = await getBlockTimestamp(tx) - }) - - it('fails when not enough osToken shares', async () => { - await expect( - osTokenVaultEscrow - .connect(owner) - .claimExitedAssets(vaultAddr, positionTicket, exitOsTokenShares + 1n) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('fails from not position owner', async () => { - await osToken.connect(owner).transfer(other.address, exitOsTokenShares) - await expect( - osTokenVaultEscrow - .connect(other) - .claimExitedAssets(vaultAddr, positionTicket, exitOsTokenShares) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'AccessDenied') - }) - - it('fails with more osToken shares than available', async () => { - await vault.depositAndMintOsToken(owner.address, MAX_UINT256, ZERO_ADDRESS, { - value: assets, - }) - const osTokenShares = await osToken.balanceOf(owner.address) - await expect( - osTokenVaultEscrow - .connect(owner) - .claimExitedAssets(vaultAddr, positionTicket, osTokenShares) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'InvalidShares') - }) - - it('fails for not processed exited assets', async () => { - await expect( - osTokenVaultEscrow - .connect(owner) - .claimExitedAssets(vaultAddr, positionTicket, exitOsTokenShares) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'ExitRequestNotProcessed') - }) - - describe('succeeds', async () => { - let exitedAssets: bigint - - beforeEach('process exited assets', async () => { - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - const exitPosition = await vault.calculateExitedAssets( - await osTokenVaultEscrow.getAddress(), - positionTicket, - timestamp, - index - ) - exitedAssets = exitPosition.exitedAssets - - await osTokenVaultEscrow - .connect(owner) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - }) - - it('succeeds for partial osToken shares', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - const osTokenSharesToBurn = exitOsTokenShares / 2n - let escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const totalOsTokenShares = escrowPosition[2] - - const assetsToWithdraw = (exitedAssets * osTokenSharesToBurn) / totalOsTokenShares - const balanceBefore = await ethers.provider.getBalance(owner.address) - const tx = await osTokenVaultEscrow - .connect(owner) - .claimExitedAssets(vaultAddr, positionTicket, osTokenSharesToBurn) - const balanceAfter = await ethers.provider.getBalance(owner.address) - const gasUsed = await getGasUsed(tx) - expect(balanceAfter - balanceBefore).to.equal(assetsToWithdraw - gasUsed) - await expect(tx) - .to.emit(osTokenVaultEscrow, 'ExitedAssetsClaimed') - .withArgs(owner.address, vaultAddr, positionTicket, osTokenSharesToBurn, assetsToWithdraw) - - escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - expect(escrowPosition[1]).to.equal(exitedAssets - assetsToWithdraw) - expect(escrowPosition[2]).to.equal(totalOsTokenShares - osTokenSharesToBurn) - await snapshotGasCost(tx) - }) - - it('succeeds for all osToken shares', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - await vault.depositAndMintOsToken(owner.address, MAX_UINT256, ZERO_ADDRESS, { - value: assets, - }) - - let escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const osTokenSharesToBurn = escrowPosition[2] - const assetsToWithdraw = exitedAssets - const balanceBefore = await ethers.provider.getBalance(owner.address) - const tx = await osTokenVaultEscrow - .connect(owner) - .claimExitedAssets(vaultAddr, positionTicket, osTokenSharesToBurn) - const balanceAfter = await ethers.provider.getBalance(owner.address) - const gasUsed = await getGasUsed(tx) - expect(balanceAfter - balanceBefore).to.equal(assetsToWithdraw - gasUsed) - await expect(tx) - .to.emit(osTokenVaultEscrow, 'ExitedAssetsClaimed') - .withArgs(owner.address, vaultAddr, positionTicket, osTokenSharesToBurn, assetsToWithdraw) - - escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - expect(escrowPosition[1]).to.equal(0n) - expect(escrowPosition[2]).to.equal(0n) - await snapshotGasCost(tx) - }) - }) - }) - - describe('redeem', () => { - let positionTicket: bigint - let redeemedShares: bigint - let exitedAssets: bigint - - beforeEach('register position', async () => { - const tx = await vault - .connect(owner) - .transferOsTokenPositionToEscrow(await vault.osTokenPositions(owner.address)) - positionTicket = await extractExitPositionTicket(tx) - const timestamp = await getBlockTimestamp(tx) - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - await osTokenVaultEscrow - .connect(other) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - - const escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - exitedAssets = escrowPosition[1] - redeemedShares = escrowPosition[2] - - const redeemAssets = await osTokenVaultController.convertToAssets(redeemedShares) - const vaultConfig = await osTokenConfig.getConfig(vaultAddr) - if ((await osTokenConfig.redeemer()) !== redeemer.address) { - await osTokenConfig.connect(dao).setRedeemer(redeemer.address) - } - await vault - .connect(redeemer) - .depositAndMintOsToken(redeemer.address, MAX_UINT256, ZERO_ADDRESS, { - value: (redeemAssets * parseEther('1.1')) / vaultConfig.ltvPercent, - }) - }) - - it('cannot redeem osTokens from not redeemer', async () => { - await osTokenConfig.connect(dao).setRedeemer(dao.address) - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, redeemedShares, redeemer.address) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot redeem osTokens to zero receiver', async () => { - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, redeemedShares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('cannot redeem osTokens for position with zero minted shares', async () => { - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket + 1n, redeemedShares, redeemer.address) - ).to.be.revertedWithCustomError(vault, 'InvalidPosition') - }) - - it('cannot redeem osTokens when received assets exceed exited assets', async () => { - const redeemedShares = await osTokenVaultController.convertToShares(exitedAssets * 3n) - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, redeemedShares, redeemer.address) - ).to.be.revertedWithCustomError(vault, 'InvalidReceivedAssets') - }) - - it('cannot redeem osTokens when redeeming more than minted', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - const escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const redeemedShares = escrowPosition[2] + 1n - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, redeemedShares, redeemer.address) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('cannot redeem zero osToken shares', async () => { - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, 0, redeemer.address) - ).to.be.revertedWithCustomError(osTokenVaultController, 'InvalidShares') - }) - - it('cannot redeem without osTokens', async () => { - await osToken.connect(redeemer).transfer(dao.address, redeemedShares) - await expect( - osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, redeemedShares, redeemer.address) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('can redeem', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - - const osTokenBalanceBefore = await osToken.balanceOf(redeemer.address) - const escrowPositionBefore = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const assetsBalanceBefore = await ethers.provider.getBalance(redeemer.address) - - const receipt = await osTokenVaultEscrow - .connect(redeemer) - .redeemOsToken(vaultAddr, positionTicket, redeemedShares, redeemer.address) - - let redeemedAssets = await osTokenVaultController.convertToAssets(redeemedShares) - const escrowPositionAfter = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const assetsBalanceAfter = await ethers.provider.getBalance(redeemer.address) - const gasUsed = await getGasUsed(receipt) - - expect(await osToken.balanceOf(redeemer.address)).to.eq(osTokenBalanceBefore - redeemedShares) - expect(escrowPositionAfter[2]).to.be.eq(escrowPositionBefore[2] - redeemedShares) - - try { - await expect(receipt) - .to.emit(osTokenVaultEscrow, 'OsTokenRedeemed') - .withArgs( - redeemer.address, - vaultAddr, - positionTicket, - redeemer.address, - redeemedShares, - redeemedAssets - ) - } catch { - redeemedAssets -= 1n // rounding error - await expect(receipt) - .to.emit(osTokenVaultEscrow, 'OsTokenRedeemed') - .withArgs( - redeemer.address, - vaultAddr, - positionTicket, - redeemer.address, - redeemedShares, - redeemedAssets - ) - } - - expect(escrowPositionAfter[1]).to.be.eq(escrowPositionBefore[1] - redeemedAssets) - expect(assetsBalanceAfter).to.eq(assetsBalanceBefore + redeemedAssets - gasUsed) - - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(redeemer.address, ZERO_ADDRESS, redeemedShares) - await expect(receipt) - .to.emit(osTokenVaultController, 'Burn') - .withArgs( - await osTokenVaultEscrow.getAddress(), - redeemer.address, - redeemedAssets, - redeemedShares - ) - - await snapshotGasCost(receipt) - }) - }) - - describe('liquidate', () => { - let positionTicket: bigint - let liquidatedShares: bigint - - beforeEach('register position', async () => { - const tx = await vault - .connect(owner) - .transferOsTokenPositionToEscrow(await vault.osTokenPositions(owner.address)) - positionTicket = await extractExitPositionTicket(tx) - const timestamp = await getBlockTimestamp(tx) - - // slash 20% of assets - const penalty = -(await vault.totalAssets()) / 5n - - // slashing received - const vaultReward = getHarvestParams(await vault.getAddress(), penalty, 0n) - let tree = await updateRewards(keeper, [vaultReward], 0) - let harvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - - tree = await updateRewards(keeper, [vaultReward], 0) - harvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - await osTokenVaultEscrow - .connect(other) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - - const escrowPosition = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - liquidatedShares = escrowPosition[2] - const liquidatedAssets = await osTokenVaultController.convertToAssets(liquidatedShares) - - const vaultConfig = await osTokenConfig.getConfig(vaultAddr) - await vault.depositAndMintOsToken(liquidator.address, MAX_UINT256, ZERO_ADDRESS, { - value: (liquidatedAssets * parseEther('1.1')) / vaultConfig.ltvPercent, - }) - }) - - it('cannot liquidate osTokens when received assets exceed exited assets', async () => { - await expect( - osTokenVaultEscrow - .connect(liquidator) - .liquidateOsToken(vaultAddr, positionTicket, liquidatedShares, liquidator.address) - ).to.be.revertedWithCustomError(vault, 'InvalidReceivedAssets') - }) - - it('cannot liquidate osTokens when health factor is above 1', async () => { - await vault.connect(other).depositAndMintOsToken(other.address, MAX_UINT256, ZERO_ADDRESS, { - value: assets, - }) - await osTokenVaultEscrowAuth.setCanRegister(other.address, true) - const tx = await vault - .connect(other) - .transferOsTokenPositionToEscrow(await vault.osTokenPositions(other.address)) - const positionTicket = await extractExitPositionTicket(tx) - const timestamp = await getBlockTimestamp(tx) - const vaultReward = getHarvestParams(vaultAddr, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const index = await vault.getExitQueueIndex(positionTicket) - await osTokenVaultEscrow - .connect(other) - .processExitedAssets(vaultAddr, positionTicket, timestamp, index) - - await expect( - osTokenVaultEscrow - .connect(liquidator) - .liquidateOsToken(vaultAddr, positionTicket, liquidatedShares, liquidator.address) - ).to.be.revertedWithCustomError(vault, 'InvalidHealthFactor') - }) - - it('can liquidate', async () => { - const osTokenBalanceBefore = await osToken.balanceOf(liquidator.address) - const escrowPositionBefore = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const assetsBalanceBefore = await ethers.provider.getBalance(liquidator.address) - - let receivedAssets = escrowPositionBefore[1] - const liquidatedShares = await osTokenVaultController.convertToShares( - (receivedAssets * parseEther('1')) / (await osTokenVaultEscrow.liqBonusPercent()) - ) - receivedAssets -= 2n // rounding error - - const receipt = await osTokenVaultEscrow - .connect(liquidator) - .liquidateOsToken(vaultAddr, positionTicket, liquidatedShares, liquidator.address) - - const escrowPositionAfter = await osTokenVaultEscrow.getPosition(vaultAddr, positionTicket) - const assetsBalanceAfter = await ethers.provider.getBalance(liquidator.address) - const gasUsed = await getGasUsed(receipt) - - expect(await osToken.balanceOf(liquidator.address)).to.eq( - osTokenBalanceBefore - liquidatedShares - ) - expect(escrowPositionAfter[1]).to.be.eq(escrowPositionBefore[1] - receivedAssets) - expect(escrowPositionAfter[2]).to.be.eq(escrowPositionBefore[2] - liquidatedShares) - await expect(receipt) - .to.emit(osTokenVaultEscrow, 'OsTokenLiquidated') - .withArgs( - liquidator.address, - vaultAddr, - positionTicket, - liquidator.address, - liquidatedShares, - receivedAssets - ) - - expect(assetsBalanceAfter).to.eq(assetsBalanceBefore + receivedAssets - gasUsed) - - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(liquidator.address, ZERO_ADDRESS, liquidatedShares) - await expect(receipt).to.emit(osTokenVaultController, 'Burn') - - await snapshotGasCost(receipt) - }) - }) - - describe('set authenticator', () => { - it('fails with the same value', async () => { - await expect( - osTokenVaultEscrow.connect(dao).setAuthenticator(await osTokenVaultEscrow.authenticator()) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'ValueNotChanged') - }) - it('fails from not owner', async () => { - await expect( - osTokenVaultEscrow.connect(other).setAuthenticator(other.address) - ).to.be.revertedWithCustomError(osTokenVaultEscrow, 'OwnableUnauthorizedAccount') - }) - - it('owner can update authenticator', async () => { - const tx = await osTokenVaultEscrow.connect(dao).setAuthenticator(other.address) - expect(await osTokenVaultEscrow.authenticator()).to.be.eq(other.address) - await expect(tx).to.emit(osTokenVaultEscrow, 'AuthenticatorUpdated').withArgs(other.address) - await snapshotGasCost(tx) - }) - }) - - describe('update config', () => { - const newLiqThresholdPercent = OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD - 1n - const newLiqBonusPercent = OSTOKEN_VAULT_ESCROW_LIQ_BONUS - 1n - const maxPercent = parseEther('1') - - it('updates in constructor', async () => { - expect(await osTokenVaultEscrow.liqThresholdPercent()).to.be.eq( - OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD - ) - expect(await osTokenVaultEscrow.liqBonusPercent()).to.be.eq(OSTOKEN_VAULT_ESCROW_LIQ_BONUS) - }) - - it('not owner cannot update config', async () => { - await expect( - osTokenVaultEscrow - .connect(other) - .updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent) - ).to.revertedWithCustomError(osTokenConfig, 'OwnableUnauthorizedAccount') - }) - - it('fails with invalid liqThresholdPercent', async () => { - await expect( - osTokenVaultEscrow.connect(dao).updateLiqConfig(0n, newLiqBonusPercent) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqThresholdPercent') - - await expect( - osTokenVaultEscrow.connect(dao).updateLiqConfig(maxPercent, newLiqBonusPercent) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqThresholdPercent') - }) - - it('fails with invalid liqBonusPercent', async () => { - await expect( - osTokenVaultEscrow.connect(dao).updateLiqConfig(newLiqThresholdPercent, maxPercent - 1n) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqBonusPercent') - await expect( - osTokenVaultEscrow.connect(dao).updateLiqConfig(parseEther('0.95'), parseEther('1.1')) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqBonusPercent') - }) - - it('owner can update config', async () => { - const tx = await osTokenVaultEscrow - .connect(dao) - .updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent) - await expect(tx) - .to.emit(osTokenVaultEscrow, 'LiqConfigUpdated') - .withArgs(newLiqThresholdPercent, newLiqBonusPercent) - expect(await osTokenVaultEscrow.liqThresholdPercent()).to.be.eq(newLiqThresholdPercent) - expect(await osTokenVaultEscrow.liqBonusPercent()).to.be.eq(newLiqBonusPercent) - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/EthRewardSplitter.t.sol b/test/EthRewardSplitter.t.sol index 2e8cad48..96f7063f 100644 --- a/test/EthRewardSplitter.t.sol +++ b/test/EthRewardSplitter.t.sol @@ -118,7 +118,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { assertGt(newShares, initialShares, 'RewardSplitter should have received vault shares'); // Sync rewards in the splitter + _startSnapshotGas('EthRewardSplitter_syncRewards'); rewardSplitter.syncRewards(); + _stopSnapshotGas(); // Check available rewards uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); @@ -132,7 +134,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { // Shareholder1 enters exit queue with their vault shares vm.prank(shareholder1); uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas('EthRewardSplitter_enterExitQueue'); uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); + _stopSnapshotGas(); // Process the exit queue harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); @@ -157,8 +161,10 @@ contract EthRewardSplitterTest is Test, EthHelpers { // Shareholder2 directly claims tokens without going through exit queue vm.prank(shareholder2); + _startSnapshotGas('EthRewardSplitter_claimVaultTokens'); address receiver = shareholder2; rewardSplitter.claimVaultTokens(rewards2, receiver); + _stopSnapshotGas(); // Verify shareholder2 received vault tokens assertGt(vault.getShares(receiver), 0, 'Shareholder2 should receive vault tokens directly'); @@ -186,7 +192,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { vm.prank(shareholder1); vm.expectEmit(true, false, false, true); emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); + _startSnapshotGas('EthRewardSplitter_enterExitQueueMaxWithdrawal'); rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); + _stopSnapshotGas(); // Check rewards were fully claimed assertEq(rewardSplitter.rewardsOf(shareholder1), 0, 'All rewards should be withdrawn'); @@ -274,7 +282,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { vm.prank(admin); vm.expectEmit(true, false, false, true); emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); + _startSnapshotGas('EthRewardSplitter_setClaimOnBehalf'); rewardSplitter.setClaimOnBehalf(true); + _stopSnapshotGas(); // Generate rewards vm.prank(depositor); @@ -300,7 +310,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { uint256 timestamp = vm.getBlockTimestamp(); vm.expectEmit(true, false, false, true); emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point + _startSnapshotGas('EthRewardSplitter_enterExitQueueOnBehalf'); uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + _stopSnapshotGas(); // Verify position is tracked correctly assertEq( @@ -329,7 +341,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { vm.prank(admin); vm.expectEmit(true, false, false, true); emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); + _startSnapshotGas('EthRewardSplitter_claimExitedAssetsOnBehalf'); rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); // Verify shareholder1 received rewards assertGt( @@ -361,7 +375,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { // Sync rewards with event check vm.expectEmit(false, false, false, false); // We don't know exact values emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values + _startSnapshotGas('EthRewardSplitter_syncRewardsDetailed'); rewardSplitter.syncRewards(); + _stopSnapshotGas(); // Verify rewards were synced uint256 newTotalRewards = rewardSplitter.totalRewards(); @@ -395,7 +411,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { vm.prank(admin); vm.expectEmit(true, false, false, true); emit IRewardSplitter.SharesIncreased(shareholder1, 1000); + _startSnapshotGas('EthRewardSplitter_increaseShares'); rewardSplitter.increaseShares(shareholder1, 1000); + _stopSnapshotGas(); assertEq( rewardSplitter.sharesOf(shareholder1), @@ -407,7 +425,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { vm.prank(admin); vm.expectEmit(true, false, false, true); emit IRewardSplitter.SharesDecreased(shareholder1, 1000); + _startSnapshotGas('EthRewardSplitter_decreaseShares'); rewardSplitter.decreaseShares(shareholder1, 1000); + _stopSnapshotGas(); assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1, 'Shares should decrease by 1000'); } @@ -421,9 +441,11 @@ contract EthRewardSplitterTest is Test, EthHelpers { ); // Update vault state through reward splitter + _startSnapshotGas('EthRewardSplitter_updateVaultState'); rewardSplitter.updateVaultState(harvestParams); + _stopSnapshotGas(); - // Verify rewards can be sync'd + // Verify rewards can be synced assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards after update'); // Sync and verify rewards @@ -438,7 +460,9 @@ contract EthRewardSplitterTest is Test, EthHelpers { uint256 initialBalance = address(rewardSplitter).balance; // Send ETH + _startSnapshotGas('EthRewardSplitter_receiveEth'); (bool success, ) = address(rewardSplitter).call{value: amount}(''); + _stopSnapshotGas(); assertTrue(success, 'ETH transfer should succeed'); // Verify balance increased diff --git a/test/EthVault.burn.spec.ts b/test/EthVault.burn.spec.ts deleted file mode 100644 index 2c133afc..00000000 --- a/test/EthVault.burn.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, ContractTransactionReceipt, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - Keeper, - OsTokenVaultController, - OsToken, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import snapshotGasCost from './shared/snapshotGasCost' -import { createUnknownVaultMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ONE_DAY, ZERO_ADDRESS } from './shared/constants' -import { collateralizeEthVault, setAvgRewardPerSecond } from './shared/rewards' -import { increaseTime } from './shared/utils' - -describe('EthVault - burn', () => { - const assets = ethers.parseEther('2') - const osTokenAssets = ethers.parseEther('1') - let osTokenShares: bigint - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let sender: Wallet, admin: Signer, owner: Wallet - let vault: EthVault, - keeper: Keeper, - osTokenVaultController: OsTokenVaultController, - osToken: OsToken, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createVault: ThenArg>['createEthVault'] - - beforeEach('deploy fixture', async () => { - ;[sender, owner, admin] = (await (ethers as any).getSigners()).slice(1, 4) - ;({ - createEthVault: createVault, - keeper, - validatorsRegistry, - osToken, - osTokenVaultController, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault(admin, vaultParams) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - // collateralize vault - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: assets }) - osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - await vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - }) - - it('cannot burn zero osTokens', async () => { - await expect(vault.connect(sender).burnOsToken(0)).to.be.revertedWithCustomError( - vault, - 'InvalidShares' - ) - }) - - it('cannot burn osTokens when nothing is minted', async () => { - await osToken.connect(sender).transfer(owner.address, osTokenShares) - await expect(vault.connect(owner).burnOsToken(osTokenShares)).to.be.revertedWithCustomError( - vault, - 'InvalidPosition' - ) - }) - - it('cannot burn osTokens from unregistered vault', async () => { - const unknownVault = await createUnknownVaultMock( - osTokenVaultController, - await vault.implementation() - ) - await expect( - unknownVault.connect(sender).burnOsToken(osTokenShares) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('updates position accumulated fee', async () => { - await setAvgRewardPerSecond(owner, vault, keeper, 1005987242) - const treasury = await osTokenVaultController.treasury() - const currTotalShares = await osTokenVaultController.totalShares() - const currTotalAssets = await osTokenVaultController.totalAssets() - const currCumulativeFeePerShare = await osTokenVaultController.cumulativeFeePerShare() - const currTreasuryShares = await osToken.balanceOf(treasury) - const currPositionShares = await vault.osTokenPositions(sender.address) - - await increaseTime(ONE_DAY) - - const newTotalShares = await osTokenVaultController.totalShares() - const newTotalAssets = await osTokenVaultController.totalAssets() - const newCumulativeFeePerShare = await osTokenVaultController.cumulativeFeePerShare() - const newTreasuryShares = await osToken.balanceOf(treasury) - const newPositionShares = await vault.osTokenPositions(sender.address) - expect(newTotalShares).to.be.eq(currTotalShares) - expect(newTotalAssets).to.be.above(currTotalAssets) - expect(newCumulativeFeePerShare).to.be.above(currCumulativeFeePerShare) - expect(newTreasuryShares).to.be.eq(currTreasuryShares) - expect(newPositionShares).to.be.above(currPositionShares) - - const receipt = await vault.connect(sender).burnOsToken(osTokenShares) - expect(await vault.osTokenPositions(sender.address)).to.be.above( - newPositionShares - currPositionShares - ) - await snapshotGasCost(receipt) - }) - - it('burns osTokens', async () => { - await setAvgRewardPerSecond(owner, vault, keeper, 1005987242) - const tx = await vault.connect(sender).burnOsToken(osTokenShares) - const receipt = (await tx.wait()) as ContractTransactionReceipt - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const osTokenAssets = receipt.logs?.[receipt.logs.length - 1]?.args?.assets - - expect(await osToken.balanceOf(sender.address)).to.eq(0) - expect(await vault.osTokenPositions(sender.address)).to.be.above(0) - await expect(tx) - .to.emit(vault, 'OsTokenBurned') - .withArgs(sender.address, osTokenAssets, osTokenShares) - await expect(tx) - .to.emit(osToken, 'Transfer') - .withArgs(sender.address, ZERO_ADDRESS, osTokenShares) - await expect(tx) - .to.emit(osTokenVaultController, 'Burn') - .withArgs(await vault.getAddress(), sender.address, osTokenAssets, osTokenShares) - await snapshotGasCost(tx) - }) -}) diff --git a/test/EthVault.deposit.spec.ts b/test/EthVault.deposit.spec.ts deleted file mode 100644 index 486323dc..00000000 --- a/test/EthVault.deposit.spec.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - DepositDataRegistry, - EthVault, - EthVaultMock, - IKeeperRewards, - Keeper, - SharedMevEscrow, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import snapshotGasCost from './shared/snapshotGasCost' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { PANIC_CODES, SECURITY_DEPOSIT, ZERO_ADDRESS } from './shared/constants' -import { collateralizeEthVault, getRewardsRootProof, updateRewards } from './shared/rewards' -import { setBalance } from './shared/utils' -import { registerEthValidator } from './shared/validators' - -const ether = ethers.parseEther('1') - -describe('EthVault - deposit', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const referrer = '0x' + '1'.repeat(40) - let sender: Wallet, receiver: Wallet, admin: Wallet, other: Wallet - let vault: EthVault, - keeper: Keeper, - mevEscrow: SharedMevEscrow, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createVault: ThenArg>['createEthVault'] - let createVaultMock: ThenArg>['createEthVaultMock'] - - beforeEach('deploy fixtures', async () => { - ;[sender, receiver, admin, other] = (await (ethers as any).getSigners()).slice(1, 5) - ;({ - createEthVault: createVault, - createEthVaultMock: createVaultMock, - keeper, - validatorsRegistry, - sharedMevEscrow: mevEscrow, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - }) - - it('fails to deposit to zero address', async () => { - await expect( - vault.connect(sender).deposit(ZERO_ADDRESS, referrer, { value: ethers.parseEther('999') }) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - describe('empty vault: no assets & no shares', () => { - it('status', async () => { - expect(await vault.totalAssets()).to.equal(SECURITY_DEPOSIT) - expect(await vault.totalShares()).to.equal(SECURITY_DEPOSIT) - }) - - it('deposit', async () => { - const amount = ether - expect(await vault.convertToShares(amount)).to.eq(amount) - const receipt = await vault - .connect(sender) - .deposit(receiver.address, referrer, { value: amount }) - expect(await vault.getShares(receiver.address)).to.eq(amount) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, amount, referrer) - await snapshotGasCost(receipt) - }) - }) - - describe('partially empty vault: shares & no assets', () => { - let ethVaultMock: EthVaultMock - - beforeEach(async () => { - ethVaultMock = await createVaultMock(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - await ethVaultMock._setTotalAssets(0) - }) - - it('status', async () => { - expect(await ethVaultMock.totalAssets()).to.eq(0) - }) - - it('deposit', async () => { - await expect( - ethVaultMock.connect(sender).deposit(receiver.address, referrer, { value: ether }) - ).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO) - }) - }) - - describe('full vault: assets & shares', () => { - beforeEach(async () => { - await vault - .connect(other) - .deposit(other.address, referrer, { value: ethers.parseEther('10') }) - }) - - it('status', async () => { - expect(await vault.totalAssets()).to.eq(ethers.parseEther('10') + SECURITY_DEPOSIT) - }) - - it('fails with exceeded capacity', async () => { - await expect( - vault - .connect(sender) - .deposit(receiver.address, referrer, { value: ethers.parseEther('999') }) - ).to.be.revertedWithCustomError(vault, 'CapacityExceeded') - }) - - it('fails when not harvested', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await updateRewards(keeper, [ - { - reward: ethers.parseEther('5'), - unlockedMevReward: 0n, - vault: await vault.getAddress(), - }, - ]) - await updateRewards(keeper, [ - { - reward: ethers.parseEther('10'), - unlockedMevReward: 0n, - vault: await vault.getAddress(), - }, - ]) - await expect( - vault - .connect(sender) - .deposit(receiver.address, referrer, { value: ethers.parseEther('10') }) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('update state and deposit', async () => { - await vault - .connect(other) - .deposit(other.address, referrer, { value: ethers.parseEther('32') }) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(other).enterExitQueue(ethers.parseEther('32'), other.address) - - let vaultReward = ethers.parseEther('10') - await updateRewards(keeper, [ - { - reward: vaultReward, - unlockedMevReward: vaultReward, - vault: await vault.getAddress(), - }, - ]) - - vaultReward = vaultReward + ethers.parseEther('1') - const tree = await updateRewards(keeper, [ - { - reward: vaultReward, - unlockedMevReward: vaultReward, - vault: await vault.getAddress(), - }, - ]) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward, - unlockedMevReward: vaultReward, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - unlockedMevReward: vaultReward, - reward: vaultReward, - }), - } - await setBalance(await mevEscrow.getAddress(), vaultReward) - await setBalance(await vault.getAddress(), ethers.parseEther('5')) - - const amount = ethers.parseEther('100') - const receipt = await vault - .connect(sender) - .updateStateAndDeposit(receiver.address, referrer, harvestParams, { value: amount }) - await expect(receipt).to.emit(vault, 'Deposited') - await expect(receipt).to.emit(keeper, 'Harvested') - await expect(receipt).to.emit(mevEscrow, 'Harvested') - await expect(receipt).to.emit(vault, 'CheckpointCreated') - await snapshotGasCost(receipt) - }) - - it('deposit', async () => { - const amount = ethers.parseEther('100') - const expectedShares = ethers.parseEther('100') - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - - const receipt = await vault - .connect(sender) - .deposit(receiver.address, referrer, { value: amount }) - expect(await vault.getShares(receiver.address)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, receiver.address, amount, expectedShares, referrer) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback function', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - const amount = ethers.parseEther('100') - const expectedShares = ethers.parseEther('100') - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/EthVault.liquidate.spec.ts b/test/EthVault.liquidate.spec.ts deleted file mode 100644 index 017d074e..00000000 --- a/test/EthVault.liquidate.spec.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - Keeper, - OsToken, - OsTokenConfig, - OsTokenVaultController, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { MAX_UINT64, ZERO_ADDRESS } from './shared/constants' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - setAvgRewardPerSecond, - updateRewards, -} from './shared/rewards' -import { extractDepositShares, setBalance } from './shared/utils' -import snapshotGasCost from './shared/snapshotGasCost' -import { MAINNET_FORK } from '../helpers/constants' - -describe('EthVault - liquidate', () => { - const assets = ethers.parseEther('32') - let shares: bigint - const osTokenAssets = ethers.parseEther('28.8') - let osTokenShares: bigint - const unlockedMevReward = ethers.parseEther('0') - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let owner: Wallet, admin: Signer, dao: Wallet, liquidator: Wallet, receiver: Wallet - let vault: EthVault, - keeper: Keeper, - osTokenVaultController: OsTokenVaultController, - osToken: OsToken, - osTokenConfig: OsTokenConfig, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createVault: ThenArg>['createEthVault'] - - beforeEach('deploy fixture', async () => { - ;[dao, owner, liquidator, admin, receiver] = await (ethers as any).getSigners() - ;({ - createEthVault: createVault, - keeper, - validatorsRegistry, - osTokenVaultController, - osToken, - osTokenConfig, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault(admin, vaultParams) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - await osTokenVaultController.connect(dao).setFeePercent(0) - - // collateralize vault - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const tx = await vault.connect(owner).deposit(owner.address, ZERO_ADDRESS, { value: assets }) - shares = await extractDepositShares(tx) - - // set avg reward per second to 0 - await setAvgRewardPerSecond(dao, vault, keeper, 0) - - // mint osTokens - osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - await vault.connect(owner).mintOsToken(owner.address, osTokenShares, ZERO_ADDRESS) - - // slash 5% of assets - const penalty = -((await vault.totalAssets()) * 5n) / 100n - - // slashing received - const vaultReward = getHarvestParams(await vault.getAddress(), penalty, unlockedMevReward) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await osToken.connect(owner).transfer(liquidator.address, osTokenShares) - }) - - it('cannot liquidate osTokens to zero receiver', async () => { - await expect( - vault.connect(liquidator).liquidateOsToken(osTokenShares, owner.address, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('cannot liquidate osTokens from not harvested vault', async () => { - await updateRewards(keeper, [ - getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), 0n), - ]) - await updateRewards(keeper, [ - getHarvestParams(await vault.getAddress(), ethers.parseEther('1.2'), 0n), - ]) - await expect( - vault.connect(liquidator).liquidateOsToken(osTokenShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('cannot liquidate osTokens for position with zero minted shares', async () => { - await expect( - vault.connect(liquidator).liquidateOsToken(osTokenShares, dao.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidPosition') - }) - - it('cannot liquidate osTokens when received assets exceed deposited assets', async () => { - await expect( - vault.connect(liquidator).liquidateOsToken(shares + 1n, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidReceivedAssets') - }) - - it('cannot liquidate osTokens when withdrawable assets exceed received assets', async () => { - await setBalance(await vault.getAddress(), 0n) - await expect( - vault.connect(liquidator).liquidateOsToken(osTokenShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidReceivedAssets') - }) - - it('cannot liquidate osTokens when liquidating more than minted', async () => { - await expect( - vault - .connect(liquidator) - .liquidateOsToken(osTokenShares + 1n, owner.address, receiver.address) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('cannot liquidate osTokens when health factor is above 1', async () => { - await osToken.connect(liquidator).transfer(owner.address, osTokenShares) - const liqShares = osTokenShares / 2n - await vault.connect(owner).burnOsToken(liqShares) - await expect( - vault.connect(liquidator).liquidateOsToken(liqShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidHealthFactor') - }) - - it('cannot liquidate zero osToken shares', async () => { - await expect( - vault.connect(liquidator).liquidateOsToken(0, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - }) - - it('cannot liquidate without osTokens', async () => { - await osToken.connect(liquidator).transfer(dao.address, osTokenShares) - await expect( - vault.connect(liquidator).liquidateOsToken(osTokenShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('cannot liquidate with disabled liquidations', async () => { - const currentConfig = await osTokenConfig.getConfig(await vault.getAddress()) - await osTokenConfig.connect(dao).updateConfig(await vault.getAddress(), { - liqBonusPercent: 0n, - liqThresholdPercent: MAX_UINT64, - ltvPercent: currentConfig.ltvPercent, - }) - await expect( - vault.connect(liquidator).liquidateOsToken(osTokenShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'LiquidationDisabled') - }) - - it('calculates liquidation correctly', async () => { - expect(await osToken.balanceOf(liquidator.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(owner.address)).to.be.eq(osTokenShares) - expect(await vault.getShares(owner.address)).to.be.eq(shares) - - const balanceBefore = await ethers.provider.getBalance(receiver.address) - const liqBonus = (await osTokenConfig.getConfig(await vault.getAddress())).liqBonusPercent - let liquidatorAssets = (osTokenAssets * BigInt(liqBonus)) / parseEther('1') - if (MAINNET_FORK.enabled) { - liquidatorAssets -= 2n // rounding error - } - const burnedShares = await vault.convertToShares(liquidatorAssets) - - const receipt = await vault - .connect(liquidator) - .liquidateOsToken(osTokenShares, owner.address, receiver.address) - - expect(await osToken.balanceOf(liquidator.address)).to.eq(0) - expect(await vault.osTokenPositions(owner.address)).to.be.eq(0) - expect(await vault.getShares(owner.address)).to.be.eq(shares - burnedShares) - expect(await ethers.provider.getBalance(receiver.address)).to.eq( - balanceBefore + liquidatorAssets - ) - - await expect(receipt) - .to.emit(vault, 'OsTokenLiquidated') - .withArgs( - liquidator.address, - owner.address, - receiver.address, - osTokenShares, - burnedShares, - liquidatorAssets - ) - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(liquidator.address, ZERO_ADDRESS, osTokenShares) - - let burnedAssets = osTokenAssets - if (MAINNET_FORK.enabled) { - burnedAssets -= 1n // rounding error - } - - await expect(receipt) - .to.emit(osTokenVaultController, 'Burn') - .withArgs(await vault.getAddress(), liquidator.address, burnedAssets, osTokenShares) // rounding error - - await snapshotGasCost(receipt) - }) - - it('can liquidate', async () => { - const receipt = await vault - .connect(liquidator) - .liquidateOsToken(osTokenShares, owner.address, receiver.address) - - await expect(receipt).to.emit(vault, 'OsTokenLiquidated') - await expect(receipt).to.emit(osToken, 'Transfer') - await expect(receipt).to.emit(osTokenVaultController, 'Burn') - - await snapshotGasCost(receipt) - }) -}) diff --git a/test/EthVault.mint.spec.ts b/test/EthVault.mint.spec.ts deleted file mode 100644 index 530c7c11..00000000 --- a/test/EthVault.mint.spec.ts +++ /dev/null @@ -1,321 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - Keeper, - OsToken, - VaultsRegistry, - OsTokenVaultController, - DepositDataRegistry, - OsTokenConfig, - IKeeperRewards, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import snapshotGasCost from './shared/snapshotGasCost' -import { createUnknownVaultMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { MAX_UINT256, ONE_DAY, ZERO_ADDRESS } from './shared/constants' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - setAvgRewardPerSecond, - updateRewards, -} from './shared/rewards' -import { extractDepositShares, increaseTime } from './shared/utils' -import { MAINNET_FORK } from '../helpers/constants' - -describe('EthVault - mint', () => { - const assets = ethers.parseEther('2') - let shares: bigint - let osTokenShares: bigint - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let dao: Wallet, sender: Wallet, receiver: Wallet, admin: Signer, other: Wallet - let vault: EthVault, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - osTokenVaultController: OsTokenVaultController, - osToken: OsToken, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry, - osTokenConfig: OsTokenConfig - - let createVault: ThenArg>['createEthVault'] - - beforeEach('deploy fixture', async () => { - ;[dao, sender, receiver, admin, other] = await (ethers as any).getSigners() - ;({ - createEthVault: createVault, - keeper, - validatorsRegistry, - osToken, - osTokenVaultController, - vaultsRegistry, - depositDataRegistry, - osTokenConfig, - } = await loadFixture(ethVaultFixture)) - vault = await createVault(admin, vaultParams) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - // collateralize vault - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const tx = await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: assets }) - shares = await extractDepositShares(tx) - osTokenShares = await osTokenVaultController.convertToShares(assets / 2n) - }) - - it('cannot mint osTokens from not collateralized vault', async () => { - const notCollatVault = await createVault(admin, vaultParams, false, true) - await expect( - notCollatVault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'NotCollateralized') - }) - - it('cannot mint osTokens from not harvested vault', async () => { - const vaultAddr = await vault.getAddress() - await updateRewards(keeper, [ - getHarvestParams(vaultAddr, ethers.parseEther('1'), ethers.parseEther('0')), - ]) - await updateRewards(keeper, [ - getHarvestParams(vaultAddr, ethers.parseEther('1.2'), ethers.parseEther('0')), - ]) - await expect( - vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('cannot mint osTokens to zero address', async () => { - await expect( - vault.connect(sender).mintOsToken(ZERO_ADDRESS, osTokenShares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('cannot mint zero osToken shares', async () => { - await expect( - vault.connect(sender).mintOsToken(receiver.address, 0, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - }) - - it('cannot mint osTokens from unregistered vault', async () => { - const unknownVault = await createUnknownVaultMock( - osTokenVaultController, - await vault.implementation() - ) - await expect( - unknownVault.connect(sender).mintOsToken(receiver.address, osTokenShares) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot mint osTokens from vault with unsupported implementation', async () => { - const unknownVault = await createUnknownVaultMock(osTokenVaultController, ZERO_ADDRESS) - await vaultsRegistry.connect(dao).addVault(await unknownVault.getAddress()) - await expect( - unknownVault.connect(sender).mintOsToken(receiver.address, osTokenShares) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot mint osTokens when it exceeds capacity', async () => { - const osTokenAssets = await vault.convertToAssets(osTokenShares) - await osTokenVaultController.connect(dao).setCapacity(osTokenAssets - 1n) - await expect( - vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'CapacityExceeded') - }) - - it('cannot mint osTokens when LTV is violated', async () => { - const shares = await vault.convertToAssets(assets) - await expect( - vault.connect(sender).mintOsToken(receiver.address, shares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'LowLtv') - }) - - it('cannot enter exit queue when LTV is violated', async () => { - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - await expect( - vault.connect(sender).enterExitQueue(shares, receiver.address) - ).to.be.revertedWithCustomError(vault, 'LowLtv') - }) - - it('updates position accumulated fee', async () => { - await vault.connect(dao).deposit(dao.address, ZERO_ADDRESS, { - value: await osTokenVaultController.convertToAssets(osTokenShares * 2n), - }) - await vault.connect(dao).mintOsToken(dao.address, osTokenShares, ZERO_ADDRESS) - await setAvgRewardPerSecond(dao, vault, keeper, 1005987242) - - const currTotalShares = await osTokenVaultController.totalShares() - const currTotalAssets = await osTokenVaultController.totalAssets() - const currCumulativeFeePerShare = await osTokenVaultController.cumulativeFeePerShare() - - expect(await vault.osTokenPositions(sender.address)).to.eq(0n) - - await increaseTime(ONE_DAY) - - await vault.connect(sender).mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - const newTotalShares = await osTokenVaultController.totalShares() - const newTotalAssets = await osTokenVaultController.totalAssets() - expect(newTotalShares).to.be.above(currTotalShares + osTokenShares) - expect(newTotalAssets).to.be.above(currTotalAssets) - expect(await osTokenVaultController.cumulativeFeePerShare()).to.be.above( - currCumulativeFeePerShare - ) - const currPositionShares = await vault.osTokenPositions(sender.address) - await increaseTime(ONE_DAY) - expect(await vault.osTokenPositions(sender.address)).to.be.above(currPositionShares) - - const newShares = 10n - const newAssets = await osTokenVaultController.convertToAssets(newShares) - const receipt = await vault - .connect(sender) - .mintOsToken(receiver.address, newShares, ZERO_ADDRESS) - expect(await osTokenVaultController.totalShares()).to.be.above(newTotalShares + 10n) - expect(await osTokenVaultController.totalAssets()).to.be.above(newTotalAssets + newAssets) - expect(await osTokenVaultController.cumulativeFeePerShare()).to.be.above( - currCumulativeFeePerShare - ) - expect(await vault.osTokenPositions(sender.address)).to.be.above(currPositionShares + newShares) - - await snapshotGasCost(receipt) - }) - - it('mints osTokens to the receiver', async () => { - const receipt = await vault - .connect(sender) - .mintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS) - const osTokenAssets = await osTokenVaultController.convertToAssets(osTokenShares) - - expect(await osToken.balanceOf(receiver.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(sender.address)).to.eq(osTokenShares) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(sender.address, receiver.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(ZERO_ADDRESS, receiver.address, osTokenShares) - await expect(receipt) - .to.emit(osTokenVaultController, 'Mint') - .withArgs(await vault.getAddress(), receiver.address, osTokenAssets, osTokenShares) - - await snapshotGasCost(receipt) - }) - - it('can deposit and mint osToken in one transaction', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - expect(await vault.osTokenPositions(other.address)).to.eq(0n) - expect(await vault.getShares(other.address)).to.eq(0n) - - const config = await osTokenConfig.getConfig(await vault.getAddress()) - let osTokenAssets = (assets * config.ltvPercent) / ethers.parseEther('1') - let osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - - // mint max shares - let receipt = await vault - .connect(other) - .depositAndMintOsToken(receiver.address, osTokenShares, ZERO_ADDRESS, { value: assets }) - - if (MAINNET_FORK.enabled) { - osTokenAssets -= 1n // rounding error - } - - expect(await osToken.balanceOf(receiver.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(other.address)).to.eq(osTokenShares) - expect(await vault.getShares(other.address)).to.eq(shares) - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(other.address, other.address, assets, shares, ZERO_ADDRESS) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(other.address, receiver.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - - // mint half shares - osTokenAssets = assets / 2n - osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - receipt = await vault - .connect(sender) - .depositAndMintOsToken(other.address, osTokenShares, ZERO_ADDRESS, { value: assets }) - - if (MAINNET_FORK.enabled) { - osTokenAssets -= 1n // rounding error - } - - expect(await osToken.balanceOf(other.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(sender.address)).to.eq(osTokenShares) - expect(await vault.getShares(sender.address)).to.eq(shares * 2n) - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, assets, shares, ZERO_ADDRESS) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(sender.address, other.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - - it('can update state, deposit, and mint osToken in one transaction', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 0) - const vaultAddr = await vault.getAddress() - - await updateRewards( - keeper, - [getHarvestParams(vaultAddr, ethers.parseEther('1'), ethers.parseEther('0'))], - 0 - ) - - const tree = await updateRewards( - keeper, - [getHarvestParams(vaultAddr, ethers.parseEther('1.2'), ethers.parseEther('0'))], - 0 - ) - const vaultReward = getHarvestParams( - vaultAddr, - ethers.parseEther('1.2'), - ethers.parseEther('0') - ) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - const sharesBefore = await vault.convertToShares(assets) - - expect(await vault.osTokenPositions(other.address)).to.eq(0n) - expect(await vault.getShares(other.address)).to.eq(0n) - - const config = await osTokenConfig.getConfig(await vault.getAddress()) - let osTokenAssets = (assets * config.ltvPercent) / ethers.parseEther('1') - const osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - osTokenAssets = await osTokenVaultController.convertToAssets(osTokenShares) - - const receipt = await vault - .connect(other) - .updateStateAndDepositAndMintOsToken( - receiver.address, - MAX_UINT256, - ZERO_ADDRESS, - harvestParams, - { - value: assets, - } - ) - let sharesAfter = await vault.convertToShares(assets) - sharesAfter += 1n // rounding error - - expect(sharesBefore).to.gt(sharesAfter) - expect(await osToken.balanceOf(receiver.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(other.address)).to.eq(osTokenShares) - expect(await vault.getShares(other.address)).to.eq(sharesAfter) - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(other.address, other.address, assets, sharesAfter, ZERO_ADDRESS) - await expect(receipt) - .to.emit(vault, 'OsTokenMinted') - .withArgs(other.address, receiver.address, osTokenAssets, osTokenShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) -}) diff --git a/test/EthVault.multicall.spec.ts b/test/EthVault.multicall.spec.ts deleted file mode 100644 index 30f85775..00000000 --- a/test/EthVault.multicall.spec.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - IKeeperRewards, - Keeper, - MulticallMock, - OwnMevEscrow__factory, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import snapshotGasCost from './shared/snapshotGasCost' -import { createMulticallMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { - extractExitPositionTicket, - getBlockTimestamp, - getLatestBlockTimestamp, - increaseTime, - setBalance, -} from './shared/utils' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import { registerEthValidator } from './shared/validators' -import { ONE_DAY } from './shared/constants' - -describe('EthVault - multicall', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = '0x' + '1'.repeat(40) - const metadataIpfsHash = '/ipfs/QmanU2bk9VsJuxhBmvfgXaC44fXpcC8DNHNxPZKMpNXo37' - - let sender: Wallet, admin: Signer - let vault: EthVault, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createVault: ThenArg>['createEthVault'] - - beforeEach('deploy fixture', async () => { - ;[sender, admin] = (await (ethers as any).getSigners()).slice(1, 3) - ;({ - createEthVault: createVault, - keeper, - validatorsRegistry, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - }) - - it('can update state and queue for exit', async () => { - const mevEscrow = OwnMevEscrow__factory.connect(await vault.mevEscrow(), sender) - const vaultAddr = await vault.getAddress() - - // collateralize vault - await vault - .connect(sender) - .deposit(sender.address, referrer, { value: ethers.parseEther('32') }) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await setBalance(await mevEscrow.getAddress(), ethers.parseEther('10')) - - const userShares = await vault.getShares(sender.address) - - // update rewards root for the vault - const vaultReward = getHarvestParams(vaultAddr, ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - - // retrieve redeemable shares after state update - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, { - vault: vaultReward.vault, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - }), - } - - // fetch available assets and user assets after state update - let calls: string[] = [ - vault.interface.encodeFunctionData('updateState', [harvestParams]), - vault.interface.encodeFunctionData('convertToAssets', [userShares]), - ] - let result = await vault.multicall.staticCall(calls) - const userAssets = vault.interface.decodeFunctionResult('convertToAssets', result[1])[0] - - // convert exit queue assets to shares - calls = [ - vault.interface.encodeFunctionData('updateState', [harvestParams]), - vault.interface.encodeFunctionData('convertToShares', [userAssets]), - ] - result = await vault.multicall.staticCall(calls) - const exitQueueShares = vault.interface.decodeFunctionResult('convertToShares', result[1])[0] - - calls = [vault.interface.encodeFunctionData('updateState', [harvestParams])] - - // add call for entering exit queue - calls.push( - vault.interface.encodeFunctionData('enterExitQueue', [exitQueueShares, sender.address]) - ) - - await updateRewards(keeper, [vaultReward]) - - let receipt = await vault.connect(sender).multicall(calls) - const queueTicket = await extractExitPositionTicket(receipt) - const timestamp = await getBlockTimestamp(receipt) - await expect(receipt).to.emit(keeper, 'Harvested') - await expect(receipt).to.emit(mevEscrow, 'Harvested') - await expect(receipt).to.emit(vault, 'ExitQueueEntered') - await snapshotGasCost(receipt) - const vaultTotalBalance = - userAssets + - (await ethers.provider.getBalance(vaultAddr)) + - (await vault.convertToAssets(await vault.queuedShares())) - - // wait for exit queue to complete and withdraw exited assets - await setBalance(await vault.getAddress(), vaultTotalBalance) - - // wait for exit queue - await increaseTime(ONE_DAY) - await updateRewards(keeper, [vaultReward]) - - calls = [vault.interface.encodeFunctionData('updateState', [harvestParams])] - calls.push(vault.interface.encodeFunctionData('getExitQueueIndex', [queueTicket])) - result = await vault.connect(sender).multicall.staticCall(calls) - const checkpointIndex = vault.interface.decodeFunctionResult('getExitQueueIndex', result[1])[0] - - calls = [vault.interface.encodeFunctionData('updateState', [harvestParams])] - calls.push( - vault.interface.encodeFunctionData('claimExitedAssets', [ - queueTicket, - timestamp, - checkpointIndex, - ]) - ) - - receipt = await vault.connect(sender).multicall(calls) - await expect(receipt) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(sender.address, queueTicket, 0, userAssets - 1n) // 1 wei is left in the vault - await snapshotGasCost(receipt) - }) - - it('fails to deposit in multicall', async () => { - const calls: string[] = [ - vault.interface.encodeFunctionData('deposit', [sender.address, referrer]), - ] - await expect(vault.connect(sender).multicall(calls)).reverted - }) - - describe('flash loan', () => { - let multicallMock: MulticallMock - - beforeEach(async () => { - multicallMock = await createMulticallMock() - }) - - it('fails to deposit, enter exit queue, update state and claim in one transaction', async () => { - const vaultAddr = await vault.getAddress() - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - expect(await vault.isStateUpdateRequired()).to.eq(false) - expect(await keeper.canHarvest(vaultAddr)).to.eq(false) - - const vaultReward = getHarvestParams(vaultAddr, ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - await setBalance(await vault.mevEscrow(), ethers.parseEther('1')) - expect(await vault.isStateUpdateRequired()).to.eq(false) - expect(await keeper.canHarvest(vaultAddr)).to.eq(true) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, { - vault: vaultAddr, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - }), - } - - const amount = ethers.parseEther('1') - const currentBlockTimestamp = await getLatestBlockTimestamp() - await ethers.provider.send('evm_setNextBlockTimestamp', [currentBlockTimestamp + 1]) - const calls = [ - { - target: vaultAddr, - isPayable: true, - callData: vault.interface.encodeFunctionData('deposit', [ - await multicallMock.getAddress(), - referrer, - ]), - }, - { - target: vaultAddr, - isPayable: false, - callData: vault.interface.encodeFunctionData('enterExitQueue', [ - amount, - await multicallMock.getAddress(), - ]), - }, - { - target: vaultAddr, - isPayable: false, - callData: vault.interface.encodeFunctionData('updateState', [harvestParams]), - }, - { - target: vaultAddr, - isPayable: false, - callData: vault.interface.encodeFunctionData('claimExitedAssets', [ - ethers.parseEther('32'), - currentBlockTimestamp + 1, - 1, - ]), - }, - ] - await expect(multicallMock.connect(sender).aggregate(calls, { value: amount })).reverted - }) - }) -}) diff --git a/test/EthVault.redeem.spec.ts b/test/EthVault.redeem.spec.ts deleted file mode 100644 index 2a919e69..00000000 --- a/test/EthVault.redeem.spec.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - IKeeperRewards, - Keeper, - OsToken, - OsTokenConfig, - OsTokenVaultController, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { - OSTOKEN_LIQ_BONUS, - OSTOKEN_LIQ_THRESHOLD, - OSTOKEN_LTV, - ZERO_ADDRESS, -} from './shared/constants' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - setAvgRewardPerSecond, - updateRewards, -} from './shared/rewards' -import { extractDepositShares, setBalance } from './shared/utils' -import snapshotGasCost from './shared/snapshotGasCost' -import { MAINNET_FORK } from '../helpers/constants' - -describe('EthVault - redeem osToken', () => { - const assets = ethers.parseEther('32') - const osTokenAssets = ethers.parseEther('28.8') - let shares: bigint - let osTokenShares: bigint - const unlockedMevReward = ethers.parseEther('0') - const redeemedAssets = ethers.parseEther('4.76') - let redeemedShares: bigint - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let owner: Wallet, admin: Signer, dao: Wallet, redeemer: Wallet, receiver: Wallet - let vault: EthVault, - keeper: Keeper, - osTokenVaultController: OsTokenVaultController, - osToken: OsToken, - osTokenConfig: OsTokenConfig, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createVault: ThenArg>['createEthVault'] - - beforeEach('deploy fixture', async () => { - ;[dao, owner, redeemer, admin, receiver] = await (ethers as any).getSigners() - ;({ - createEthVault: createVault, - keeper, - validatorsRegistry, - osTokenVaultController, - osToken, - osTokenConfig, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault(admin, vaultParams) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - await osTokenVaultController.connect(dao).setFeePercent(0) - - // collateralize vault - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const tx = await vault.connect(owner).deposit(owner.address, ZERO_ADDRESS, { value: assets }) - shares = await extractDepositShares(tx) - - await setAvgRewardPerSecond(dao, vault, keeper, 0) - await osTokenConfig.connect(dao).updateConfig(await vault.getAddress(), { - liqThresholdPercent: OSTOKEN_LIQ_THRESHOLD, - liqBonusPercent: OSTOKEN_LIQ_BONUS, - ltvPercent: OSTOKEN_LTV, - }) - osTokenShares = await osTokenVaultController.convertToShares(osTokenAssets) - redeemedShares = await osTokenVaultController.convertToShares(redeemedAssets) - await vault.connect(owner).mintOsToken(owner.address, osTokenShares, ZERO_ADDRESS) - - // penalty received - // slash 1% of assets - const penalty = -((await vault.totalAssets()) * 2n) / 100n - const vaultReward = getHarvestParams(await vault.getAddress(), penalty, unlockedMevReward) - const tree = await updateRewards(keeper, [vaultReward], 0) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - await osToken.connect(owner).transfer(redeemer.address, osTokenShares) - await osTokenConfig.connect(dao).setRedeemer(redeemer.address) - }) - - it('cannot redeem osTokens from not redeemer', async () => { - await osTokenConfig.connect(dao).setRedeemer(dao.address) - await expect( - vault.connect(redeemer).redeemOsToken(redeemedShares, owner.address, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot redeem osTokens to zero receiver', async () => { - await expect( - vault.connect(redeemer).redeemOsToken(redeemedShares, owner.address, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('cannot redeem osTokens from not harvested vault', async () => { - await updateRewards(keeper, [ - { - vault: await vault.getAddress(), - reward: ethers.parseEther('1'), - unlockedMevReward: ethers.parseEther('0'), - }, - ]) - await updateRewards(keeper, [ - { - vault: await vault.getAddress(), - reward: ethers.parseEther('1.2'), - unlockedMevReward: ethers.parseEther('0'), - }, - ]) - await expect( - vault.connect(redeemer).redeemOsToken(redeemedShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('cannot redeem osTokens for position with zero minted shares', async () => { - await expect( - vault.connect(redeemer).redeemOsToken(redeemedShares, dao.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidPosition') - }) - - it('cannot redeem osTokens when withdrawable assets exceed received assets', async () => { - await setBalance(await vault.getAddress(), 0n) - await expect( - vault.connect(redeemer).redeemOsToken(redeemedShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidReceivedAssets') - }) - - it('cannot redeem osTokens when redeeming more than minted', async () => { - await expect( - vault.connect(redeemer).redeemOsToken(osTokenShares + 1n, owner.address, receiver.address) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('cannot redeem zero osToken shares', async () => { - await expect( - vault.connect(redeemer).redeemOsToken(0, owner.address, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - }) - - it('cannot redeem without osTokens', async () => { - await osToken.connect(redeemer).transfer(dao.address, osTokenShares) - await expect( - vault.connect(redeemer).redeemOsToken(osTokenShares, owner.address, receiver.address) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('calculates redeem correctly', async () => { - expect(await osToken.balanceOf(redeemer.address)).to.eq(osTokenShares) - expect(await vault.osTokenPositions(owner.address)).to.be.eq(osTokenShares) - expect(await vault.getShares(owner.address)).to.be.eq(shares) - - const balanceBefore = await ethers.provider.getBalance(receiver.address) - let burnedShares = await vault.convertToShares(redeemedAssets) - let receiverAssets = redeemedAssets - - const receipt = await vault - .connect(redeemer) - .redeemOsToken(redeemedShares, owner.address, receiver.address) - - if (MAINNET_FORK.enabled) { - burnedShares -= 1n // rounding error - receiverAssets -= 1n // rounding error - } - - expect(await osToken.balanceOf(redeemer.address)).to.eq(osTokenShares - redeemedShares) - expect(await vault.osTokenPositions(owner.address)).to.be.eq(osTokenShares - redeemedShares) - expect(await vault.getShares(owner.address)).to.be.eq(shares - burnedShares) - expect(await ethers.provider.getBalance(receiver.address)).to.eq(balanceBefore + receiverAssets) - - await expect(receipt) - .to.emit(vault, 'OsTokenRedeemed') - .withArgs( - redeemer.address, - owner.address, - receiver.address, - redeemedShares, - burnedShares, - receiverAssets - ) - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(redeemer.address, ZERO_ADDRESS, redeemedShares) - await expect(receipt) - .to.emit(osTokenVaultController, 'Burn') - .withArgs(await vault.getAddress(), redeemer.address, receiverAssets, redeemedShares) - - await snapshotGasCost(receipt) - }) - - it('can redeem', async () => { - const receipt = await vault - .connect(redeemer) - .redeemOsToken(redeemedShares, owner.address, receiver.address) - - await expect(receipt).to.emit(vault, 'OsTokenRedeemed') - await expect(receipt).to.emit(osToken, 'Transfer') - await expect(receipt).to.emit(osTokenVaultController, 'Burn') - - await snapshotGasCost(receipt) - }) -}) diff --git a/test/EthVault.register.spec.ts b/test/EthVault.register.spec.ts deleted file mode 100644 index aa6a9b10..00000000 --- a/test/EthVault.register.spec.ts +++ /dev/null @@ -1,499 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { UintNumberType } from '@chainsafe/ssz' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { ThenArg } from '../helpers/types' -import { EthVault, IKeeperValidators, Keeper } from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { expect } from './shared/expect' -import { setBalance, toHexString } from './shared/utils' -import { - appendDepositData, - createEthValidatorsData, - EthValidatorsData, - exitSignatureIpfsHashes, - getEthValidatorsSigningData, - getValidatorsManagerSigningData, - getWithdrawalCredentials, -} from './shared/validators' -import { ethVaultFixture, getOraclesSignatures } from './shared/fixtures' -import { - MAX_UINT256, - VALIDATORS_DEADLINE, - VALIDATORS_MIN_ORACLES, - ZERO_ADDRESS, -} from './shared/constants' -import { getHarvestParams, updateRewards } from './shared/rewards' -import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util' - -const gwei = 1000000000n -const uintSerializer = new UintNumberType(8) -const privateKey = '0x7c93e5f6928cb70e47ef96e9e800fc320efdaf7d4114ce84ab7c7679796e5973' - -describe('EthVault - register', () => { - const validatorDeposit = ethers.parseEther('32') - const capacity = MAX_UINT256 - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const deadline = VALIDATORS_DEADLINE - - let admin: Signer, other: Wallet, validatorsManager: Wallet - let vault: EthVault, keeper: Keeper, validatorsRegistry: Contract - let validatorsData: EthValidatorsData - let validatorsRegistryRoot: string - - let createVault: ThenArg>['createEthVault'] - - before('create fixture loader', async () => { - ;[admin, other, validatorsManager] = (await (ethers as any).getSigners()).slice(1, 4) - }) - - beforeEach('deploy fixture', async () => { - ;({ - validatorsRegistry, - createEthVault: createVault, - keeper, - } = await loadFixture(ethVaultFixture)) - - vault = await createVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - validatorsData = await createEthValidatorsData(vault) - validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: validatorDeposit }) - await vault.connect(admin).setValidatorsManager(validatorsManager.address) - }) - - describe('single validator', () => { - let validator: Buffer - let approvalParams: IKeeperValidators.ApprovalParamsStruct - - beforeEach(async () => { - validator = validatorsData.validators[0] - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - validator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - approvalParams = { - validatorsRegistryRoot, - validators: validator, - signatures, - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails from non-validators manager', async () => { - await expect( - vault.connect(other).registerValidators(approvalParams, '0x') - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails with not enough withdrawable assets', async () => { - await setBalance(await vault.getAddress(), ethers.parseEther('31.9')) - await expect( - vault.connect(validatorsManager).registerValidators(approvalParams, '0x') - ).to.be.revertedWithCustomError(vault, 'InsufficientAssets') - }) - - it('fails with invalid validators manager signature', async () => { - const invalidManager = Wallet.createRandom() - const signingData = await getValidatorsManagerSigningData( - approvalParams.validators, - vault, - approvalParams.validatorsRegistryRoot - ) - const signature = signTypedData({ - privateKey: invalidManager.privateKey.slice(2), - data: signingData, - version: SignTypedDataVersion.V4, - }) - await expect( - vault.connect(other).registerValidators(approvalParams, signature) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('fails when not harvested', async () => { - // collateralize - const vaultReward = getHarvestParams(await vault.getAddress(), 1n, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - const proof = tree.getProof([ - vaultReward.vault, - vaultReward.reward, - vaultReward.unlockedMevReward, - ]) - await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - // make vault not harvested - await updateRewards(keeper, [vaultReward]) - await updateRewards(keeper, [vaultReward]) - await expect( - vault.connect(validatorsManager).registerValidators(approvalParams, '0x') - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('fails with invalid validator length', async () => { - const invalidValidator = appendDepositData( - Buffer.alloc(1), - validatorDeposit, - await vault.getAddress() - ) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: invalidValidator, - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidator, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - }) - - it('succeeds from validators manager', async () => { - const index = await validatorsRegistry.get_deposit_count() - const receipt = await vault - .connect(validatorsManager) - .registerValidators(approvalParams, '0x') - const publicKey = `0x${validator.subarray(0, 48).toString('hex')}` - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - index - ) - await snapshotGasCost(receipt) - }) - - it('succeeds using validators manager signature', async () => { - const index = await validatorsRegistry.get_deposit_count() - const manager = new ethers.Wallet(privateKey) - await vault.connect(admin).setValidatorsManager(await manager.getAddress()) - const signingData = await getValidatorsManagerSigningData( - approvalParams.validators, - vault, - approvalParams.validatorsRegistryRoot - ) - const signature = signTypedData({ - privateKey: manager.privateKey.slice(2), - data: signingData, - version: SignTypedDataVersion.V4, - }) - const receipt = await vault.connect(other).registerValidators(approvalParams, signature) - const publicKey = `0x${validator.subarray(0, 48).toString('hex')}` - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - index - ) - }) - }) - - describe('multiple validators', () => { - let validators: Buffer[] - let approvalParams: IKeeperValidators.ApprovalParamsStruct - let signatures: Buffer - - beforeEach(async () => { - validators = validatorsData.validators - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - const vaultAddr = await vault.getAddress() - const balance = - validatorDeposit * BigInt(validators.length) + (await ethers.provider.getBalance(vaultAddr)) - await setBalance(vaultAddr, balance) - signatures = getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.concat(validators), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ) - approvalParams = { - validatorsRegistryRoot, - validators: Buffer.concat(validators), - signatures, - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails with not enough withdrawable assets', async () => { - await setBalance(await vault.getAddress(), validatorDeposit * BigInt(validators.length - 1)) - await expect( - vault.connect(validatorsManager).registerValidators(approvalParams, '0x') - ).to.be.revertedWithCustomError(vault, 'InsufficientAssets') - }) - - it('fails with invalid validators count', async () => { - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: Buffer.from(''), - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - Buffer.from(''), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - }) - - it('fails with invalid deposit data root', async () => { - const invalidRoot = appendDepositData( - validators[1].subarray(0, 144), - validatorDeposit, - await vault.getAddress() - ).subarray(144, 176) - const invalidValidators = [ - Buffer.concat([validators[0].subarray(0, 144), invalidRoot]), - ...validators.slice(1), - ] - const invalidValidatorsConcat = Buffer.concat(invalidValidators) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - deadline, - validators: invalidValidatorsConcat, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidatorsConcat, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWith( - 'DepositContract: reconstructed DepositData does not match supplied deposit_data_root' - ) - }) - - it('fails with invalid deposit amount', async () => { - const invalidValidators = [ - appendDepositData( - validators[0].subarray(0, 144), - ethers.parseEther('1'), - await vault.getAddress() - ), - ...validators.slice(1), - ] - const invalidValidatorsConcat = Buffer.concat(invalidValidators) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: invalidValidatorsConcat, - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidatorsConcat, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWith( - 'DepositContract: reconstructed DepositData does not match supplied deposit_data_root' - ) - }) - - it('fails with invalid withdrawal credentials', async () => { - const invalidValidators = [ - appendDepositData( - validators[0].subarray(0, 144), - ethers.parseEther('1'), - await keeper.getAddress() - ), - ...validators.slice(1), - ] - const invalidValidatorsConcat = Buffer.concat(invalidValidators) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: invalidValidatorsConcat, - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidatorsConcat, - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWith( - 'DepositContract: reconstructed DepositData does not match supplied deposit_data_root' - ) - }) - - it('fails with invalid validator length', async () => { - const invalidValidators = [ - validators[0].subarray(0, 100), - Buffer.concat([validators[0], validators[1].subarray(0, 10)]), - ] - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - - for (let i = 0; i < invalidValidators.length; i++) { - await expect( - vault.connect(validatorsManager).registerValidators( - { - validatorsRegistryRoot, - validators: invalidValidators[i], - deadline, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - invalidValidators[i], - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - VALIDATORS_MIN_ORACLES - ), - exitSignaturesIpfsHash, - }, - '0x' - ) - ).to.be.revertedWithCustomError(vault, 'InvalidValidators') - } - }) - - it('succeeds from validators manager', async () => { - const startIndex = uintSerializer.deserialize( - ethers.getBytes(await validatorsRegistry.get_deposit_count()) - ) - const receipt = await vault - .connect(validatorsManager) - .registerValidators(approvalParams, '0x') - for (let i = 0; i < validators.length; i++) { - const validator = validators[i] - const publicKey = toHexString(validator.subarray(0, 48)) - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - toHexString(Buffer.from(uintSerializer.serialize(startIndex + i))) - ) - } - await snapshotGasCost(receipt) - }) - - it('succeeds using validators manager signature', async () => { - const manager = new ethers.Wallet(privateKey) - await vault.connect(admin).setValidatorsManager(await manager.getAddress()) - const signingData = await getValidatorsManagerSigningData( - approvalParams.validators, - vault, - approvalParams.validatorsRegistryRoot - ) - const signature = signTypedData({ - privateKey: manager.privateKey.slice(2), - data: signingData, - version: SignTypedDataVersion.V4, - }) - const startIndex = uintSerializer.deserialize( - ethers.getBytes(await validatorsRegistry.get_deposit_count()) - ) - const receipt = await vault - .connect(validatorsManager) - .registerValidators(approvalParams, signature) - for (let i = 0; i < validators.length; i++) { - const validator = validators[i] - const publicKey = toHexString(validator.subarray(0, 48)) - await expect(receipt).to.emit(vault, 'ValidatorRegistered').withArgs(publicKey) - await expect(receipt) - .to.emit(validatorsRegistry, 'DepositEvent') - .withArgs( - publicKey, - toHexString(getWithdrawalCredentials(await vault.getAddress())), - toHexString(Buffer.from(uintSerializer.serialize(Number(validatorDeposit / gwei)))), - toHexString(validator.subarray(48, 144)), - toHexString(Buffer.from(uintSerializer.serialize(startIndex + i))) - ) - } - }) - }) -}) diff --git a/test/EthVault.settings.spec.ts b/test/EthVault.settings.spec.ts deleted file mode 100644 index 5e2f1272..00000000 --- a/test/EthVault.settings.spec.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' - -import { EthVault, Keeper, DepositDataRegistry } from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import snapshotGasCost from './shared/snapshotGasCost' -import { ZERO_ADDRESS } from './shared/constants' -import { collateralizeEthVault, updateRewards } from './shared/rewards' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' - -describe('EthVault - settings', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - let createVault: ThenArg>['createEthVault'] - let admin: Wallet, validatorsManager: Wallet, other: Wallet, newFeeRecipient: Wallet - let keeper: Keeper, validatorsRegistry: Contract, depositDataRegistry: DepositDataRegistry - - before('create fixture loader', async () => { - ;[admin, validatorsManager, other, newFeeRecipient] = ( - await (ethers as any).getSigners() - ).slice(1, 5) - }) - - beforeEach('deploy fixture', async () => { - ;({ - keeper, - validatorsRegistry, - depositDataRegistry, - createEthVault: createVault, - } = await loadFixture(ethVaultFixture)) - }) - - describe('fee percent', () => { - it('cannot be set to invalid value', async () => { - const vault = await createVault( - admin, - { - capacity, - feePercent: 10000, - metadataIpfsHash, - }, - false, - true - ) - await expect( - createVault( - admin, - { - capacity, - feePercent: 10001, - metadataIpfsHash, - }, - false, - true - ) - ).to.be.revertedWithCustomError(vault, 'InvalidFeePercent') - }) - }) - - describe('validators manager', () => { - let vault: EthVault - - beforeEach('deploy vault', async () => { - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - }) - - it('cannot be updated by anyone', async () => { - await expect( - vault.connect(other).setValidatorsManager(validatorsManager.address) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be updated by admin', async () => { - // initially equals to admin - expect(await vault.validatorsManager()).to.be.eq(await depositDataRegistry.getAddress()) - const receipt = await vault.connect(admin).setValidatorsManager(validatorsManager.address) - await expect(receipt) - .to.emit(vault, 'ValidatorsManagerUpdated') - .withArgs(admin.address, validatorsManager.address) - expect(await vault.validatorsManager()).to.be.eq(validatorsManager.address) - await snapshotGasCost(receipt) - }) - }) - - describe('fee recipient', () => { - let vault: EthVault - - beforeEach('deploy vault', async () => { - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - }) - - it('only admin can update', async () => { - await expect( - vault.connect(other).setFeeRecipient(newFeeRecipient.address) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set to zero address', async () => { - await expect( - vault.connect(admin).setFeeRecipient(ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'InvalidFeeRecipient') - }) - - it('cannot update when not harvested', async () => { - await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 1n, unlockedMevReward: 0n }, - ]) - await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 2n, unlockedMevReward: 0n }, - ]) - await expect( - vault.connect(admin).setFeeRecipient(newFeeRecipient.address) - ).to.be.revertedWithCustomError(vault, 'NotHarvested') - }) - - it('can update', async () => { - expect(await vault.feeRecipient()).to.be.eq(admin.address) - const receipt = await vault.connect(admin).setFeeRecipient(newFeeRecipient.address) - await expect(receipt) - .to.emit(vault, 'FeeRecipientUpdated') - .withArgs(admin.address, newFeeRecipient.address) - expect(await vault.feeRecipient()).to.be.eq(newFeeRecipient.address) - await snapshotGasCost(receipt) - }) - }) - - describe('metadata IPFS hash', () => { - let vault: EthVault - const newMetadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - beforeEach('deploy vault', async () => { - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - }) - - it('only admin can update', async () => { - await expect( - vault.connect(other).setMetadata(newMetadataIpfsHash) - ).to.be.revertedWithCustomError(vault, 'AccessDenied') - const receipt = await vault.connect(admin).setMetadata(newMetadataIpfsHash) - await expect(receipt) - .to.emit(vault, 'MetadataUpdated') - .withArgs(admin.address, newMetadataIpfsHash) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/EthVault.state.spec.ts b/test/EthVault.state.spec.ts deleted file mode 100644 index 5a6b2b4c..00000000 --- a/test/EthVault.state.spec.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - Keeper, - OwnMevEscrow__factory, - SharedMevEscrow, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import snapshotGasCost from './shared/snapshotGasCost' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { - MAX_UINT256, - PANIC_CODES, - SECURITY_DEPOSIT, - ZERO_ADDRESS, - ZERO_BYTES32, -} from './shared/constants' -import { extractDepositShares, setBalance } from './shared/utils' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' - -describe('EthVault - state', () => { - const holderAssets = ethers.parseEther('1') - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - let holder: Wallet, admin: Signer, other: Wallet - let vault: EthVault, - keeper: Keeper, - sharedMevEscrow: SharedMevEscrow, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createVault: ThenArg>['createEthVault'] - let createVaultMock: ThenArg>['createEthVaultMock'] - - beforeEach('deploy fixture', async () => { - ;[holder, admin, other] = (await (ethers as any).getSigners()).slice(1, 4) - ;({ - createEthVault: createVault, - createEthVaultMock: createVaultMock, - keeper, - validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - await vault.connect(holder).deposit(holder.address, ZERO_ADDRESS, { value: holderAssets }) - }) - - it('does not fail with zero assets delta', async () => { - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(tree, vaultReward) - const receipt = await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs(await vault.getAddress(), tree.root, 0, 0) - await expect(receipt).to.not.emit(sharedMevEscrow, 'Harvested') - }) - - it('reverts when overflow', async () => { - const reward = (2n ** 160n - 1n) / 2n - const unlockedMevReward = 2n ** 160n - 1n - const tree = await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward, unlockedMevReward }, - ]) - await setBalance(await sharedMevEscrow.getAddress(), unlockedMevReward) - await expect( - vault.updateState({ - rewardsRoot: tree.root, - reward, - unlockedMevReward, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - reward, - unlockedMevReward, - }), - }) - ).revertedWithCustomError(vault, 'SafeCastOverflowedUintDowncast') - }) - - it('reverts when underflow', async () => { - const reward = ethers.parseEther('-2') - const tree = await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward, unlockedMevReward: 0n }, - ]) - await expect( - vault.updateState({ - rewardsRoot: tree.root, - reward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - reward, - unlockedMevReward: 0n, - }), - }) - ).revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('is not affected by inflation attack', async () => { - const vault = await createVaultMock( - admin as Wallet, - { - capacity: MAX_UINT256, - feePercent: 0, - metadataIpfsHash, - }, - true - ) - const securityDeposit = 1000000000n - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: 1 }) - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault._setTotalAssets(1) - expect(await vault.totalAssets()).to.eq(1) - expect(await vault.totalShares()).to.eq(securityDeposit + 1n) - - // attacker drops a lot of eth as a reward - const burnedAssets = ethers.parseEther('1000') - await setBalance(await vault.mevEscrow(), burnedAssets) - - // state is updated - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 1n) - const tree = await updateRewards(keeper, [vaultReward]) - await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, { - vault: vaultReward.vault, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - }), - }) - - // small amount of shares own a lot of assets - expect(await vault.totalAssets()).to.eq(burnedAssets + 1n) - expect(await vault.totalShares()).to.eq(securityDeposit + 1n) - - // user deposits - const userAssets = ethers.parseEther('10') - await vault.connect(holder).deposit(holder.address, ZERO_ADDRESS, { value: userAssets }) - - // user lost ~ 10 gwei due to the inflation above - expect( - userAssets - (await vault.convertToAssets(await vault.getShares(holder.address))) - ).to.be.below(10000000000) - }) - - it('only vault can harvest', async () => { - await expect( - keeper.harvest({ rewardsRoot: ZERO_BYTES32, reward: 0n, unlockedMevReward: 0n, proof: [] }) - ).revertedWithCustomError(keeper, 'AccessDenied') - }) - - it('only mev escrow can send ether', async () => { - await expect(vault.connect(other).receiveFromMevEscrow()).revertedWithCustomError( - vault, - 'AccessDenied' - ) - }) - - it('applies penalty when delta is below zero', async () => { - const penalty = ethers.parseEther('-0.5') - const rewardMevEscrow = ethers.parseEther('0.3') - await setBalance(await vault.mevEscrow(), rewardMevEscrow) - const vaultReward = getHarvestParams(await vault.getAddress(), penalty, rewardMevEscrow) - const tree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(tree, { - vault: vaultReward.vault, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - }) - - const totalSharesBefore = await vault.totalShares() - const totalAssetsBefore = await vault.totalAssets() - const balanceBefore = await ethers.provider.getBalance(await vault.getAddress()) - const receipt = await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - await expect(receipt) - .emit(keeper, 'Harvested') - .withArgs(await vault.getAddress(), tree.root, penalty, rewardMevEscrow) - await expect(receipt) - .emit(sharedMevEscrow, 'Harvested') - .withArgs(await vault.getAddress(), rewardMevEscrow) - await expect(receipt).not.emit(vault, 'FeeSharesMinted') - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq( - rewardMevEscrow + balanceBefore - ) - expect(await vault.totalShares()).to.be.eq(totalSharesBefore) - expect(await vault.totalAssets()).to.be.eq(totalAssetsBefore + penalty) - await snapshotGasCost(receipt) - }) - - it('allocates fee to recipient when delta is above zero', async () => { - // create vault with own mev escrow - const vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true, - true - ) - await vault.connect(holder).deposit(holder.address, ZERO_ADDRESS, { value: holderAssets }) - - const mevEscrow = OwnMevEscrow__factory.connect(await vault.mevEscrow(), admin) - const rewardValidators = ethers.parseEther('0.5') - const rewardMevEscrow = ethers.parseEther('0.5') - const operatorReward = ethers.parseEther('0.1') - const reward = rewardValidators + rewardMevEscrow - - await setBalance(await mevEscrow.getAddress(), rewardMevEscrow) - const vaultReward = getHarvestParams(await vault.getAddress(), rewardValidators, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(tree, vaultReward) - - const totalSharesBefore = await vault.totalShares() - const totalAssetsBefore = await vault.totalAssets() - const receipt = await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - const operatorShares = await vault.getShares(await admin.getAddress()) - expect(await vault.convertToAssets(operatorShares)).to.be.eq(operatorReward - 2n) // rounding error - expect(await vault.convertToShares(operatorReward)).to.be.eq(operatorShares) - expect(await ethers.provider.getBalance(await mevEscrow.getAddress())).to.be.eq(0) - - await expect(receipt) - .emit(keeper, 'Harvested') - .withArgs(await vault.getAddress(), tree.root, rewardValidators, 0) - await expect(receipt).emit(mevEscrow, 'Harvested').withArgs(rewardMevEscrow) - await expect(receipt) - .emit(vault, 'FeeSharesMinted') - .withArgs(await admin.getAddress(), operatorShares, operatorReward) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq( - rewardMevEscrow + holderAssets + SECURITY_DEPOSIT - ) - expect(await vault.totalShares()).to.be.eq(totalSharesBefore + operatorShares) - expect(await vault.totalAssets()).to.be.eq(totalAssetsBefore + reward) - await snapshotGasCost(receipt) - }) - - it('updates exit queue', async () => { - const vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const tx = await vault - .connect(holder) - .deposit(holder.address, ZERO_ADDRESS, { value: holderAssets }) - const holderShares = await extractDepositShares(tx) - await vault.connect(holder).enterExitQueue(holderShares, holder.address) - - const totalSharesBefore = await vault.totalShares() - const totalAssetsBefore = await vault.totalAssets() - - const rewardValidators = ethers.parseEther('0.5') - const unlockedMevReward = ethers.parseEther('0.5') - const reward = rewardValidators + unlockedMevReward - await setBalance(await sharedMevEscrow.getAddress(), unlockedMevReward) - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const tree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(tree, vaultReward) - - const receipt = await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - const operatorShares = await vault.getShares(await admin.getAddress()) - expect(await ethers.provider.getBalance(await sharedMevEscrow.getAddress())).to.be.eq(0) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq( - unlockedMevReward + holderAssets + SECURITY_DEPOSIT - ) - await expect(receipt) - .emit(keeper, 'Harvested') - .withArgs(await vault.getAddress(), tree.root, reward, unlockedMevReward) - await expect(receipt) - .emit(sharedMevEscrow, 'Harvested') - .withArgs(await vault.getAddress(), unlockedMevReward) - await expect(receipt).emit(vault, 'CheckpointCreated') - - let totalSharesAfter = totalSharesBefore + operatorShares - let totalAssetsAfter = totalAssetsBefore + reward - - const unclaimedAssets = holderAssets + unlockedMevReward + SECURITY_DEPOSIT - const burnedShares = (unclaimedAssets * totalSharesAfter) / totalAssetsAfter - - totalSharesAfter = totalSharesAfter - burnedShares - totalAssetsAfter = totalAssetsAfter - unclaimedAssets - - expect(await vault.totalShares()).to.be.eq(totalSharesAfter) - expect(await vault.totalAssets()).to.be.eq(totalAssetsAfter) - await snapshotGasCost(receipt) - }) -}) diff --git a/test/EthVault.token.spec.ts b/test/EthVault.token.spec.ts deleted file mode 100644 index e7b18971..00000000 --- a/test/EthVault.token.spec.ts +++ /dev/null @@ -1,470 +0,0 @@ -import { ethers, network } from 'hardhat' -import { Wallet } from 'ethers' -import EthereumWallet from 'ethereumjs-wallet' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthErc20Vault } from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { expect } from './shared/expect' -import { - EIP712Domain, - MAX_UINT256, - PANIC_CODES, - PermitSig, - SECURITY_DEPOSIT, - ZERO_ADDRESS, -} from './shared/constants' -import { domainSeparator, getLatestBlockTimestamp, getSignatureFromTypedData } from './shared/utils' -import snapshotGasCost from './shared/snapshotGasCost' -import { ethVaultFixture } from './shared/fixtures' - -describe('EthVault - token', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const name = 'SW ETH Vault' - const symbol = 'SW-ETH-1' - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const initialSupply = 1000n - - let vault: EthErc20Vault - let admin: Wallet, initialHolder: Wallet, spender: Wallet, recipient: Wallet - - let createVault: ThenArg>['createEthErc20Vault'] - - before('create fixture loader', async () => { - ;[admin, initialHolder, spender, recipient] = (await (ethers as any).getSigners()).slice(1, 5) - }) - - beforeEach('deploy fixture', async () => { - ;({ createEthErc20Vault: createVault } = await loadFixture(ethVaultFixture)) - vault = await createVault( - admin, - { - capacity, - feePercent, - name, - symbol, - metadataIpfsHash, - }, - false, - true - ) - await vault - .connect(initialHolder) - .deposit(initialHolder.address, ZERO_ADDRESS, { value: initialSupply }) - }) - - it('has a name', async () => { - expect(await vault.name()).to.eq(name) - }) - - it('has a symbol', async () => { - expect(await vault.symbol()).to.eq(symbol) - }) - - it('has 18 decimals', async () => { - expect(await vault.decimals()).to.eq(18) - }) - - it('fails to deploy with invalid name length', async () => { - await expect( - createVault( - admin, - { - capacity, - feePercent, - name: 'a'.repeat(31), - symbol, - metadataIpfsHash, - }, - false, - true - ) - ).to.be.revertedWithCustomError(vault, 'InvalidTokenMeta') - }) - - it('fails to deploy with zero capacity', async () => { - await expect( - createVault( - admin, - { - capacity: 0n, - feePercent, - name, - symbol, - metadataIpfsHash, - }, - false, - true - ) - ).to.be.revertedWithCustomError(vault, 'InvalidCapacity') - }) - - it('fails to deploy with capacity less than validator deposit amount', async () => { - await expect( - createVault( - admin, - { - capacity: ethers.parseEther('31'), - feePercent, - name, - symbol, - metadataIpfsHash, - }, - false, - true - ) - ).to.be.revertedWithCustomError(vault, 'InvalidCapacity') - }) - - it('fails to deploy with invalid symbol length', async () => { - await expect( - createVault( - admin, - { - capacity, - feePercent, - name, - symbol: 'a'.repeat(21), - metadataIpfsHash, - }, - false, - true - ) - ).to.be.revertedWithCustomError(vault, 'InvalidTokenMeta') - }) - - describe('total supply', () => { - it('returns the total amount of tokens', async () => { - expect(await vault.totalSupply()).to.eq(SECURITY_DEPOSIT + initialSupply) - }) - }) - - describe('balanceOf', () => { - describe('when the requested account has no tokens', () => { - it('returns zero', async () => { - expect(await vault.balanceOf(spender.address)).to.eq(0) - }) - }) - - describe('when the requested account has some tokens', () => { - it('returns the total amount of tokens', async () => { - expect(await vault.balanceOf(initialHolder.address)).to.eq(initialSupply) - }) - }) - }) - - describe('transfer', () => { - const balance = initialSupply - - it('reverts when the sender does not have enough balance', async () => { - const amount = balance + 1n - await expect( - vault.connect(initialHolder).transfer(recipient.address, amount) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('reverts with zero address recipient', async () => { - await expect( - vault.connect(initialHolder).transfer(ZERO_ADDRESS, balance) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - describe('when the sender transfers all balance', () => { - const amount = initialSupply - - it('transfers the requested amount', async () => { - const receipt = await vault.connect(initialHolder).transfer(recipient.address, amount) - expect(await vault.balanceOf(initialHolder.address)).to.eq(0) - expect(await vault.balanceOf(recipient.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - - it('emits a transfer event', async () => { - await expect(vault.connect(initialHolder).transfer(recipient.address, amount)) - .to.emit(vault, 'Transfer') - .withArgs(initialHolder.address, recipient.address, amount) - }) - }) - - describe('when the sender transfers zero tokens', () => { - const amount = 0 - const balance = initialSupply - - it('transfers the requested amount', async () => { - const receipt = await vault.connect(initialHolder).transfer(recipient.address, amount) - expect(await vault.balanceOf(initialHolder.address)).to.eq(balance) - expect(await vault.balanceOf(recipient.address)).to.eq(0) - await snapshotGasCost(receipt) - }) - - it('emits a transfer event', async () => { - await expect(vault.connect(initialHolder).transfer(recipient.address, amount)) - .to.emit(vault, 'Transfer') - .withArgs(initialHolder.address, recipient.address, amount) - }) - }) - }) - - describe('transfer from', () => { - describe('when the spender has enough allowance', () => { - beforeEach(async () => { - await vault.connect(initialHolder).approve(spender.address, initialSupply) - }) - - describe('when the token owner has enough balance', () => { - const amount = initialSupply - - it('transfers the requested amount', async () => { - const receipt = await vault - .connect(spender) - .transferFrom(initialHolder.address, spender.address, amount) - expect(await vault.balanceOf(initialHolder.address)).to.eq(0) - expect(await vault.balanceOf(spender.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - - it('decreases the spender allowance', async () => { - await vault.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - expect(await vault.allowance(initialHolder.address, spender.address)).to.eq(0) - }) - - it('emits a transfer event', async () => { - await expect( - vault.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ) - .emit(vault, 'Transfer') - .withArgs(initialHolder.address, spender.address, amount) - }) - }) - - describe('when the token owner does not have enough balance', () => { - const amount = initialSupply - - beforeEach('reducing balance', async () => { - await vault.connect(initialHolder).transfer(spender.address, 1) - }) - - it('reverts', async () => { - await expect( - vault.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - }) - }) - - describe('when the spender does not have enough allowance', () => { - const allowance = initialSupply - 1n - - beforeEach(async () => { - await vault.connect(initialHolder).approve(spender.address, allowance) - }) - - describe('when the token owner has enough balance', () => { - const amount = initialSupply - - it('reverts', async () => { - await expect( - vault.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - }) - - describe('when the token owner does not have enough balance', () => { - const amount = allowance - - beforeEach('reducing balance', async () => { - await vault.connect(initialHolder).transfer(spender.address, 2) - }) - - it('reverts', async () => { - await expect( - vault.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - }) - }) - - describe('when the spender has unlimited allowance', () => { - beforeEach(async () => { - await vault.connect(initialHolder).approve(spender.address, MAX_UINT256) - }) - - it('does not decrease the spender allowance', async () => { - const receipt = await vault - .connect(spender) - .transferFrom(initialHolder.address, spender.address, 1) - expect(await vault.allowance(initialHolder.address, spender.address)).to.eq(MAX_UINT256) - await snapshotGasCost(receipt) - }) - }) - }) - - describe('approve', () => { - it('fails to approve zero address', async () => { - const amount = ethers.parseEther('1') - await expect( - vault.connect(initialHolder).approve(ZERO_ADDRESS, amount) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - describe('when the sender has enough balance', () => { - const amount = initialSupply - - it('emits an approval event', async () => { - await expect(vault.connect(initialHolder).approve(spender.address, amount)) - .emit(vault, 'Approval') - .withArgs(initialHolder.address, spender.address, amount) - }) - - describe('when there was no approved amount before', () => { - it('approves the requested amount', async () => { - const receipt = await vault.connect(initialHolder).approve(spender.address, amount) - expect(await vault.allowance(initialHolder.address, spender.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - }) - - describe('when the spender had an approved amount', () => { - beforeEach(async () => { - await vault.connect(initialHolder).approve(spender.address, 1) - }) - - it('approves the requested amount and replaces the previous one', async () => { - const receipt = await vault.connect(initialHolder).approve(spender.address, amount) - expect(await vault.allowance(initialHolder.address, spender.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - }) - }) - - describe('when the sender does not have enough balance', () => { - const amount = initialSupply + 1n - - it('emits an approval event', async () => { - await expect(vault.connect(initialHolder).approve(spender.address, amount)) - .emit(vault, 'Approval') - .withArgs(initialHolder.address, spender.address, amount) - }) - - describe('when there was no approved amount before', () => { - it('approves the requested amount', async () => { - await vault.connect(initialHolder).approve(spender.address, amount) - expect(await vault.allowance(initialHolder.address, spender.address)).to.eq(amount) - }) - }) - - describe('when the spender had an approved amount', () => { - beforeEach(async () => { - await vault.connect(initialHolder).approve(spender.address, 1) - }) - - it('approves the requested amount and replaces the previous one', async () => { - await vault.connect(initialHolder).approve(spender.address, amount) - - expect(await vault.allowance(initialHolder.address, spender.address)).to.eq(amount) - }) - }) - }) - }) - - describe('permit', () => { - const value = 42 - const nonce = 0 - const maxDeadline = MAX_UINT256.toString() - const chainId = network.config.chainId - - const owner = new EthereumWallet( - Buffer.from( - ethers.getBytes('0x35a1c4d02b06d93778758410e5c09e010760268cf98b1af33c2d0646f27a8b70') - ) - ) - const ownerAddress = owner.getChecksumAddressString() - const ownerPrivateKey = owner.getPrivateKey() - - const buildData = async (deadline = maxDeadline, spender) => ({ - primaryType: 'Permit', - types: { EIP712Domain, Permit: PermitSig }, - domain: { - name, - version: '1', - chainId, - verifyingContract: await vault.getAddress(), - }, - message: { owner: ownerAddress, spender, value, nonce, deadline }, - }) - - it('initial nonce is 0', async () => { - expect(await vault.nonces(ownerAddress)).to.eq(0) - }) - - it('domain separator', async () => { - expect(await vault.DOMAIN_SEPARATOR()).to.equal( - await domainSeparator(name, '1', chainId, await vault.getAddress()) - ) - }) - - it('accepts owner signature', async () => { - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(maxDeadline, spender.address) - ) - - const receipt = await vault.permit(ownerAddress, spender.address, value, maxDeadline, v, r, s) - await snapshotGasCost(receipt) - - await expect(receipt) - .to.emit(vault, 'Approval') - .withArgs(ownerAddress, spender.address, value) - - expect(await vault.nonces(ownerAddress)).to.eq('1') - expect(await vault.allowance(ownerAddress, spender.address)).to.eq(value) - }) - - it('rejects reused signature', async () => { - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(maxDeadline, spender.address) - ) - - await vault.permit(ownerAddress, spender.address, value, maxDeadline, v, r, s) - - await expect( - vault.permit(initialHolder.address, spender.address, value, maxDeadline, v, r, s) - ).to.be.revertedWithCustomError(vault, 'PermitInvalidSigner') - }) - - it('rejects other signature', async () => { - const otherWallet = EthereumWallet.generate() - const data = await buildData(maxDeadline, spender.address) - const { v, r, s } = getSignatureFromTypedData(otherWallet.getPrivateKey(), data) - - await expect( - vault.permit(ownerAddress, spender.address, value, maxDeadline, v, r, s) - ).to.be.revertedWithCustomError(vault, 'PermitInvalidSigner') - }) - - it('rejects expired permit', async () => { - const deadline = ((await getLatestBlockTimestamp()) - 500).toString() - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(deadline, spender.address) - ) - - await expect( - vault.permit(ownerAddress, spender.address, value, deadline, v, r, s) - ).to.be.revertedWithCustomError(vault, 'DeadlineExpired') - }) - - it('rejects zero address', async () => { - const deadline = ((await getLatestBlockTimestamp()) - 500).toString() - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(deadline, ZERO_ADDRESS) - ) - - await expect( - vault.permit(ownerAddress, ZERO_ADDRESS, value, deadline, v, r, s) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - }) -}) diff --git a/test/EthVault.upgrade.spec.ts b/test/EthVault.upgrade.spec.ts deleted file mode 100644 index 921c2e0b..00000000 --- a/test/EthVault.upgrade.spec.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, parseEther, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - DepositDataRegistry, - EthVault, - EthVault__factory, - EthVaultFactory, - EthVaultV5Mock, - EthVaultV5Mock__factory, - Keeper, - OsTokenConfig, - OsTokenVaultController, - OsTokenVaultEscrow, - SharedMevEscrow, - VaultsRegistry, -} from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { - deployEthVaultImplementation, - deployEthVaultV3, - encodeEthErc20VaultInitParams, - encodeEthVaultInitParams, - ethVaultFixture, -} from './shared/fixtures' -import { expect } from './shared/expect' -import { - EXITING_ASSETS_MIN_DELAY, - MAX_UINT256, - SECURITY_DEPOSIT, - ZERO_ADDRESS, -} from './shared/constants' -import { collateralizeEthVault } from './shared/rewards' -import { - getEthBlocklistErc20VaultV3Factory, - getEthBlocklistVaultV3Factory, - getEthErc20VaultV3Factory, - getEthGenesisVaultV3Factory, - getEthPrivErc20VaultV3Factory, - getEthPrivVaultV3Factory, - getEthVaultV3Factory, -} from './shared/contracts' -import { ThenArg } from '../helpers/types' - -describe('EthVault - upgrade', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7r' - let admin: Signer, dao: Wallet, other: Wallet - let vault: EthVault, - vaultsRegistry: VaultsRegistry, - keeper: Keeper, - validatorsRegistry: Contract, - updatedVault: EthVaultV5Mock, - sharedMevEscrow: SharedMevEscrow, - osTokenConfig: OsTokenConfig, - osTokenVaultController: OsTokenVaultController, - osTokenVaultEscrow: OsTokenVaultEscrow, - depositDataRegistry: DepositDataRegistry, - ethVaultFactory: EthVaultFactory, - ethPrivVaultFactory: EthVaultFactory, - ethBlocklistVaultFactory: EthVaultFactory, - ethErc20VaultFactory: EthVaultFactory, - ethPrivErc20VaultFactory: EthVaultFactory, - ethBlocklistErc20VaultFactory: EthVaultFactory - let currImpl: string - let mockImpl: string - let callData: string - let fixture: any - - let createGenesisVault: ThenArg>['createEthGenesisVault'] - - beforeEach('deploy fixture', async () => { - ;[dao, admin, other] = await (ethers as any).getSigners() - fixture = await loadFixture(ethVaultFixture) - vaultsRegistry = fixture.vaultsRegistry - validatorsRegistry = fixture.validatorsRegistry - keeper = fixture.keeper - sharedMevEscrow = fixture.sharedMevEscrow - osTokenVaultController = fixture.osTokenVaultController - depositDataRegistry = fixture.depositDataRegistry - ethVaultFactory = fixture.ethVaultFactory - ethPrivVaultFactory = fixture.ethPrivVaultFactory - ethBlocklistVaultFactory = fixture.ethBlocklistVaultFactory - ethErc20VaultFactory = fixture.ethErc20VaultFactory - ethPrivErc20VaultFactory = fixture.ethPrivErc20VaultFactory - ethBlocklistErc20VaultFactory = fixture.ethBlocklistErc20VaultFactory - createGenesisVault = fixture.createEthGenesisVault - osTokenConfig = fixture.osTokenConfig - osTokenVaultEscrow = fixture.osTokenVaultEscrow - vault = await fixture.createEthVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - mockImpl = await deployEthVaultImplementation( - 'EthVaultV5Mock', - fixture.keeper, - fixture.vaultsRegistry, - await fixture.validatorsRegistry.getAddress(), - fixture.osTokenVaultController, - fixture.osTokenConfig, - fixture.osTokenVaultEscrow, - fixture.sharedMevEscrow, - fixture.depositDataRegistry, - EXITING_ASSETS_MIN_DELAY - ) - currImpl = await vault.implementation() - callData = ethers.AbiCoder.defaultAbiCoder().encode(['uint128'], [100]) - await vaultsRegistry.connect(dao).addVaultImpl(mockImpl) - updatedVault = EthVaultV5Mock__factory.connect( - await vault.getAddress(), - await ethers.provider.getSigner() - ) - }) - - it('fails from not admin', async () => { - await expect( - vault.connect(other).upgradeToAndCall(mockImpl, callData) - ).to.revertedWithCustomError(vault, 'AccessDenied') - expect(await vault.version()).to.be.eq(4) - }) - - it('fails with zero new implementation address', async () => { - await expect( - vault.connect(admin).upgradeToAndCall(ZERO_ADDRESS, callData) - ).to.revertedWithCustomError(vault, 'UpgradeFailed') - expect(await vault.version()).to.be.eq(4) - }) - - it('fails for the same implementation', async () => { - await expect( - vault.connect(admin).upgradeToAndCall(currImpl, callData) - ).to.revertedWithCustomError(vault, 'UpgradeFailed') - expect(await vault.version()).to.be.eq(4) - }) - - it('fails for not approved implementation', async () => { - await vaultsRegistry.connect(dao).removeVaultImpl(mockImpl) - await expect( - vault.connect(admin).upgradeToAndCall(mockImpl, callData) - ).to.revertedWithCustomError(vault, 'UpgradeFailed') - expect(await vault.version()).to.be.eq(4) - }) - - it('fails for implementation with different vault id', async () => { - const newImpl = await deployEthVaultImplementation( - 'EthPrivVaultV4Mock', - fixture.keeper, - fixture.vaultsRegistry, - await fixture.validatorsRegistry.getAddress(), - fixture.osTokenVaultController, - fixture.osTokenConfig, - fixture.osTokenVaultEscrow, - fixture.sharedMevEscrow, - fixture.depositDataRegistry, - EXITING_ASSETS_MIN_DELAY - ) - callData = ethers.AbiCoder.defaultAbiCoder().encode(['uint128'], [100]) - await vaultsRegistry.connect(dao).addVaultImpl(newImpl) - await expect( - vault.connect(admin).upgradeToAndCall(newImpl, callData) - ).to.revertedWithCustomError(vault, 'UpgradeFailed') - expect(await vault.version()).to.be.eq(4) - }) - - it('fails for implementation with too high version', async () => { - const newImpl = await deployEthVaultImplementation( - 'EthVaultV6Mock', - fixture.keeper, - fixture.vaultsRegistry, - await fixture.validatorsRegistry.getAddress(), - fixture.osTokenVaultController, - fixture.osTokenConfig, - fixture.osTokenVaultEscrow, - fixture.sharedMevEscrow, - fixture.depositDataRegistry, - EXITING_ASSETS_MIN_DELAY - ) - callData = ethers.AbiCoder.defaultAbiCoder().encode(['uint128'], [100]) - await vaultsRegistry.connect(dao).addVaultImpl(newImpl) - await expect( - vault.connect(admin).upgradeToAndCall(newImpl, callData) - ).to.revertedWithCustomError(vault, 'UpgradeFailed') - expect(await vault.version()).to.be.eq(4) - }) - - it('fails with invalid call data', async () => { - await expect( - vault - .connect(admin) - .upgradeToAndCall( - mockImpl, - ethers.AbiCoder.defaultAbiCoder().encode(['uint256'], [MAX_UINT256]) - ) - ).to.revertedWithCustomError(vault, 'FailedInnerCall') - expect(await vault.version()).to.be.eq(4) - }) - - it('works with valid call data', async () => { - const receipt = await vault.connect(admin).upgradeToAndCall(mockImpl, callData) - expect(await vault.version()).to.be.eq(5) - expect(await vault.implementation()).to.be.eq(mockImpl) - expect(await updatedVault.newVar()).to.be.eq(100) - expect(await updatedVault.somethingNew()).to.be.eq(true) - await expect( - vault.connect(admin).upgradeToAndCall(mockImpl, callData) - ).to.revertedWithCustomError(vault, 'UpgradeFailed') - await expect(updatedVault.connect(admin).initialize(callData)).to.revertedWithCustomError( - updatedVault, - 'InvalidInitialization' - ) - await snapshotGasCost(receipt) - }) - - it('does not modify the state variables', async () => { - const vaults: Contract[] = [] - for (const factory of [ - await getEthVaultV3Factory(), - await getEthPrivVaultV3Factory(), - await getEthBlocklistVaultV3Factory(), - ]) { - const vault = await deployEthVaultV3( - factory, - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - sharedMevEscrow, - depositDataRegistry, - osTokenVaultEscrow, - encodeEthVaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - }) - ) - vaults.push(vault) - } - for (const factory of [ - await getEthErc20VaultV3Factory(), - await getEthPrivErc20VaultV3Factory(), - await getEthBlocklistErc20VaultV3Factory(), - ]) { - const vault = await deployEthVaultV3( - factory, - admin, - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - sharedMevEscrow, - depositDataRegistry, - osTokenVaultEscrow, - encodeEthErc20VaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - name: 'Vault', - symbol: 'VLT', - }) - ) - vaults.push(vault) - } - - const checkVault = async (vault: Contract, newImpl: string) => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: parseEther('3') }) - await vault.connect(other).enterExitQueue(parseEther('1'), other.address) - await vault.connect(other).mintOsToken(other.address, parseEther('1'), ZERO_ADDRESS) - - const userShares = await vault.getShares(other.address) - const userAssets = await vault.convertToAssets(userShares) - const osTokenPosition = await vault.osTokenPositions(other.address) - const mevEscrow = await vault.mevEscrow() - const totalAssets = await vault.totalAssets() - const totalShares = await vault.totalShares() - const vaultAddress = await vault.getAddress() - expect(await vault.version()).to.be.eq(3) - - const receipt = await vault.connect(admin).upgradeToAndCall(newImpl, '0x') - const vaultV4 = EthVault__factory.connect(vaultAddress, admin) - expect(await vaultV4.version()).to.be.eq(4) - expect(await vaultV4.implementation()).to.be.eq(newImpl) - expect(await vaultV4.getShares(other.address)).to.be.eq(userShares) - expect(await vaultV4.convertToAssets(userShares)).to.be.deep.eq(userAssets) - expect(await vaultV4.osTokenPositions(other.address)).to.be.above(osTokenPosition) - expect(await vaultV4.validatorsManager()).to.be.eq(await depositDataRegistry.getAddress()) - expect(await vaultV4.mevEscrow()).to.be.eq(mevEscrow) - expect(await vaultV4.totalAssets()).to.be.eq(totalAssets) - expect(await vaultV4.totalShares()).to.be.eq(totalShares) - await snapshotGasCost(receipt) - } - await checkVault(vaults[0], await ethVaultFactory.implementation()) - await vaults[1].connect(admin).updateWhitelist(other.address, true) - await checkVault(vaults[1], await ethPrivVaultFactory.implementation()) - await checkVault(vaults[2], await ethBlocklistVaultFactory.implementation()) - - await checkVault(vaults[3], await ethErc20VaultFactory.implementation()) - await vaults[4].connect(admin).updateWhitelist(other.address, true) - await checkVault(vaults[4], await ethPrivErc20VaultFactory.implementation()) - await checkVault(vaults[5], await ethBlocklistErc20VaultFactory.implementation()) - - const [v4GenesisVault, rewardEthToken, poolEscrow] = await createGenesisVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - const factory = await getEthGenesisVaultV3Factory() - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await osTokenVaultEscrow.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - await poolEscrow.getAddress(), - await rewardEthToken.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const contract = await factory.deploy(...constructorArgs) - const genesisImpl = await contract.getAddress() - const genesisImplV4 = await v4GenesisVault.implementation() - await vaultsRegistry.addVaultImpl(genesisImpl) - - const proxyFactory = await ethers.getContractFactory('ERC1967Proxy') - const proxy = await proxyFactory.deploy(genesisImpl, '0x') - const proxyAddress = await proxy.getAddress() - const genesisVault = new Contract(proxyAddress, contract.interface, admin) - await rewardEthToken.connect(dao).setVault(proxyAddress) - await poolEscrow.connect(dao).commitOwnershipTransfer(proxyAddress) - await genesisVault.initialize( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [await admin.getAddress(), [capacity, feePercent, metadataIpfsHash]] - ), - { value: SECURITY_DEPOSIT } - ) - await genesisVault.acceptPoolEscrowOwnership() - await vaultsRegistry.addVault(proxyAddress) - await checkVault(genesisVault, genesisImplV4) - }) -}) diff --git a/test/EthVault.whitelist.spec.ts b/test/EthVault.whitelist.spec.ts deleted file mode 100644 index 4cda9105..00000000 --- a/test/EthVault.whitelist.spec.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthPrivVault, Keeper } from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { createDepositorMock, ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { ZERO_ADDRESS } from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import { extractDepositShares } from './shared/utils' -import { MAINNET_FORK } from '../helpers/constants' - -describe('EthVault - whitelist', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = ZERO_ADDRESS - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - let sender: Wallet, whitelister: Wallet, admin: Signer, other: Wallet - let vault: EthPrivVault, - keeper: Keeper, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - - let createPrivateVault: ThenArg>['createEthPrivVault'] - - before('create fixture loader', async () => { - ;[sender, whitelister, admin, other] = (await (ethers as any).getSigners()).slice(1, 5) - }) - - beforeEach('deploy fixtures', async () => { - ;({ - createEthPrivVault: createPrivateVault, - keeper, - validatorsRegistry, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createPrivateVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - }) - - describe('set whitelister', () => { - it('cannot be called by not admin', async () => { - await expect( - vault.connect(other).setWhitelister(whitelister.address) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('admin can update whitelister', async () => { - const tx = await vault.connect(admin).setWhitelister(whitelister.address) - await expect(tx) - .to.emit(vault, 'WhitelisterUpdated') - .withArgs(await admin.getAddress(), whitelister.address) - expect(await vault.whitelister()).to.be.eq(whitelister.address) - await snapshotGasCost(tx) - }) - }) - - describe('whitelist', () => { - beforeEach(async () => { - await vault.connect(admin).setWhitelister(whitelister.address) - }) - - it('cannot be updated by not whitelister', async () => { - await expect( - vault.connect(other).updateWhitelist(sender.address, true) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot be updated twice', async () => { - await vault.connect(whitelister).updateWhitelist(sender.address, true) - await expect(vault.connect(whitelister).updateWhitelist(sender.address, true)).to.not.emit( - vault, - 'WhitelistUpdated' - ) - }) - - it('can be updated by whitelister', async () => { - // add to whitelist - let tx = await vault.connect(whitelister).updateWhitelist(sender.address, true) - await expect(tx) - .to.emit(vault, 'WhitelistUpdated') - .withArgs(whitelister.address, sender.address, true) - expect(await vault.whitelistedAccounts(sender.address)).to.be.eq(true) - await snapshotGasCost(tx) - - // remove from whitelist - tx = await vault.connect(whitelister).updateWhitelist(sender.address, false) - await expect(tx) - .to.emit(vault, 'WhitelistUpdated') - .withArgs(whitelister.address, sender.address, false) - expect(await vault.whitelistedAccounts(sender.address)).to.be.eq(false) - await snapshotGasCost(tx) - }) - }) - - describe('deposit', () => { - const amount = ethers.parseEther('1') - - beforeEach(async () => { - await vault.connect(admin).updateWhitelist(await admin.getAddress(), true) - await vault.connect(admin).updateWhitelist(sender.address, true) - }) - - it('cannot be called by not whitelisted sender', async () => { - await expect( - vault.connect(other).deposit(other.address, referrer, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot update state and call', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const vaultReward = getHarvestParams(await vault.getAddress(), ethers.parseEther('1'), 0n) - const tree = await updateRewards(keeper, [vaultReward]) - - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await expect( - vault - .connect(other) - .updateStateAndDeposit(other.address, referrer, harvestParams, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('cannot set receiver to not whitelisted user', async () => { - await expect( - vault.connect(other).deposit(other.address, referrer, { value: amount }) - ).to.revertedWithCustomError(vault, 'AccessDenied') - }) - - it('can be called by whitelisted user', async () => { - const receipt = await vault - .connect(sender) - .deposit(sender.address, referrer, { value: amount }) - const shares = await extractDepositShares(receipt) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(sender.address, sender.address, amount, shares, referrer) - await snapshotGasCost(receipt) - }) - - it('deposit through receive fallback cannot be called by not whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const amount = ethers.parseEther('100') - const expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - await expect( - depositorMock.connect(sender).depositToVault({ value: amount }) - ).to.revertedWithCustomError(depositorMock, 'DepositFailed') - }) - - it('deposit through receive fallback can be called by whitelisted sender', async () => { - const depositorMock = await createDepositorMock(vault) - const depositorMockAddress = await depositorMock.getAddress() - await vault.connect(admin).updateWhitelist(depositorMockAddress, true) - - const amount = ethers.parseEther('100') - let expectedShares = await vault.convertToShares(amount) - expect(await vault.convertToShares(amount)).to.eq(expectedShares) - const receipt = await depositorMock.connect(sender).depositToVault({ value: amount }) - if (MAINNET_FORK.enabled) { - expectedShares += 1n // rounding error - } - expect(await vault.getShares(depositorMockAddress)).to.eq(expectedShares) - - await expect(receipt) - .to.emit(vault, 'Deposited') - .withArgs(depositorMockAddress, depositorMockAddress, amount, expectedShares, ZERO_ADDRESS) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/EthVault.withdraw.spec.ts b/test/EthVault.withdraw.spec.ts deleted file mode 100644 index d3ee3b53..00000000 --- a/test/EthVault.withdraw.spec.ts +++ /dev/null @@ -1,1013 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - EthVaultMock, - IKeeperRewards, - Keeper, - SharedMevEscrow, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import snapshotGasCost from './shared/snapshotGasCost' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { - EXITING_ASSETS_MIN_DELAY, - MAX_UINT128, - ONE_DAY, - PANIC_CODES, - SECURITY_DEPOSIT, - ZERO_ADDRESS, -} from './shared/constants' -import { - extractDepositShares, - extractExitPositionTicket, - getBlockTimestamp, - getGasUsed, - increaseTime, - setBalance, -} from './shared/utils' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import { registerEthValidator } from './shared/validators' - -const validatorDeposit = ethers.parseEther('32') - -describe('EthVault - withdraw', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const referrer = '0x' + '1'.repeat(40) - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const holderAssets = ethers.parseEther('1') - let holderShares: bigint - - let holder: Wallet, receiver: Wallet, admin: Signer, other: Wallet - let vault: EthVault, - keeper: Keeper, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - validatorsRegistry: Contract - - let createVault: ThenArg>['createEthVault'] - let createVaultMock: ThenArg>['createEthVaultMock'] - - beforeEach('deploy fixture', async () => { - ;[holder, receiver, admin, other] = (await (ethers as any).getSigners()).slice(1, 5) - ;({ - createEthVault: createVault, - createEthVaultMock: createVaultMock, - keeper, - validatorsRegistry, - sharedMevEscrow, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - const tx = await vault - .connect(holder) - .deposit(holder.address, referrer, { value: holderAssets }) - holderShares = await extractDepositShares(tx) - }) - - describe('redeem', () => { - it('fails with not enough balance', async () => { - await setBalance(await vault.getAddress(), 0n) - await expect( - vault.connect(holder).enterExitQueue(holderShares, receiver.address) - ).to.be.revertedWithCustomError(vault, 'AddressInsufficientBalance') - }) - - it('fails for sender other than owner without approval', async () => { - await expect( - vault.connect(other).enterExitQueue(holderShares, receiver.address) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('fails for shares larger than balance', async () => { - const newBalance = holderShares + 1n - await setBalance(await vault.getAddress(), newBalance) - await expect( - vault.connect(holder).enterExitQueue(newBalance, receiver.address) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('fails for zero address receiver', async () => { - const newBalance = holderShares + 1n - await setBalance(await vault.getAddress(), newBalance) - await expect( - vault.connect(holder).enterExitQueue(newBalance, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('fails for zero shares', async () => { - await expect( - vault.connect(holder).enterExitQueue(0, holder.address) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - }) - - it('does not overflow', async () => { - const vault: EthVaultMock = await createVaultMock(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - await vault.resetSecurityDeposit() - await vault.connect(holder).deposit(holder.address, referrer, { value: holderAssets }) - - const receiverBalanceBefore = await ethers.provider.getBalance(receiver.address) - - await setBalance(await vault.getAddress(), MAX_UINT128) - await vault._setTotalAssets(MAX_UINT128) - - await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - expect(await vault.totalAssets()).to.be.eq(0) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq( - receiverBalanceBefore + MAX_UINT128 - ) - }) - - it('redeem transfers assets to receiver', async () => { - const receiverBalanceBefore = await ethers.provider.getBalance(receiver.address) - const receipt = await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - await expect(receipt) - .to.emit(vault, 'Redeemed') - .withArgs(holder.address, receiver.address, holderAssets, holderShares) - - expect(await vault.totalAssets()).to.be.eq(SECURITY_DEPOSIT) - expect(await vault.totalShares()).to.be.eq(SECURITY_DEPOSIT) - expect(await vault.getShares(holder.address)).to.be.eq(0) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(SECURITY_DEPOSIT) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq( - receiverBalanceBefore + holderAssets - ) - - await snapshotGasCost(receipt) - }) - }) - - describe('enter exit queue', () => { - beforeEach(async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - }) - - it('fails with zero shares', async () => { - await expect( - vault.connect(holder).enterExitQueue(0, receiver.address) - ).to.be.revertedWithCustomError(vault, 'InvalidShares') - }) - - it('fails for zero address receiver', async () => { - await expect( - vault.connect(holder).enterExitQueue(holderShares, ZERO_ADDRESS) - ).to.be.revertedWithCustomError(vault, 'ZeroAddress') - }) - - it('fails for sender other than owner without approval', async () => { - await expect( - vault.connect(other).enterExitQueue(holderShares, receiver.address) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('fails for shares larger than balance', async () => { - await expect( - vault.connect(holder).enterExitQueue(holderShares + 1n, receiver.address) - ).to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW) - }) - - it('locks shares for the time of exit', async () => { - expect(await vault.queuedShares()).to.be.eq(0) - expect(await vault.getShares(holder.address)).to.be.eq(holderShares) - expect(await vault.getShares(await vault.getAddress())).to.be.eq(SECURITY_DEPOSIT) - - const receipt = await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - await expect(receipt) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(holder.address, receiver.address, validatorDeposit, holderShares) - - expect(await vault.queuedShares()).to.be.eq(holderShares) - expect(await vault.getShares(holder.address)).to.be.eq(0) - - await snapshotGasCost(receipt) - }) - }) - - describe('update exit queue', () => { - let harvestParams: IKeeperRewards.HarvestParamsStruct - - beforeEach(async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - harvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - }) - - it('skips with 0 queued shares', async () => { - await expect(vault.updateState(harvestParams)).to.emit(vault, 'CheckpointCreated') - expect(await vault.queuedShares()).to.be.eq(0) - await increaseTime(ONE_DAY) - const tree = await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 0n, unlockedMevReward: 0n }, - ]) - const newHarvestParams = { - rewardsRoot: tree.root, - reward: 0n, - unlockedMevReward: 0n, - proof: getRewardsRootProof(tree, { - vault: await vault.getAddress(), - reward: 0n, - unlockedMevReward: 0n, - }), - } - await expect(vault.updateState(newHarvestParams)).to.not.emit(vault, 'CheckpointCreated') - }) - - it('skips with 0 burned assets', async () => { - const totalAssets = await vault.totalAssets() - const penalty = totalAssets - totalAssets * 2n - const vaultReward = getHarvestParams(await vault.getAddress(), penalty, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - await expect( - vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - }) - ).to.not.emit(vault, 'CheckpointCreated') - }) - - it('for not all the queued shares', async () => { - const halfHolderAssets = holderAssets / 2n - const halfHolderShares = holderShares / 2n - await setBalance(await vault.getAddress(), halfHolderAssets) - - const receipt = await vault.updateState(harvestParams) - await expect(receipt) - .to.emit(vault, 'CheckpointCreated') - .withArgs(halfHolderShares, halfHolderAssets) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(halfHolderAssets) - expect(await vault.queuedShares()).to.be.eq(halfHolderShares) - expect(await vault.getExitQueueIndex(validatorDeposit)).to.be.eq(1) - - await snapshotGasCost(receipt) - }) - - it('adds checkpoint', async () => { - const receipt = await vault.updateState(harvestParams) - await expect(receipt).to.emit(vault, 'CheckpointCreated').withArgs(holderShares, holderAssets) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq( - holderAssets + SECURITY_DEPOSIT - ) - expect(await vault.getExitQueueIndex(0)).to.be.eq(0) - expect(await vault.totalShares()).to.be.eq(SECURITY_DEPOSIT) - expect(await vault.totalAssets()).to.be.eq(SECURITY_DEPOSIT) - expect(await vault.queuedShares()).to.be.eq(0) - - await snapshotGasCost(receipt) - }) - }) - - it('get checkpoint index works with many checkpoints', async () => { - const vault: EthVaultMock = await createVaultMock(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - - // collateralize vault by registering validator - await vault.connect(holder).deposit(holder.address, referrer, { value: validatorDeposit }) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - const receipt = await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - const positionTicket = await extractExitPositionTicket(receipt) - - // create checkpoints every day for 10 years - for (let i = 1; i <= 3650; i++) { - await setBalance(await vault.getAddress(), BigInt(i)) - await increaseTime(ONE_DAY) - const rewardsTree = await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 0n, unlockedMevReward: 0n }, - ]) - const proof = getRewardsRootProof(rewardsTree, { - vault: await vault.getAddress(), - reward: 0n, - unlockedMevReward: 0n, - }) - await expect( - vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: 0n, - unlockedMevReward: 0n, - proof, - }) - ).to.emit(vault, 'CheckpointCreated') - } - await snapshotGasCost(await vault.getGasCostOfGetExitQueueIndex(positionTicket)) - }) - - describe('claim exited assets', () => { - let receiverBalanceBefore: bigint - let positionTicket: bigint - let timestamp: number - let harvestParams: IKeeperRewards.HarvestParamsStruct - - beforeEach(async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const response = await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - positionTicket = await extractExitPositionTicket(response) - timestamp = await getBlockTimestamp(response) - receiverBalanceBefore = await ethers.provider.getBalance(receiver.address) - - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - harvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - }) - - it('returns zero with no queued shares', async () => { - await increaseTime(EXITING_ASSETS_MIN_DELAY) - await vault.updateState(harvestParams) - const checkpointIndex = await vault.getExitQueueIndex(positionTicket) - const result = await vault.calculateExitedAssets( - other.address, - positionTicket, - timestamp, - checkpointIndex - ) - expect(result.exitedTickets).to.be.eq(0) - expect(result.leftTickets).to.be.eq(0) - expect(result.exitedAssets).to.be.eq(0) - await expect( - vault.connect(other).claimExitedAssets(positionTicket, timestamp, checkpointIndex) - ).to.revertedWithCustomError(vault, 'ExitRequestNotProcessed') - }) - - it('returns -1 for unknown checkpoint index', async () => { - expect(await vault.getExitQueueIndex(validatorDeposit)).to.be.eq(-1) - }) - - it('returns 0 with checkpoint index larger than checkpoints array', async () => { - await increaseTime(EXITING_ASSETS_MIN_DELAY) - const result = await vault.calculateExitedAssets(other.address, positionTicket, timestamp, 1) - expect(result.exitedTickets).to.be.eq(0) - expect(result.leftTickets).to.be.eq(0) - expect(result.exitedAssets).to.be.eq(0) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq(receiverBalanceBefore) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq( - holderAssets + SECURITY_DEPOSIT - ) - }) - - it('fails with invalid checkpoint index', async () => { - await vault.updateState(harvestParams) - const checkpointIndex = await vault.getExitQueueIndex(positionTicket) - - await vault.connect(holder).deposit(holder.address, referrer, { value: holderAssets * 2n }) - let response = await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - const positionTicket2 = await extractExitPositionTicket(response) - const timestamp2 = await getBlockTimestamp(response) - - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - // checkpointIndex is lower than positionTicket - await expect( - vault.connect(receiver).claimExitedAssets(positionTicket2, timestamp2, checkpointIndex) - ).to.be.revertedWithCustomError(vault, 'InvalidCheckpointIndex') - await increaseTime(ONE_DAY) - await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 0n, unlockedMevReward: 0n }, - ]) - await vault.updateState(harvestParams) - - response = await vault.connect(holder).enterExitQueue(holderShares, receiver.address) - const positionTicket3 = await extractExitPositionTicket(response) - await increaseTime(ONE_DAY) - await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 0n, unlockedMevReward: 0n }, - ]) - await vault.updateState(harvestParams) - - const checkpointIndexThree = await vault.getExitQueueIndex(positionTicket3) - // checkpointIndex is higher than positionTicket - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - await expect( - vault.connect(receiver).claimExitedAssets(positionTicket, timestamp, checkpointIndexThree) - ).to.be.revertedWithCustomError(vault, 'InvalidCheckpointIndex') - }) - - it('fails with invalid timestamp', async () => { - await vault.updateState(harvestParams) - await expect( - vault - .connect(receiver) - .claimExitedAssets( - positionTicket, - timestamp, - await vault.getExitQueueIndex(positionTicket) - ) - ).to.be.revertedWithCustomError(vault, 'ExitRequestNotProcessed') - }) - - it('for single user in single checkpoint', async () => { - await vault.updateState(harvestParams) - const checkpointIndex = await vault.getExitQueueIndex(positionTicket) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - const receipt = await vault - .connect(receiver) - .claimExitedAssets(positionTicket, timestamp, checkpointIndex) - await expect(receipt) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(receiver.address, positionTicket, 0, holderAssets) - const gasUsed = await getGasUsed(receipt) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq( - receiverBalanceBefore + holderAssets - gasUsed - ) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(SECURITY_DEPOSIT) - - await snapshotGasCost(receipt) - }) - - it('for single user in multiple checkpoints in single transaction', async () => { - const halfHolderAssets = holderAssets / 2n - const halfHolderShares = holderShares / 2n - - // create two checkpoints - await setBalance(await vault.getAddress(), halfHolderAssets) - await expect(vault.updateState(harvestParams)) - .to.emit(vault, 'CheckpointCreated') - .withArgs(halfHolderShares, halfHolderAssets) - const checkpointIndex = await vault.getExitQueueIndex(positionTicket) - - await increaseTime(ONE_DAY) - await setBalance(await vault.getAddress(), holderAssets) - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - await updateRewards(keeper, [vaultReward]) - await expect(vault.updateState(harvestParams)) - .to.emit(vault, 'CheckpointCreated') - .withArgs(halfHolderShares, halfHolderAssets) - - await increaseTime(EXITING_ASSETS_MIN_DELAY) - const receipt = await vault - .connect(receiver) - .claimExitedAssets(positionTicket, timestamp, checkpointIndex) - - await expect(receipt) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(receiver.address, positionTicket, 0, holderAssets) - - const gasUsed = await getGasUsed(receipt) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq( - receiverBalanceBefore + holderAssets - gasUsed - ) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(0) - - await snapshotGasCost(receipt) - }) - - it('for single user in multiple checkpoints in multiple transactions', async () => { - const halfHolderAssets = holderAssets / 2n - const halfHolderShares = holderShares / 2n - - // create first checkpoint - await setBalance(await vault.getAddress(), halfHolderAssets) - await expect(vault.updateState(harvestParams)) - .to.emit(vault, 'CheckpointCreated') - .withArgs(halfHolderShares, halfHolderAssets) - const checkpointIndex = await vault.getExitQueueIndex(positionTicket) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - let receipt = await vault - .connect(receiver) - .claimExitedAssets(positionTicket, timestamp, checkpointIndex) - - const newPositionTicket = validatorDeposit + halfHolderShares - await expect(receipt) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(receiver.address, positionTicket, newPositionTicket, halfHolderAssets) - - let gasUsed = await getGasUsed(receipt) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq( - receiverBalanceBefore + halfHolderAssets - gasUsed - ) - - await snapshotGasCost(receipt) - - // create second checkpoint - await increaseTime(ONE_DAY) - await setBalance(await vault.getAddress(), halfHolderAssets) - await updateRewards(keeper, [ - { vault: await vault.getAddress(), reward: 0n, unlockedMevReward: 0n }, - ]) - await expect(vault.updateState(harvestParams)) - .to.emit(vault, 'CheckpointCreated') - .withArgs(halfHolderShares, halfHolderAssets) - - const newCheckpointIndex = await vault.getExitQueueIndex(newPositionTicket) - receipt = await vault - .connect(receiver) - .claimExitedAssets(newPositionTicket, timestamp, newCheckpointIndex) - await expect(receipt) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(receiver.address, newPositionTicket, 0, halfHolderAssets) - - gasUsed += await getGasUsed(receipt) - expect(await ethers.provider.getBalance(receiver.address)).to.be.eq( - receiverBalanceBefore + holderAssets - gasUsed - ) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(0) - - await snapshotGasCost(receipt) - }) - - it('for multiple users in single checkpoint', async () => { - // harvests the previous queued position - await vault.updateState(harvestParams) - const checkpointIndex = await vault.getExitQueueIndex(positionTicket) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - await vault.connect(receiver).claimExitedAssets(positionTicket, timestamp, checkpointIndex) - - const shares = holderShares - const assets = holderAssets - const user1 = holder - const user2 = receiver - - await vault.connect(user1).deposit(user1.address, referrer, { value: assets }) - await vault.connect(user2).deposit(user2.address, referrer, { value: assets }) - - let response = await vault.connect(user1).enterExitQueue(shares, user1.address) - const user1PositionTicket = await extractExitPositionTicket(response) - const user1Timestamp = await getBlockTimestamp(response) - const user1BalanceBefore = await ethers.provider.getBalance(user1.address) - - response = await vault.connect(user2).enterExitQueue(shares, user2.address) - const user2PositionTicket = await extractExitPositionTicket(response) - const user2Timestamp = await getBlockTimestamp(response) - const user2BalanceBefore = await ethers.provider.getBalance(user2.address) - - await increaseTime(ONE_DAY) - const vaultReward = getHarvestParams(await vault.getAddress(), 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward]) - const newHarvestParams = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await expect(vault.connect(other).updateState(newHarvestParams)) - .to.emit(vault, 'CheckpointCreated') - .withArgs(shares * 2n, assets * 2n) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - - response = await vault - .connect(user2) - .claimExitedAssets( - user2PositionTicket, - user2Timestamp, - await vault.getExitQueueIndex(user2PositionTicket) - ) - await expect(response) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(user2.address, user2PositionTicket, 0, assets) - - let gasUsed = await getGasUsed(response) - expect(await ethers.provider.getBalance(user2.address)).to.be.eq( - user2BalanceBefore + assets - gasUsed - ) - - response = await vault - .connect(user1) - .claimExitedAssets( - user1PositionTicket, - user1Timestamp, - await vault.getExitQueueIndex(user1PositionTicket) - ) - await expect(response) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(user1.address, user1PositionTicket, 0, assets) - - gasUsed = await getGasUsed(response) - expect(await ethers.provider.getBalance(user1.address)).to.be.eq( - user1BalanceBefore + assets - gasUsed - ) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(SECURITY_DEPOSIT) - }) - }) - - /// Scenario inspired by solmate ERC4626 tests: - /// https://github.com/transmissions11/solmate/blob/main/src/test/ERC4626.t.sol - it('multiple deposits and withdrawals', async () => { - const vault = await createVaultMock(admin, { - capacity, - feePercent: 0, - metadataIpfsHash, - }) - await vault.resetSecurityDeposit() - const alice = holder - const bob = other - let sharedMevEscrowBalance = await ethers.provider.getBalance( - await sharedMevEscrow.getAddress() - ) - - // collateralize vault by registering validator - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await vault._setTotalAssets(0) - await vault._setTotalShares(0) - - let aliceShares = 0n - let aliceAssets = 0n - let bobShares = 0n - let bobAssets = 0n - let totalAssets = 0n - let totalShares = 0n - let queuedShares = 0n - let unclaimedAssets = 0n - let latestPositionTicket = validatorDeposit - let vaultLiquidAssets = 0n - let totalReward = 0n - let totalUnlockedMevReward = 0n - - const checkVaultState = async () => { - expect(await vault.getShares(alice.address)).to.be.eq(aliceShares) - expect(await vault.getShares(bob.address)).to.be.eq(bobShares) - expect(await vault.convertToAssets(aliceShares)).to.be.eq(aliceAssets) - expect(await vault.convertToAssets(bobShares)).to.be.eq(bobAssets) - expect(await vault.totalShares()).to.be.eq(totalShares) - expect(await ethers.provider.getBalance(await sharedMevEscrow.getAddress())).to.be.eq( - sharedMevEscrowBalance - ) - expect(await ethers.provider.getBalance(await vault.getAddress())).to.be.eq(vaultLiquidAssets) - expect(await vault.totalAssets()).to.be.eq(totalAssets) - expect(await vault.queuedShares()).to.be.eq(queuedShares) - } - - // 1. Alice deposits 2000 ETH (mints 2000 shares) - aliceShares += 2000n - aliceAssets += 2000n - totalAssets += 2000n - vaultLiquidAssets += 2000n - totalShares += 2000n - await vault.connect(alice).deposit(alice.address, referrer, { value: aliceAssets }) - - await checkVaultState() - - // 2. Bob deposits 4000 ETH (mints 4000 shares) - bobShares += 4000n - bobAssets += 4000n - totalAssets += 4000n - vaultLiquidAssets += 4000n - totalShares += 4000n - await vault.connect(bob).deposit(bob.address, referrer, { value: bobAssets }) - - await checkVaultState() - - // 3. Vault mutates by +3000 ETH (40% from validators, 60% from priority fees) - totalAssets += 3000n - totalReward += 3000n - vaultLiquidAssets += 1800n - totalUnlockedMevReward += 1800n - let vaultReward = getHarvestParams( - await vault.getAddress(), - totalReward, - totalUnlockedMevReward - ) - let tree = await updateRewards(keeper, [vaultReward]) - let proof = getRewardsRootProof(tree, vaultReward) - await setBalance(await sharedMevEscrow.getAddress(), 1800n) - await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - aliceAssets += 1000n - bobAssets += 2000n - sharedMevEscrowBalance = 0n - - await checkVaultState() - - // 4. Alice deposits 2000 ETH (mints 1334 shares) - aliceShares += 1334n - aliceAssets += 2000n - bobAssets -= 1n // rounding error - totalAssets += 2000n - vaultLiquidAssets += 2000n - totalShares += 1334n - - await vault.connect(alice).deposit(alice.address, referrer, { value: 2000 }) - await checkVaultState() - - // 5. Bob deposits 3000 ETH (mints 2000 shares) - await vault.connect(bob).deposit(bob.address, referrer, { value: 3000 }) - bobShares += 2001n // rounds up - bobAssets += 3000n - totalAssets += 3000n - vaultLiquidAssets += 3000n - totalShares += 2001n - - await checkVaultState() - - // 6. Vault mutates by +3000 shares - totalAssets += 3000n - totalReward += 3000n - vaultLiquidAssets += 1800n - totalUnlockedMevReward += 1800n - await setBalance(await sharedMevEscrow.getAddress(), 1800n) - vaultReward = getHarvestParams(await vault.getAddress(), totalReward, totalUnlockedMevReward) - tree = await updateRewards(keeper, [vaultReward]) - proof = getRewardsRootProof(tree, vaultReward) - await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - aliceAssets += 1071n - bobAssets += 1929n - - await checkVaultState() - - // 7. Alice enters exit queue with 1333 shares (2427 assets) - let response = await vault.connect(alice).enterExitQueue(1333, alice.address) - let alicePositionTicket = await extractExitPositionTicket(response) - let aliceTimestamp = await getBlockTimestamp(response) - - // alice withdraws assets - vaultReward = getHarvestParams(await vault.getAddress(), totalReward, totalUnlockedMevReward) - tree = await updateRewards(keeper, [vaultReward]) - proof = getRewardsRootProof(tree, vaultReward) - await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - await vault - .connect(alice) - .claimExitedAssets( - alicePositionTicket, - aliceTimestamp, - await vault.getExitQueueIndex(alicePositionTicket) - ) - - aliceShares -= 1333n - aliceAssets -= 2428n - bobAssets -= 1n // rounding error - totalAssets -= 2427n - vaultLiquidAssets -= 2427n - totalShares -= 1332n - expect(alicePositionTicket).to.eq(latestPositionTicket) - latestPositionTicket = validatorDeposit + 1333n - queuedShares += 1n - - await checkVaultState() - - // 8. Bob enters exit queue with 1608 assets (2928 shares) - response = await vault.connect(bob).enterExitQueue(1608, bob.address) - let bobPositionTicket = await extractExitPositionTicket(response) - let bobTimestamp = await getBlockTimestamp(response) - - vaultReward = getHarvestParams(await vault.getAddress(), totalReward, totalUnlockedMevReward) - await updateRewards(keeper, [vaultReward]) - await vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - await increaseTime(EXITING_ASSETS_MIN_DELAY) - await vault - .connect(bob) - .claimExitedAssets( - bobPositionTicket, - bobTimestamp, - await vault.getExitQueueIndex(bobPositionTicket) - ) - - bobShares -= 1608n - bobAssets -= 2929n - totalAssets -= 2929n - vaultLiquidAssets -= 2927n - totalShares -= 1608n - expect(bobPositionTicket).to.eq(latestPositionTicket) - latestPositionTicket = latestPositionTicket + 1608n - - await checkVaultState() - - // 9. Most the Vault's assets are staked - vaultLiquidAssets = 2600n - await setBalance(await vault.getAddress(), 2600n) - - // 10. Alice enters exit queue with 1000 shares - response = await vault.connect(alice).enterExitQueue(1000, alice.address) - alicePositionTicket = await extractExitPositionTicket(response) - aliceTimestamp = await getBlockTimestamp(response) - await expect(response) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(alice.address, alice.address, alicePositionTicket, 1000) - - aliceShares -= 1000n // rounding error - aliceAssets -= 1821n - queuedShares += 1000n - expect(alicePositionTicket).to.eq(latestPositionTicket) - latestPositionTicket = latestPositionTicket + 1000n - - await checkVaultState() - - // 11. Bob enters exit queue with 4393 shares - response = await vault.connect(bob).enterExitQueue(4393n, bob.address) - bobPositionTicket = await extractExitPositionTicket(response) - bobTimestamp = await getBlockTimestamp(response) - - await expect(response) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(bob.address, bob.address, bobPositionTicket, 4393) - - bobShares -= 4393n - bobAssets -= 7998n - queuedShares += 4393n - expect(bobPositionTicket).to.eq(latestPositionTicket) - latestPositionTicket = latestPositionTicket + 4393n - - await checkVaultState() - - // 12. Update exit queue and transfer not staked assets to Bob and Alice - vaultReward = getHarvestParams(await vault.getAddress(), totalReward, totalUnlockedMevReward) - tree = await updateRewards(keeper, [vaultReward]) - proof = getRewardsRootProof(tree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ) - .to.emit(vault, 'CheckpointCreated') - .withArgs(1426, 2598) - - totalAssets -= 2598n - totalShares -= 1426n - queuedShares -= 1426n - unclaimedAssets += 2598n - await checkVaultState() - - // 13. Vault mutates by +5000 shares - totalAssets += 5000n - totalReward += 5000n - vaultLiquidAssets += 3000n - totalUnlockedMevReward += 3000n - - vaultReward = getHarvestParams(await vault.getAddress(), totalReward, totalUnlockedMevReward) - tree = await updateRewards(keeper, [vaultReward]) - await setBalance(await sharedMevEscrow.getAddress(), 3000n) - proof = getRewardsRootProof(tree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ) - .to.emit(vault, 'CheckpointCreated') - .withArgs(1061, 3000) - - // update alice assets - aliceAssets += 1007n - totalShares -= 1061n - totalAssets -= 3000n - queuedShares -= 1061n - unclaimedAssets += 3000n - await checkVaultState() - - // 14. Bob claims exited assets - let bobCheckpointIdx = await vault.getExitQueueIndex(bobPositionTicket) - await expect( - vault.connect(bob).claimExitedAssets(bobPositionTicket, bobTimestamp, bobCheckpointIdx) - ) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(bob.address, bobPositionTicket, bobPositionTicket + 1486n, 3774n) - - bobPositionTicket = bobPositionTicket + 1486n - vaultLiquidAssets -= 3774n - unclaimedAssets -= 3774n - await checkVaultState() - - // 15. Alice claims exited assets - let aliceCheckpointIdx = await vault.getExitQueueIndex(alicePositionTicket) - await expect( - vault - .connect(alice) - .claimExitedAssets(alicePositionTicket, aliceTimestamp, aliceCheckpointIdx) - ) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(alice.address, alicePositionTicket, 0, 1821) - - vaultLiquidAssets -= 1821n - unclaimedAssets -= 1821n - await checkVaultState() - - // 16. Alice enters exit queue with 1001 shares - response = await vault.connect(alice).enterExitQueue(1001, alice.address) - alicePositionTicket = await extractExitPositionTicket(response) - aliceTimestamp = await getBlockTimestamp(response) - await expect(response) - .to.emit(vault, 'ExitQueueEntered') - .withArgs(alice.address, alice.address, alicePositionTicket, 1001) - - expect(alicePositionTicket).to.be.eq(latestPositionTicket) - queuedShares += 1001n - aliceShares -= 1001n - aliceAssets -= 2829n - await checkVaultState() - - // 17. Withdrawal of all the assets arrives - await increaseTime(ONE_DAY) - await setBalance(await vault.getAddress(), totalAssets + unclaimedAssets + 2n) - vaultReward = getHarvestParams(await vault.getAddress(), totalReward, totalUnlockedMevReward) - tree = await updateRewards(keeper, [vaultReward]) - proof = getRewardsRootProof(tree, vaultReward) - await expect( - vault.updateState({ - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - ).to.emit(vault, 'CheckpointCreated') - - unclaimedAssets += totalAssets + 2n - vaultLiquidAssets = unclaimedAssets - totalShares = 0n - queuedShares = 0n - totalAssets = 0n - - await checkVaultState() - - // 18. Bob claims exited assets - bobCheckpointIdx = await vault.getExitQueueIndex(bobPositionTicket) - expect(bobCheckpointIdx).to.eq(5) - await expect( - vault.connect(bob).claimExitedAssets(bobPositionTicket, bobTimestamp, bobCheckpointIdx) - ) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(bob.address, bobPositionTicket, 0, 8216) - - vaultLiquidAssets -= 8216n - await checkVaultState() - - // 19. Alice claims exited assets - aliceCheckpointIdx = await vault.getExitQueueIndex(alicePositionTicket) - expect(aliceCheckpointIdx).to.eq(5) - await expect( - vault - .connect(alice) - .claimExitedAssets(alicePositionTicket, aliceTimestamp, aliceCheckpointIdx) - ) - .to.emit(vault, 'ExitedAssetsClaimed') - .withArgs(alice.address, alicePositionTicket, 0, 2829) - vaultLiquidAssets -= 2829n - await checkVaultState() - - // 20. Check whether state is correct - aliceShares = 0n - aliceAssets = 0n - bobShares = 0n - bobAssets = 0n - totalAssets = 0n - totalShares = 0n - queuedShares = 0n - vaultLiquidAssets = 6n - await checkVaultState() - }) -}) diff --git a/test/EthVaultFactory.spec.ts b/test/EthVaultFactory.spec.ts deleted file mode 100644 index d3a26aee..00000000 --- a/test/EthVaultFactory.spec.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { ethers } from 'hardhat' -import { Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthVaultFactory, SharedMevEscrow, VaultsRegistry } from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { expect } from './shared/expect' -import { - encodeEthErc20VaultInitParams, - encodeEthVaultInitParams, - ethVaultFixture, -} from './shared/fixtures' -import { SECURITY_DEPOSIT, ZERO_ADDRESS, ZERO_BYTES32 } from './shared/constants' -import { extractMevEscrowAddress, extractVaultAddress, toHexString } from './shared/utils' -import keccak256 from 'keccak256' - -describe('EthVaultFactory', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const name = 'SW ETH Vault' - const symbol = 'SW-ETH-1' - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - const ethVaultInitParams = { - capacity, - feePercent, - metadataIpfsHash, - } - const ethVaultInitParamsEncoded = encodeEthVaultInitParams(ethVaultInitParams) - const ethErc20VaultInitParams = { - capacity, - feePercent, - name, - symbol, - metadataIpfsHash, - } - const ethErc20VaultInitParamsEncoded = encodeEthErc20VaultInitParams(ethErc20VaultInitParams) - let admin: Wallet - let ethVaultFactory: EthVaultFactory, - ethPrivVaultFactory: EthVaultFactory, - ethErc20VaultFactory: EthVaultFactory, - ethPrivErc20VaultFactory: EthVaultFactory, - ethBlocklistVaultFactory: EthVaultFactory, - ethBlocklistErc20VaultFactory: EthVaultFactory - let sharedMevEscrow: SharedMevEscrow - let vaultsRegistry: VaultsRegistry - - beforeEach(async () => { - ;[admin] = (await (ethers as any).getSigners()).slice(1, 2) - ;({ - ethVaultFactory, - ethPrivVaultFactory, - ethErc20VaultFactory, - ethPrivErc20VaultFactory, - ethBlocklistVaultFactory, - ethBlocklistErc20VaultFactory, - vaultsRegistry, - sharedMevEscrow, - } = await loadFixture(ethVaultFixture)) - }) - - describe('EthVault', () => { - it('public vault deployment with own escrow gas', async () => { - const receipt = await ethVaultFactory - .connect(admin) - .createVault(ethVaultInitParamsEncoded, true, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - - it('public vault deployment with shared escrow gas', async () => { - const receipt = await ethVaultFactory - .connect(admin) - .createVault(ethVaultInitParamsEncoded, false, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with own escrow gas', async () => { - const receipt = await ethPrivVaultFactory - .connect(admin) - .createVault(ethVaultInitParamsEncoded, true, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with shared escrow gas', async () => { - const receipt = await ethPrivVaultFactory - .connect(admin) - .createVault(ethVaultInitParamsEncoded, false, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - }) - - describe('EthErc20Vault', () => { - it('public vault deployment with own escrow gas', async () => { - const receipt = await ethErc20VaultFactory - .connect(admin) - .createVault(ethErc20VaultInitParamsEncoded, true, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - - it('public vault deployment with shared escrow gas', async () => { - const receipt = await ethErc20VaultFactory - .connect(admin) - .createVault(ethErc20VaultInitParamsEncoded, false, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with own escrow gas', async () => { - const receipt = await ethPrivErc20VaultFactory - .connect(admin) - .createVault(ethErc20VaultInitParamsEncoded, true, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - - it('private vault deployment with shared escrow gas', async () => { - const receipt = await ethPrivErc20VaultFactory - .connect(admin) - .createVault(ethErc20VaultInitParamsEncoded, false, { value: SECURITY_DEPOSIT }) - await snapshotGasCost(receipt) - }) - }) - - it('creates vaults correctly', async () => { - for (const config of [ - { - factory: ethVaultFactory, - vaultClass: 'EthVault', - isErc20: false, - isPrivate: false, - isBlocklist: false, - }, - { - factory: ethPrivVaultFactory, - vaultClass: 'EthPrivVault', - isErc20: false, - isPrivate: true, - isBlocklist: false, - }, - { - factory: ethBlocklistVaultFactory, - vaultClass: 'EthBlocklistVault', - isErc20: false, - isPrivate: false, - isBlocklist: true, - }, - { - factory: ethErc20VaultFactory, - vaultClass: 'EthErc20Vault', - isErc20: true, - isPrivate: false, - isBlocklist: false, - }, - { - factory: ethPrivErc20VaultFactory, - vaultClass: 'EthPrivErc20Vault', - isErc20: true, - isPrivate: true, - isBlocklist: false, - }, - { - factory: ethBlocklistErc20VaultFactory, - vaultClass: 'EthBlocklistErc20Vault', - isErc20: true, - isPrivate: false, - isBlocklist: true, - }, - ]) { - for (const isOwnEscrow of [false, true]) { - const { factory, isErc20, vaultClass, isPrivate, isBlocklist } = config - const initParamsEncoded = isErc20 - ? encodeEthErc20VaultInitParams(ethErc20VaultInitParams) - : encodeEthVaultInitParams(ethVaultInitParams) - - // fails without security deposit - await expect(factory.connect(admin).createVault(initParamsEncoded, isOwnEscrow)).to.reverted - - const tx = await factory - .connect(admin) - .createVault(initParamsEncoded, isOwnEscrow, { value: SECURITY_DEPOSIT }) - const vaultAddress = await extractVaultAddress(tx) - const mevEscrow = isOwnEscrow - ? await extractMevEscrowAddress(tx) - : await sharedMevEscrow.getAddress() - - await expect(tx) - .to.emit(factory, 'VaultCreated') - .withArgs( - admin.address, - vaultAddress, - isOwnEscrow ? mevEscrow : ZERO_ADDRESS, - initParamsEncoded - ) - - const vaultFactory = await ethers.getContractFactory(vaultClass) - const vault = await vaultFactory.attach(vaultAddress) - - await expect(tx) - .to.emit(vaultsRegistry, 'VaultAdded') - .withArgs(await factory.getAddress(), vaultAddress) - await expect(vault.connect(admin).initialize(ZERO_BYTES32)).to.revertedWithCustomError( - vault, - 'InvalidInitialization' - ) - - // Factory - expect(await factory.vaultAdmin()).to.be.eq(ZERO_ADDRESS) - expect(await factory.ownMevEscrow()).to.be.eq(ZERO_ADDRESS) - - expect(await vaultsRegistry.vaults(vaultAddress)).to.be.eq(true) - expect(await vault.capacity()).to.be.eq(capacity) - - // VaultToken - if (isErc20) { - expect(await vault.name()).to.be.eq(name) - expect(await vault.symbol()).to.be.eq(symbol) - } - - // VaultAdmin - expect(await vault.admin()).to.be.eq(admin.address) - await expect(tx) - .to.emit(vault, 'MetadataUpdated') - .withArgs(await factory.getAddress(), metadataIpfsHash) - - // VaultVersion - expect(await vault.version()).to.be.eq(4) - expect(await vault.vaultId()).to.be.eq(toHexString(keccak256(vaultClass))) - expect(await factory.implementation()).to.be.eq(await vault.implementation()) - - // VaultFee - expect(await vault.feeRecipient()).to.be.eq(admin.address) - expect(await vault.feePercent()).to.be.eq(feePercent) - await expect(tx) - .to.emit(vault, 'FeeRecipientUpdated') - .withArgs(await factory.getAddress(), admin.address) - - // VaultMev - expect(await vault.mevEscrow()).to.be.eq(mevEscrow) - - // VaultWhitelist - if (isPrivate) { - await expect(await vault.whitelister()).to.be.eq(admin.address) - await expect(tx) - .to.emit(vault, 'WhitelisterUpdated') - .withArgs(await factory.getAddress(), admin.address) - } - - // VaultBlocklist - if (isBlocklist) { - await expect(await vault.blocklistManager()).to.be.eq(admin.address) - await expect(tx) - .to.emit(vault, 'BlocklistManagerUpdated') - .withArgs(await factory.getAddress(), admin.address) - } - } - } - }) -}) diff --git a/test/Fork.t.sol b/test/Fork.t.sol deleted file mode 100644 index 989cf994..00000000 --- a/test/Fork.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -abstract contract ForkTest { - uint256 public forkBlockNumber; - address public keeper; - address public validatorsRegistry; - address public vaultsRegistry; - address public osTokenVaultController; - address public osTokenConfig; - address public osTokenVaultEscrow; - address public sharedMevEscrow; - address public depositDataRegistry; - uint256 public exitingAssetsClaimDelay; - address public v2VaultFactory; - address public erc20VaultFactory; - address public vaultV3Impl; - address public genesisVault; - address public poolEscrow; - address public rewardEthToken; -} diff --git a/test/GnoRewardSplitter.t.sol b/test/GnoRewardSplitter.t.sol deleted file mode 100644 index 1168d420..00000000 --- a/test/GnoRewardSplitter.t.sol +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IGnoVault} from '../contracts/interfaces/IGnoVault.sol'; -import {IGnoVaultFactory} from '../contracts/interfaces/IGnoVaultFactory.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IVaultAdmin} from '../contracts/interfaces/IVaultAdmin.sol'; -import {IVaultFee} from '../contracts/interfaces/IVaultFee.sol'; -import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; -import {GnoVault} from '../contracts/vaults/gnosis/GnoVault.sol'; -import {RewardSplitterFactory} from '../contracts/misc/RewardSplitterFactory.sol'; -import {IRewardSplitterFactory} from '../contracts/interfaces/IRewardSplitterFactory.sol'; -import {GnoRewardSplitter} from '../contracts/misc/GnoRewardSplitter.sol'; -import {RewardSplitter} from '../contracts/misc/RewardSplitter.sol'; -import {IRewardSplitter} from '../contracts/interfaces/IRewardSplitter.sol'; -import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {IVaultGnoStaking} from '../contracts/interfaces/IVaultGnoStaking.sol'; -import {Vm} from '../lib/forge-std/src/Vm.sol'; -import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; -import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; -import {Test} from '../lib/forge-std/src/Test.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {RewardsTest} from './Rewards.t.sol'; -import {ConstantsTest} from './Constants.t.sol'; -import {GnosisForkTest} from './GnosisFork.t.sol'; - -abstract contract GnoRewardSplitterTest is Test, ConstantsTest, GnosisForkTest, RewardsTest { - address public constant user1 = address(0x1); - address public constant user2 = address(0x2); - - address public vault; - address public vaultAdmin; - address public rewardSplitter; - address public rewardSplitterFactory; - uint256 avgRewardPerSecond = 1585489600; - - function setUp() public virtual override(ConstantsTest, GnosisForkTest, RewardsTest) { - GnosisForkTest.setUp(); - ConstantsTest.setUp(); - RewardsTest.setUp(); - - vm.prank(VaultsRegistry(vaultsRegistry).owner()); - VaultsRegistry(vaultsRegistry).addFactory(v2VaultFactory); - - // set GNO token balance - deal(address(gnoToken), address(this), 100 ether); - - // approve GNO token for V2 vault factory - IERC20(gnoToken).approve(v2VaultFactory, 1 ether); - - // create V2 vault - IGnoVault.GnoVaultInitParams memory params = IGnoVault.GnoVaultInitParams({ - capacity: type(uint256).max, - feePercent: 1000, - metadataIpfsHash: '' - }); - vault = IGnoVaultFactory(v2VaultFactory).createVault(abi.encode(params), false); - - // collateralize vault (imitate validator creation) - _collateralizeVault(vault); - - // set vault admin - vaultAdmin = IVaultAdmin(vault).admin(); - - // create reward splitter and connect to vault - vm.startPrank(vaultAdmin); - address rewardSplitterImpl = address(new GnoRewardSplitter(gnoToken)); - rewardSplitterFactory = address(new RewardSplitterFactory(rewardSplitterImpl)); - rewardSplitter = IRewardSplitterFactory(rewardSplitterFactory).createRewardSplitter(vault); - IVaultFee(vault).setFeeRecipient(rewardSplitter); - vm.stopPrank(); - } -} - -contract GnoRewardSplitterClaimExitedAssetsOnBehalfTest is GnoRewardSplitterTest { - uint128 public constant shares = 100; - uint256 rewards; - uint256 positionTicket; - uint256 timestamp; - - function setUp() public override { - super.setUp(); - - // add shareholder - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).increaseShares(user1, shares); - - // approve GNO token for vault - IERC20(gnoToken).approve(vault, 10 ether); - - // deposit vault - uint256 depositAmount = 10 ether - SECURITY_DEPOSIT; - IVaultGnoStaking(vault).deposit(depositAmount, user2, ZERO_ADDRESS); - - // set vault rewards - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 - ); - IVaultState(vault).updateState(harvestParams); - - // set shareholder rewards - IRewardSplitter(rewardSplitter).syncRewards(); - rewards = IRewardSplitter(rewardSplitter).rewardsOf(user1); - - // enable claim on behalf - vm.prank(vaultAdmin); - IRewardSplitter(rewardSplitter).setClaimOnBehalf(true); - - // enter exit queue on behalf - positionTicket = IRewardSplitter(rewardSplitter).enterExitQueueOnBehalf(rewards, user1); - timestamp = block.timestamp; - } - - function test_basic() public { - skip(exitingAssetsClaimDelay + 1); - - // repeat update state to trigger exit queue processing - uint256 totalReward = 1 ether; - skip(REWARDS_DELAY + 1); - IKeeperRewards.HarvestParams memory harvestParams = _setVaultRewards( - vault, SafeCast.toInt256(totalReward), 0, 0 - ); - IVaultState(vault).updateState(harvestParams); - - // set shareholder balance before claim - uint256 balanceBeforeClaim = IERC20(gnoToken).balanceOf(user1); - - // check onBehalf, positionTicket, do not check amount - vm.expectEmit(true, true, false, false); - emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(user1, positionTicket, 0); - - // claim exited assets on behalf - int256 exitQueueIndex = IGnoVault(vault).getExitQueueIndex(positionTicket); - IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( - positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) - ); - - // Take 1 ether vault reward, apply 10% vault fee - uint256 exitedAssets = 0.1 ether; - - // check user balance change, leave 1 wei for rounding error - uint256 balanceAfterClaim = IERC20(gnoToken).balanceOf(user1); - assertApproxEqAbs(balanceAfterClaim - balanceBeforeClaim, exitedAssets, 1 wei); - - // check repeating call fails - vm.expectRevert(Errors.InvalidPosition.selector); - IRewardSplitter(rewardSplitter).claimExitedAssetsOnBehalf( - positionTicket, timestamp, SafeCast.toUint256(exitQueueIndex) - ); - } -} diff --git a/test/GnosisFork.t.sol b/test/GnosisFork.t.sol deleted file mode 100644 index d19c0dd6..00000000 --- a/test/GnosisFork.t.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {Test} from '../lib/forge-std/src/Test.sol'; -import {ForkTest} from './Fork.t.sol'; - - -abstract contract GnosisForkTest is Test, ForkTest { - address public gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; - - function setUp() public virtual { - forkBlockNumber = 38760307; - - keeper = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; - validatorsRegistry = 0x0B98057eA310F4d31F2a452B414647007d1645d9; - vaultsRegistry = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; - osTokenVaultController = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; - osTokenConfig = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; - osTokenVaultEscrow = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; - sharedMevEscrow = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; - depositDataRegistry = 0x58e16621B5c0786D6667D2d54E28A20940269E16; - exitingAssetsClaimDelay = 24 hours; - v2VaultFactory = 0x78c54FEfAB5DAb75ee7461565b85341dd8b92e30; - erc20VaultFactory = 0x0aaa2b3Cf5F14eF24Afb2CD7Cf4CcCC065Be108B; - vaultV3Impl = 0x0000000000000000000000000000000000000000; - genesisVault = 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a; - poolEscrow = 0x0000000000000000000000000000000000000000; - rewardEthToken = 0x0000000000000000000000000000000000000000; - gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; - - vm.createSelectFork(vm.envString('GNOSIS_RPC_URL'), forkBlockNumber); - } -} diff --git a/test/KeeperOracles.spec.ts b/test/KeeperOracles.spec.ts deleted file mode 100644 index 8eb835f0..00000000 --- a/test/KeeperOracles.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { ethers } from 'hardhat' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { Wallet } from 'ethers' -import { Keeper } from '../typechain-types' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import snapshotGasCost from './shared/snapshotGasCost' -import { ORACLES, ORACLES_CONFIG, ZERO_ADDRESS } from './shared/constants' - -describe('KeeperOracles', () => { - const maxOracles = 30 - let dao: Wallet, oracle: Wallet, other: Wallet - let keeper: Keeper - let totalOracles: number - - beforeEach('deploy fixture', async () => { - ;[dao, oracle, other] = await (ethers as any).getSigners() - ;({ keeper } = await loadFixture(ethVaultFixture)) - totalOracles = Number(await keeper.totalOracles()) - }) - - describe('add oracle', () => { - it('fails if not owner', async () => { - await expect(keeper.connect(other).addOracle(oracle.address)).revertedWithCustomError( - keeper, - 'OwnableUnauthorizedAccount' - ) - }) - - it('fails if already added', async () => { - await keeper.connect(dao).addOracle(oracle.address) - await expect(keeper.connect(dao).addOracle(oracle.address)).revertedWithCustomError( - keeper, - 'AlreadyAdded' - ) - }) - - it('fails when number of oracles exceeded', async () => { - for (let i = 0; i < maxOracles - ORACLES.length; i++) { - await keeper.connect(dao).addOracle(ethers.Wallet.createRandom().address) - } - await expect( - keeper.connect(dao).addOracle(ethers.Wallet.createRandom().address) - ).revertedWithCustomError(keeper, 'MaxOraclesExceeded') - }) - - it('succeeds', async () => { - const receipt = await keeper.connect(dao).addOracle(oracle.address) - await expect(receipt).to.emit(keeper, 'OracleAdded').withArgs(oracle.address) - expect(await keeper.isOracle(oracle.address)).to.be.eq(true) - expect(await keeper.totalOracles()).to.be.eq(totalOracles + 1) - await snapshotGasCost(receipt) - }) - }) - - describe('remove oracle', () => { - let totalOracles: number - - beforeEach(async () => { - await keeper.connect(dao).addOracle(oracle.address) - totalOracles = Number(await keeper.totalOracles()) - }) - - it('fails if not owner', async () => { - await expect(keeper.connect(other).removeOracle(oracle.address)).revertedWithCustomError( - keeper, - 'OwnableUnauthorizedAccount' - ) - }) - - it('fails if already removed', async () => { - await keeper.connect(dao).removeOracle(oracle.address) - await expect(keeper.connect(dao).removeOracle(oracle.address)).revertedWithCustomError( - keeper, - 'AlreadyRemoved' - ) - }) - - it('succeeds', async () => { - const receipt = await keeper.connect(dao).removeOracle(oracle.address) - await expect(receipt).to.emit(keeper, 'OracleRemoved').withArgs(oracle.address) - expect(await keeper.isOracle(oracle.address)).to.be.eq(false) - expect(await keeper.totalOracles()).to.be.eq(totalOracles - 1) - await snapshotGasCost(receipt) - }) - }) - - describe('update config', () => { - it('fails if not owner', async () => { - await expect(keeper.connect(other).updateConfig(ORACLES_CONFIG)).revertedWithCustomError( - keeper, - 'OwnableUnauthorizedAccount' - ) - }) - - it('succeeds', async () => { - const receipt = await keeper.connect(dao).updateConfig(ORACLES_CONFIG) - await expect(receipt).to.emit(keeper, 'ConfigUpdated').withArgs(ORACLES_CONFIG) - await snapshotGasCost(receipt) - }) - }) - - describe('initialize', () => { - it('cannot initialize twice', async () => { - await expect(keeper.connect(dao).initialize(other.address)).revertedWithCustomError( - keeper, - 'AccessDenied' - ) - }) - - it('not owner cannot initialize', async () => { - await expect(keeper.connect(other).initialize(other.address)).revertedWithCustomError( - keeper, - 'OwnableUnauthorizedAccount' - ) - }) - - it('cannot initialize to zero address', async () => { - await expect(keeper.connect(dao).initialize(ZERO_ADDRESS)).revertedWithCustomError( - keeper, - 'ZeroAddress' - ) - }) - }) -}) diff --git a/test/KeeperOracles.t.sol b/test/KeeperOracles.t.sol index 188ac078..9f5aded9 100644 --- a/test/KeeperOracles.t.sol +++ b/test/KeeperOracles.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.22; import {Test} from 'forge-std/Test.sol'; import {IKeeperOracles} from '../contracts/interfaces/IKeeperOracles.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; import {Errors} from '../contracts/libraries/Errors.sol'; import {Keeper} from '../contracts/keeper/Keeper.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; diff --git a/test/KeeperRewards.spec.ts b/test/KeeperRewards.spec.ts deleted file mode 100644 index 4b7b4f2c..00000000 --- a/test/KeeperRewards.spec.ts +++ /dev/null @@ -1,837 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - IKeeperRewards, - Keeper, - OsTokenVaultController, - SharedMevEscrow, - DepositDataRegistry, -} from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { ethVaultFixture, getOraclesSignatures } from './shared/fixtures' -import { expect } from './shared/expect' -import { - MAX_AVG_REWARD_PER_SECOND, - ORACLES, - REWARDS_DELAY, - REWARDS_MIN_ORACLES, - ZERO_ADDRESS, - ZERO_BYTES32, -} from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { - getHarvestParams, - getKeeperRewardsUpdateData, - getRewardsRootProof, - VaultReward, -} from './shared/rewards' -import { increaseTime, setBalance, toHexString } from './shared/utils' -import { registerEthValidator } from './shared/validators' - -describe('KeeperRewards', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - let createVault: ThenArg>['createEthVault'] - - let dao: Wallet, admin: Signer, oracle: Wallet, other: Wallet - let keeper: Keeper, - validatorsRegistry: Contract, - sharedMevEscrow: SharedMevEscrow, - osTokenVaultController: OsTokenVaultController, - depositDataRegistry: DepositDataRegistry - let globalRewardsNonce: number - - beforeEach(async () => { - ;[dao, admin, oracle, other] = await (ethers as any).getSigners() - ;({ - keeper, - createEthVault: createVault, - validatorsRegistry, - sharedMevEscrow, - osTokenVaultController, - depositDataRegistry, - } = await loadFixture(ethVaultFixture)) - await setBalance(oracle.address, ethers.parseEther('10000')) - }) - - describe('update rewards', () => { - let vaultReward: VaultReward - let rewardsUpdateParams: IKeeperRewards.RewardsUpdateParamsStruct - let vault: EthVault - - beforeEach(async () => { - vault = await createVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - vaultReward = getHarvestParams( - await vault.getAddress(), - ethers.parseEther('5'), - ethers.parseEther('1') - ) - globalRewardsNonce = Number(await keeper.rewardsNonce()) - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper, { - nonce: globalRewardsNonce, - }) - rewardsUpdateParams = { - rewardsRoot: rewardsUpdate.root, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - } - await increaseTime(REWARDS_DELAY) - }) - - it('fails with invalid IPFS hash', async () => { - await expect( - keeper - .connect(oracle) - .updateRewards({ ...rewardsUpdateParams, rewardsIpfsHash: ZERO_BYTES32 }) - ).to.be.revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails with invalid avgRewardPerSecond', async () => { - await expect( - keeper.connect(oracle).updateRewards({ - ...rewardsUpdateParams, - avgRewardPerSecond: MAX_AVG_REWARD_PER_SECOND + 1, - }) - ).to.be.revertedWithCustomError(keeper, 'InvalidAvgRewardPerSecond') - }) - - it('fails with invalid nonce', async () => { - await keeper.connect(oracle).updateRewards(rewardsUpdateParams) - - const newVaultReward = getHarvestParams( - await vault.getAddress(), - ethers.parseEther('3'), - ethers.parseEther('2') - ) - const newRewardsUpdate = await getKeeperRewardsUpdateData([newVaultReward], keeper) - await increaseTime(REWARDS_DELAY) - await expect( - keeper.connect(oracle).updateRewards({ - rewardsRoot: newRewardsUpdate.root, - rewardsIpfsHash: newRewardsUpdate.ipfsHash, - updateTimestamp: newRewardsUpdate.updateTimestamp, - avgRewardPerSecond: newRewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(newRewardsUpdate.signingData), - }) - ).to.be.revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails if too early', async () => { - await keeper.connect(oracle).updateRewards(rewardsUpdateParams) - const newVaultReward = getHarvestParams( - await vault.getAddress(), - ethers.parseEther('5'), - ethers.parseEther('1') - ) - const newRewardsUpdate = await getKeeperRewardsUpdateData([newVaultReward], keeper, { - nonce: globalRewardsNonce + 1, - updateTimestamp: 1680255895, - }) - expect(await keeper.canUpdateRewards()).to.eq(false) - await expect( - keeper.connect(oracle).updateRewards({ - rewardsRoot: newRewardsUpdate.root, - rewardsIpfsHash: newRewardsUpdate.ipfsHash, - updateTimestamp: newRewardsUpdate.updateTimestamp, - avgRewardPerSecond: newRewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(newRewardsUpdate.signingData), - }) - ).to.be.revertedWithCustomError(keeper, 'TooEarlyUpdate') - }) - - it('fails with invalid number of oracle signatures', async () => { - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper) - const params = { - ...rewardsUpdateParams, - signatures: getOraclesSignatures(rewardsUpdate.signingData, REWARDS_MIN_ORACLES - 1), - } - await expect(keeper.connect(oracle).updateRewards(params)).to.be.revertedWithCustomError( - keeper, - 'NotEnoughSignatures' - ) - }) - - it('fails with repeated signature', async () => { - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper) - const params = { - ...rewardsUpdateParams, - } - params.signatures = Buffer.concat([ - getOraclesSignatures(rewardsUpdate.signingData, REWARDS_MIN_ORACLES - 1), - getOraclesSignatures(rewardsUpdate.signingData, 1), - ]) - await expect(keeper.connect(oracle).updateRewards(params)).to.be.revertedWithCustomError( - keeper, - 'InvalidOracle' - ) - }) - - it('fails with invalid oracle', async () => { - await keeper - .connect(dao) - .removeOracle(new Wallet(toHexString(ORACLES[1]), ethers.provider).address) - await expect( - keeper.connect(oracle).updateRewards(rewardsUpdateParams) - ).to.be.revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('succeeds with all signatures', async () => { - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper, { - nonce: globalRewardsNonce, - }) - const params = { - ...rewardsUpdateParams, - signatures: getOraclesSignatures(rewardsUpdate.signingData, ORACLES.length), - } - const receipt = await keeper.connect(oracle).updateRewards(params) - await snapshotGasCost(receipt) - }) - - it('succeeds', async () => { - expect(await keeper.canUpdateRewards()).to.eq(true) - const prevRewardsRoot = await keeper.rewardsRoot() - const prevRewardsTimestamp = await keeper.lastRewardsTimestamp() - - let receipt = await keeper.connect(oracle).updateRewards(rewardsUpdateParams) - await expect(receipt) - .to.emit(keeper, 'RewardsUpdated') - .withArgs( - oracle.address, - rewardsUpdateParams.rewardsRoot, - rewardsUpdateParams.avgRewardPerSecond, - rewardsUpdateParams.updateTimestamp, - globalRewardsNonce, - rewardsUpdateParams.rewardsIpfsHash - ) - await expect(receipt) - .to.emit(osTokenVaultController, 'AvgRewardPerSecondUpdated') - .withArgs(rewardsUpdateParams.avgRewardPerSecond) - - expect(await keeper.prevRewardsRoot()).to.eq(prevRewardsRoot) - expect(await keeper.rewardsRoot()).to.eq(rewardsUpdateParams.rewardsRoot) - expect(await keeper.rewardsNonce()).to.eq(globalRewardsNonce + 1) - expect(await osTokenVaultController.avgRewardPerSecond()).to.eq( - rewardsUpdateParams.avgRewardPerSecond - ) - expect(await keeper.lastRewardsTimestamp()).to.not.eq(prevRewardsTimestamp) - expect(await keeper.canUpdateRewards()).to.eq(false) - await snapshotGasCost(receipt) - - // check keeps previous rewards root - const newVaultReward = getHarvestParams( - await vault.getAddress(), - ethers.parseEther('3'), - ethers.parseEther('2') - ) - const newRewardsUpdate = await getKeeperRewardsUpdateData([newVaultReward], keeper, { - nonce: globalRewardsNonce + 1, - updateTimestamp: 1670256000, - }) - await increaseTime(REWARDS_DELAY) - receipt = await keeper.connect(oracle).updateRewards({ - rewardsRoot: newRewardsUpdate.root, - rewardsIpfsHash: newRewardsUpdate.ipfsHash, - updateTimestamp: newRewardsUpdate.updateTimestamp, - avgRewardPerSecond: newRewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(newRewardsUpdate.signingData), - }) - await expect(receipt) - .to.emit(keeper, 'RewardsUpdated') - .withArgs( - oracle.address, - newRewardsUpdate.root, - newRewardsUpdate.avgRewardPerSecond, - newRewardsUpdate.updateTimestamp, - globalRewardsNonce + 1, - newRewardsUpdate.ipfsHash - ) - expect(await keeper.prevRewardsRoot()).to.eq(rewardsUpdateParams.rewardsRoot) - expect(await keeper.rewardsRoot()).to.eq(newRewardsUpdate.root) - expect(await keeper.rewardsNonce()).to.eq(globalRewardsNonce + 2) - await snapshotGasCost(receipt) - }) - }) - - describe('is harvest required', () => { - let vault: EthVault - - beforeEach(async () => { - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - await increaseTime(REWARDS_DELAY) - }) - - it('returns false for uncollateralized vault', async () => { - expect(await keeper.isCollateralized(await vault.getAddress())).to.equal(false) - expect(await keeper.isHarvestRequired(await vault.getAddress())).to.equal(false) - expect(await keeper.canHarvest(await vault.getAddress())).to.equal(false) - expect(await vault.isStateUpdateRequired()).to.equal(false) - }) - - it('returns true for collateralized two times unharvested vault', async () => { - // collateralize vault - const validatorDeposit = ethers.parseEther('32') - await vault - .connect(admin) - .deposit(await admin.getAddress(), ZERO_ADDRESS, { value: validatorDeposit }) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - expect(await keeper.isCollateralized(await vault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await vault.getAddress())).to.equal(false) - expect(await keeper.isHarvestRequired(await vault.getAddress())).to.equal(false) - expect(await vault.isStateUpdateRequired()).to.equal(false) - const globalRewardsNonce = Number(await keeper.rewardsNonce()) - - // update rewards first time - let newVaultReward = getHarvestParams( - await vault.getAddress(), - ethers.parseEther('3'), - ethers.parseEther('0.5') - ) - let newRewardsUpdate = await getKeeperRewardsUpdateData([newVaultReward], keeper, { - updateTimestamp: 1670258895, - nonce: globalRewardsNonce, - }) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: newRewardsUpdate.root, - rewardsIpfsHash: newRewardsUpdate.ipfsHash, - updateTimestamp: newRewardsUpdate.updateTimestamp, - avgRewardPerSecond: newRewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(newRewardsUpdate.signingData), - }) - - expect(await keeper.isCollateralized(await vault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await vault.getAddress())).to.equal(true) - expect(await keeper.isHarvestRequired(await vault.getAddress())).to.equal(false) - expect(await vault.isStateUpdateRequired()).to.equal(false) - - // update rewards second time - const newTimestamp = newRewardsUpdate.updateTimestamp + 1 - newVaultReward = getHarvestParams( - await vault.getAddress(), - ethers.parseEther('4'), - ethers.parseEther('2') - ) - newRewardsUpdate = await getKeeperRewardsUpdateData([newVaultReward], keeper, { - nonce: globalRewardsNonce + 1, - updateTimestamp: newTimestamp, - }) - await increaseTime(REWARDS_DELAY) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: newRewardsUpdate.root, - rewardsIpfsHash: newRewardsUpdate.ipfsHash, - updateTimestamp: newRewardsUpdate.updateTimestamp, - avgRewardPerSecond: newRewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(newRewardsUpdate.signingData), - }) - - expect(await keeper.isCollateralized(await vault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await vault.getAddress())).to.equal(true) - expect(await keeper.isHarvestRequired(await vault.getAddress())).to.equal(true) - expect(await vault.isStateUpdateRequired()).to.equal(true) - }) - }) - - describe('harvest (own escrow)', () => { - const newReward = ethers.parseEther('5') - let harvestParams: IKeeperRewards.HarvestParamsStruct - let ownMevVault: EthVault - let globalRewardsNonce: number - - beforeEach(async () => { - ownMevVault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true - ) - admin = await ethers.getImpersonatedSigner(await ownMevVault.admin()) - - const vaultReward = getHarvestParams(await ownMevVault.getAddress(), newReward, 0n) - const vaultRewards = [vaultReward] - for (let i = 1; i < 11; i++) { - const vlt = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true, - true - ) - vaultRewards.push( - getHarvestParams(await vlt.getAddress(), ethers.parseEther(i.toString()), 0n) - ) - } - - globalRewardsNonce = Number(await keeper.rewardsNonce()) - const rewardsUpdate = await getKeeperRewardsUpdateData(vaultRewards, keeper, { - nonce: globalRewardsNonce, - }) - await increaseTime(REWARDS_DELAY) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: rewardsUpdate.root, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - }) - harvestParams = { - rewardsRoot: rewardsUpdate.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(rewardsUpdate.tree, vaultReward), - } - globalRewardsNonce += 1 - expect(await keeper.rewardsNonce()).to.eq(globalRewardsNonce) - }) - - it('only vault can harvest', async () => { - await expect(keeper.harvest(harvestParams)).to.be.revertedWithCustomError( - keeper, - 'AccessDenied' - ) - }) - - it('fails for invalid reward', async () => { - await expect( - ownMevVault.updateState({ ...harvestParams, reward: 0 }) - ).to.be.revertedWithCustomError(keeper, 'InvalidProof') - }) - - it('fails for invalid proof', async () => { - await expect( - ownMevVault.updateState({ ...harvestParams, proof: [] }) - ).to.be.revertedWithCustomError(keeper, 'InvalidProof') - }) - - it('fails for invalid root', async () => { - const invalidRoot = '0x' + '1'.repeat(64) - await expect( - ownMevVault.updateState({ ...harvestParams, rewardsRoot: invalidRoot }) - ).to.be.revertedWithCustomError(keeper, 'InvalidRewardsRoot') - }) - - it('ignores unlocked mev reward', async () => { - const sharedMevEscrowBalance = ethers.parseEther('1') - await setBalance(await sharedMevEscrow.getAddress(), sharedMevEscrowBalance) - await increaseTime(REWARDS_DELAY) - - // update rewards root - const newReward = ethers.parseEther('10') - const vaultReward = getHarvestParams( - await ownMevVault.getAddress(), - newReward, - sharedMevEscrowBalance - ) - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper, { - nonce: globalRewardsNonce, - updateTimestamp: 1680255895, - }) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: rewardsUpdate.root, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - }) - const harvestParams = { - rewardsRoot: rewardsUpdate.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(rewardsUpdate.tree, vaultReward), - } - - const receipt = await ownMevVault.updateState(harvestParams) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs(await ownMevVault.getAddress(), harvestParams.rewardsRoot, newReward, 0) - expect(await ethers.provider.getBalance(await sharedMevEscrow.getAddress())).to.equal( - sharedMevEscrowBalance - ) - }) - - it('succeeds for latest rewards root', async () => { - const receipt = await ownMevVault.updateState(harvestParams) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs(await ownMevVault.getAddress(), harvestParams.rewardsRoot, newReward, 0n) - - const rewards = await keeper.rewards(await ownMevVault.getAddress()) - expect(rewards.nonce).to.equal(globalRewardsNonce) - expect(rewards.assets).to.equal(harvestParams.reward) - - const unlockedMevRewards = await keeper.unlockedMevRewards(await ownMevVault.getAddress()) - expect(unlockedMevRewards.nonce).to.equal(0) - expect(unlockedMevRewards.assets).to.equal(0) - - expect(await keeper.isCollateralized(await ownMevVault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await ownMevVault.getAddress())).to.equal(false) - expect(await keeper.isHarvestRequired(await ownMevVault.getAddress())).to.equal(false) - await snapshotGasCost(receipt) - - // does not fail for harvesting twice - const mevEscrow = await ownMevVault.mevEscrow() - await other.sendTransaction({ - to: mevEscrow, - value: ethers.parseEther('5'), - }) - const totalAssets = await ownMevVault.totalAssets() - const ownMevEscrowAssets = await ethers.provider.getBalance(mevEscrow) - await expect(await ownMevVault.updateState(harvestParams)).to.not.emit(keeper, 'Harvested') - expect(await ethers.provider.getBalance(mevEscrow)).to.equal(ownMevEscrowAssets) - expect(await ownMevVault.totalAssets()).to.equal(totalAssets) - }) - - it('succeeds for previous rewards root', async () => { - const prevReward = newReward - const prevHarvestParams = harvestParams - await increaseTime(REWARDS_DELAY) - - // update rewards root - const vaultReward = getHarvestParams( - await ownMevVault.getAddress(), - ethers.parseEther('10'), - 0n - ) - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper, { - nonce: globalRewardsNonce, - updateTimestamp: 1680255895, - }) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: rewardsUpdate.root, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - }) - const currHarvestParams = { - rewardsRoot: rewardsUpdate.root, - reward: vaultReward.reward, - unlockedMevReward: 0n, - proof: getRewardsRootProof(rewardsUpdate.tree, vaultReward), - } - - let receipt = await ownMevVault.updateState(prevHarvestParams) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs(await ownMevVault.getAddress(), prevHarvestParams.rewardsRoot, prevReward, 0) - - let rewards = await keeper.rewards(await ownMevVault.getAddress()) - expect(rewards.nonce).to.equal(globalRewardsNonce) - expect(rewards.assets).to.equal(prevHarvestParams.reward) - - expect(await keeper.isCollateralized(await ownMevVault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await ownMevVault.getAddress())).to.equal(true) - expect(await keeper.isHarvestRequired(await ownMevVault.getAddress())).to.equal(false) - await snapshotGasCost(receipt) - - receipt = await ownMevVault.updateState(currHarvestParams) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs( - await ownMevVault.getAddress(), - currHarvestParams.rewardsRoot, - currHarvestParams.reward - BigInt(prevHarvestParams.reward), - 0 - ) - - rewards = await keeper.rewards(await ownMevVault.getAddress()) - expect(rewards.nonce).to.equal(globalRewardsNonce + 1) - expect(rewards.assets).to.equal(currHarvestParams.reward) - - expect(await keeper.isCollateralized(await ownMevVault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await ownMevVault.getAddress())).to.equal(false) - expect(await keeper.isHarvestRequired(await ownMevVault.getAddress())).to.equal(false) - await snapshotGasCost(receipt) - - // does not fail for harvesting twice - const mevEscrow = await ownMevVault.mevEscrow() - await other.sendTransaction({ - to: mevEscrow, - value: ethers.parseEther('5'), - }) - const totalAssets = await ownMevVault.totalAssets() - const ownMevEscrowAssets = await ethers.provider.getBalance(mevEscrow) - await expect(await ownMevVault.updateState(prevHarvestParams)).to.not.emit( - keeper, - 'Harvested' - ) - expect(await ethers.provider.getBalance(mevEscrow)).to.equal(ownMevEscrowAssets) - expect(await ownMevVault.totalAssets()).to.equal(totalAssets) - }) - }) - - describe('harvest (shared escrow)', () => { - let newReward: bigint - let newUnlockedReward: bigint - let harvestParams: IKeeperRewards.HarvestParamsStruct - let sharedMevVault: EthVault - let globalRewardsNonce: number - let sharedMevBalanceBefore: bigint - - beforeEach(async () => { - sharedMevVault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false - ) - newReward = ethers.parseEther('5') - newUnlockedReward = ethers.parseEther('2') - const vaultReward = getHarvestParams( - await sharedMevVault.getAddress(), - newReward, - newUnlockedReward - ) - const vaultRewards = [vaultReward] - for (let i = 1; i < 11; i++) { - const vlt = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true, - true - ) - const amount = ethers.parseEther(i.toString()) - vaultRewards.push({ - reward: amount, - unlockedMevReward: amount, - vault: await vlt.getAddress(), - }) - } - - globalRewardsNonce = Number(await keeper.rewardsNonce()) - const rewardsUpdate = await getKeeperRewardsUpdateData(vaultRewards, keeper, { - nonce: globalRewardsNonce, - }) - await increaseTime(REWARDS_DELAY) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: rewardsUpdate.root, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - }) - harvestParams = { - rewardsRoot: rewardsUpdate.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(rewardsUpdate.tree, vaultReward), - } - sharedMevBalanceBefore = await ethers.provider.getBalance(await sharedMevEscrow.getAddress()) - await setBalance( - await sharedMevEscrow.getAddress(), - sharedMevBalanceBefore + newUnlockedReward - ) - globalRewardsNonce += 1 - expect(await keeper.rewardsNonce()).to.eq(globalRewardsNonce) - }) - - it('only vault can harvest', async () => { - await expect(keeper.harvest(harvestParams)).to.be.revertedWithCustomError( - keeper, - 'AccessDenied' - ) - }) - - it('fails for invalid unlocked MEV reward', async () => { - await expect( - sharedMevVault.updateState({ ...harvestParams, unlockedMevReward: 0n }) - ).to.be.revertedWithCustomError(keeper, 'InvalidProof') - }) - - it('fails for invalid proof', async () => { - await expect( - sharedMevVault.updateState({ ...harvestParams, proof: [] }) - ).to.be.revertedWithCustomError(keeper, 'InvalidProof') - }) - - it('fails for invalid root', async () => { - const invalidRoot = '0x' + '1'.repeat(64) - await expect( - sharedMevVault.updateState({ ...harvestParams, rewardsRoot: invalidRoot }) - ).to.be.revertedWithCustomError(keeper, 'InvalidRewardsRoot') - }) - - it('succeeds for latest rewards root', async () => { - const receipt = await sharedMevVault.updateState(harvestParams) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs( - await sharedMevVault.getAddress(), - harvestParams.rewardsRoot, - newReward, - newUnlockedReward - ) - expect(await ethers.provider.getBalance(await sharedMevEscrow.getAddress())).to.equal( - sharedMevBalanceBefore - ) - await expect(receipt) - .to.emit(sharedMevEscrow, 'Harvested') - .withArgs(await sharedMevVault.getAddress(), newUnlockedReward) - - const rewards = await keeper.rewards(await sharedMevVault.getAddress()) - expect(rewards.nonce).to.equal(globalRewardsNonce) - expect(rewards.assets).to.equal(harvestParams.reward) - - const unlockedMevRewards = await keeper.unlockedMevRewards(await sharedMevVault.getAddress()) - expect(unlockedMevRewards.nonce).to.equal(globalRewardsNonce) - expect(unlockedMevRewards.assets).to.equal(harvestParams.unlockedMevReward) - - expect(await keeper.isCollateralized(await sharedMevVault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await sharedMevVault.getAddress())).to.equal(false) - expect(await keeper.isHarvestRequired(await sharedMevVault.getAddress())).to.equal(false) - await snapshotGasCost(receipt) - - // does not fail for harvesting twice - await expect(await sharedMevVault.updateState(harvestParams)).to.not.emit(keeper, 'Harvested') - }) - - it('succeeds for previous rewards root', async () => { - const prevHarvestParams = harvestParams - await increaseTime(REWARDS_DELAY) - - // update rewards root - const vaultReward = getHarvestParams( - await sharedMevVault.getAddress(), - ethers.parseEther('10'), - ethers.parseEther('6') - ) - await setBalance( - await sharedMevEscrow.getAddress(), - sharedMevBalanceBefore + ethers.parseEther('6') - ) - const rewardsUpdate = await getKeeperRewardsUpdateData([vaultReward], keeper, { - nonce: globalRewardsNonce, - updateTimestamp: 1680255895, - }) - await keeper.connect(oracle).updateRewards({ - rewardsRoot: rewardsUpdate.root, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - }) - const currHarvestParams = { - rewardsRoot: rewardsUpdate.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(rewardsUpdate.tree, vaultReward), - } - - let receipt = await sharedMevVault.updateState(prevHarvestParams) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs( - await sharedMevVault.getAddress(), - prevHarvestParams.rewardsRoot, - newReward, - newUnlockedReward - ) - expect(await ethers.provider.getBalance(await sharedMevEscrow.getAddress())).to.equal( - sharedMevBalanceBefore + ethers.parseEther('4') - ) - await expect(receipt) - .to.emit(sharedMevEscrow, 'Harvested') - .withArgs(await sharedMevVault.getAddress(), ethers.parseEther('2')) - - let rewards = await keeper.rewards(await sharedMevVault.getAddress()) - expect(rewards.nonce).to.equal(globalRewardsNonce) - expect(rewards.assets).to.equal(prevHarvestParams.reward) - - expect(await keeper.isCollateralized(await sharedMevVault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await sharedMevVault.getAddress())).to.equal(true) - expect(await keeper.isHarvestRequired(await sharedMevVault.getAddress())).to.equal(false) - await snapshotGasCost(receipt) - - receipt = await sharedMevVault.updateState(currHarvestParams) - const sharedMevDelta = - currHarvestParams.unlockedMevReward - BigInt(prevHarvestParams.unlockedMevReward) - await expect(receipt) - .to.emit(keeper, 'Harvested') - .withArgs( - await sharedMevVault.getAddress(), - currHarvestParams.rewardsRoot, - currHarvestParams.reward - BigInt(prevHarvestParams.reward), - sharedMevDelta - ) - await expect(receipt) - .to.emit(sharedMevEscrow, 'Harvested') - .withArgs(await sharedMevVault.getAddress(), sharedMevDelta) - expect(await ethers.provider.getBalance(await sharedMevEscrow.getAddress())).to.equal( - sharedMevBalanceBefore - ) - - rewards = await keeper.rewards(await sharedMevVault.getAddress()) - expect(rewards.nonce).to.equal(globalRewardsNonce + 1) - expect(rewards.assets).to.equal(currHarvestParams.reward) - - expect(await keeper.isCollateralized(await sharedMevVault.getAddress())).to.equal(true) - expect(await keeper.canHarvest(await sharedMevVault.getAddress())).to.equal(false) - expect(await keeper.isHarvestRequired(await sharedMevVault.getAddress())).to.equal(false) - await snapshotGasCost(receipt) - - // does not fail for harvesting twice - await expect(await sharedMevVault.updateState(harvestParams)).to.not.emit(keeper, 'Harvested') - }) - }) - - describe('set min rewards oracles', () => { - it('fails if not owner', async () => { - await expect(keeper.connect(other).setRewardsMinOracles(1)).revertedWithCustomError( - keeper, - 'OwnableUnauthorizedAccount' - ) - }) - - it('fails with number larger than total oracles', async () => { - await expect( - keeper.connect(dao).setRewardsMinOracles(ORACLES.length + 1) - ).revertedWithCustomError(keeper, 'InvalidOracles') - }) - - it('fails with zero', async () => { - await expect(keeper.connect(dao).setRewardsMinOracles(0)).revertedWithCustomError( - keeper, - 'InvalidOracles' - ) - }) - - it('succeeds', async () => { - const receipt = await keeper.connect(dao).setRewardsMinOracles(1) - await expect(receipt).to.emit(keeper, 'RewardsMinOraclesUpdated').withArgs(1) - expect(await keeper.rewardsMinOracles()).to.be.eq(1) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/KeeperValidators.spec.ts b/test/KeeperValidators.spec.ts deleted file mode 100644 index 528b01e1..00000000 --- a/test/KeeperValidators.spec.ts +++ /dev/null @@ -1,633 +0,0 @@ -import { ethers } from 'hardhat' -import { Contract, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { EthVault, IKeeperValidators, Keeper, DepositDataRegistry } from '../typechain-types' -import { ThenArg } from '../helpers/types' -import { ethVaultFixture, getOraclesSignatures } from './shared/fixtures' -import { expect } from './shared/expect' -import { - ORACLES, - VALIDATORS_DEADLINE, - VALIDATORS_MIN_ORACLES, - ZERO_ADDRESS, - ZERO_BYTES32, -} from './shared/constants' -import { - createEthValidatorsData, - EthValidatorsData, - exitSignatureIpfsHashes, - getEthValidatorsExitSignaturesSigningData, - getEthValidatorsSigningData, - getValidatorProof, - getValidatorsMultiProof, - getWithdrawalCredentials, - ValidatorsMultiProof, -} from './shared/validators' -import snapshotGasCost from './shared/snapshotGasCost' -import { collateralizeEthVault } from './shared/rewards' -import { getLatestBlockTimestamp, toHexString } from './shared/utils' - -describe('KeeperValidators', () => { - const capacity = ethers.parseEther('1000') - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - const referrer = ZERO_ADDRESS - const deadline = VALIDATORS_DEADLINE - const depositAmount = ethers.parseEther('32') - - let createVault: ThenArg>['createEthVault'] - - let sender: Wallet, dao: Wallet, admin: Wallet - let keeper: Keeper, - vault: EthVault, - validatorsRegistry: Contract, - depositDataRegistry: DepositDataRegistry - let validatorsData: EthValidatorsData - let validatorsRegistryRoot: string - - beforeEach(async () => { - ;[dao, sender, admin] = await (ethers as any).getSigners() - ;({ - keeper, - validatorsRegistry, - depositDataRegistry, - createEthVault: createVault, - } = await loadFixture(ethVaultFixture)) - vault = await createVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - false, - true - ) - validatorsData = await createEthValidatorsData(vault) - validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), validatorsData.root) - }) - - describe('register single validator', () => { - let validator: Buffer - let proof: string[] - let signingData: any - let approveParams: IKeeperValidators.ApprovalParamsStruct - - beforeEach(async () => { - validator = validatorsData.validators[0] - const exitSignatureIpfsHash = exitSignatureIpfsHashes[0] - proof = getValidatorProof(validatorsData.tree, validator, 0) - await vault.connect(sender).deposit(sender.address, referrer, { value: depositAmount }) - signingData = await getEthValidatorsSigningData( - validator, - deadline, - exitSignatureIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ) - approveParams = { - validatorsRegistryRoot, - validators: validator, - deadline, - signatures: getOraclesSignatures(signingData, ORACLES.length), - exitSignaturesIpfsHash: exitSignatureIpfsHash, - } - }) - - it('fails for invalid vault', async () => { - await expect(keeper.approveValidators(approveParams)).revertedWithCustomError( - keeper, - 'AccessDenied' - ) - }) - - it('fails for invalid validators registry root', async () => { - await validatorsRegistry.deposit( - validator.subarray(0, 48), - getWithdrawalCredentials(await vault.getAddress()), - validator.subarray(48, 144), - validator.subarray(144, 176), - { value: depositAmount } - ) - await expect( - depositDataRegistry.registerValidator(await vault.getAddress(), approveParams, proof) - ).revertedWithCustomError(keeper, 'InvalidValidatorsRegistryRoot') - }) - - it('fails for invalid signatures', async () => { - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - { - ...approveParams, - signatures: getOraclesSignatures(signingData, VALIDATORS_MIN_ORACLES - 1), - }, - proof - ) - ).revertedWithCustomError(keeper, 'NotEnoughSignatures') - }) - - it('fails for invalid deadline', async () => { - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - { - ...approveParams, - deadline: deadline + 1n, - }, - proof - ) - ).revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails for expired deadline', async () => { - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - { - ...approveParams, - deadline: await getLatestBlockTimestamp(), - }, - proof - ) - ).revertedWithCustomError(keeper, 'DeadlineExpired') - }) - - it('fails for invalid validator', async () => { - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - { - ...approveParams, - validators: validatorsData.validators[1], - }, - proof - ) - ).revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails for invalid proof', async () => { - await expect( - depositDataRegistry.registerValidator( - await vault.getAddress(), - approveParams, - getValidatorProof(validatorsData.tree, validatorsData.validators[1], 1) - ) - ).revertedWithCustomError(keeper, 'InvalidProof') - }) - - it('succeeds', async () => { - let rewards = await keeper.rewards(await vault.getAddress()) - expect(rewards.nonce).to.eq(0) - expect(rewards.assets).to.eq(0) - const globalRewardsNonce = await keeper.rewardsNonce() - - let receipt = await depositDataRegistry.registerValidator( - await vault.getAddress(), - approveParams, - proof - ) - await expect(receipt) - .to.emit(keeper, 'ValidatorsApproval') - .withArgs(await vault.getAddress(), approveParams.exitSignaturesIpfsHash) - - // collateralize vault - rewards = await keeper.rewards(await vault.getAddress()) - expect(rewards.nonce).to.eq(globalRewardsNonce) - expect(rewards.assets).to.eq(0) - - await snapshotGasCost(receipt) - - const newValidatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - - // fails to register twice - await expect( - depositDataRegistry.registerValidator(await vault.getAddress(), approveParams, proof) - ).revertedWithCustomError(keeper, 'InvalidValidatorsRegistryRoot') - - const newValidator = validatorsData.validators[1] - const newExitSignatureIpfsHash = exitSignatureIpfsHashes[1] - const newProof = getValidatorProof(validatorsData.tree, newValidator, 1) - await vault.connect(sender).deposit(sender.address, referrer, { value: depositAmount }) - - const newSigningData = await getEthValidatorsSigningData( - newValidator, - deadline, - newExitSignatureIpfsHash, - keeper, - vault, - newValidatorsRegistryRoot - ) - const newSignatures = getOraclesSignatures(newSigningData, ORACLES.length) - receipt = await depositDataRegistry.registerValidator( - await vault.getAddress(), - { - validatorsRegistryRoot: newValidatorsRegistryRoot, - validators: newValidator, - signatures: newSignatures, - exitSignaturesIpfsHash: newExitSignatureIpfsHash, - deadline, - }, - newProof - ) - - // doesn't collateralize twice - rewards = await keeper.rewards(await vault.getAddress()) - expect(rewards.nonce).to.eq(globalRewardsNonce) - expect(rewards.assets).to.eq(0) - - await snapshotGasCost(receipt) - }) - }) - - describe('register multiple validators', () => { - let validators: Buffer[] - let indexes: number[] - let proof: ValidatorsMultiProof - let signingData: any - let approveParams: IKeeperValidators.ApprovalParamsStruct - - beforeEach(async () => { - proof = getValidatorsMultiProof(validatorsData.tree, validatorsData.validators, [ - ...Array(validatorsData.validators.length).keys(), - ]) - validators = validatorsData.validators - const sortedVals = proof.leaves.map((v) => v[0]) - indexes = validators.map((v) => sortedVals.indexOf(v)) - await vault - .connect(sender) - .deposit(sender.address, referrer, { value: depositAmount * BigInt(validators.length) }) - const exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - - signingData = await getEthValidatorsSigningData( - Buffer.concat(validators), - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ) - approveParams = { - validatorsRegistryRoot, - validators: toHexString(Buffer.concat(validators)), - signatures: getOraclesSignatures(signingData, ORACLES.length), - exitSignaturesIpfsHash, - deadline, - } - }) - - it('fails for invalid vault', async () => { - await expect(keeper.approveValidators(approveParams)).revertedWithCustomError( - keeper, - 'AccessDenied' - ) - }) - - it('fails for invalid validators registry root', async () => { - const validator = validators[0] - await validatorsRegistry.deposit( - validator.subarray(0, 48), - getWithdrawalCredentials(await vault.getAddress()), - validator.subarray(48, 144), - validator.subarray(144, 176), - { value: depositAmount } - ) - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approveParams, - indexes, - proof.proofFlags, - proof.proof - ) - ).revertedWithCustomError(keeper, 'InvalidValidatorsRegistryRoot') - }) - - it('fails for invalid signatures', async () => { - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - ...approveParams, - signatures: getOraclesSignatures(signingData, VALIDATORS_MIN_ORACLES - 1), - }, - indexes, - proof.proofFlags, - proof.proof - ) - ).revertedWithCustomError(keeper, 'NotEnoughSignatures') - }) - - it('fails for invalid validators', async () => { - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - ...approveParams, - validators: validators[0], - }, - indexes, - proof.proofFlags, - proof.proof - ) - ).revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails for invalid deadline', async () => { - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - ...approveParams, - deadline: deadline + 1n, - }, - indexes, - proof.proofFlags, - proof.proof - ) - ).revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails for expired deadline', async () => { - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - ...approveParams, - deadline: await getLatestBlockTimestamp(), - }, - indexes, - proof.proofFlags, - proof.proof - ) - ).revertedWithCustomError(keeper, 'DeadlineExpired') - }) - - it('fails for invalid proof', async () => { - const invalidProof = getValidatorsMultiProof(validatorsData.tree, [validators[0]], [0]) - const exitSignaturesIpfsHash = approveParams.exitSignaturesIpfsHash as string - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot, - deadline, - validators: validators[1], - exitSignaturesIpfsHash, - signatures: getOraclesSignatures( - await getEthValidatorsSigningData( - validators[1], - deadline, - exitSignaturesIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ), - ORACLES.length - ), - }, - [0], - invalidProof.proofFlags, - invalidProof.proof - ) - ).revertedWithCustomError(keeper, 'InvalidProof') - }) - - it('succeeds', async () => { - let rewards = await keeper.rewards(await vault.getAddress()) - expect(rewards.nonce).to.eq(0) - expect(rewards.assets).to.eq(0) - const validatorsConcat = Buffer.concat(validators) - const globalRewardsNonce = await keeper.rewardsNonce() - - let receipt = await depositDataRegistry.registerValidators( - await vault.getAddress(), - approveParams, - indexes, - proof.proofFlags, - proof.proof - ) - await expect(receipt) - .to.emit(keeper, 'ValidatorsApproval') - .withArgs(await vault.getAddress(), approveParams.exitSignaturesIpfsHash) - - rewards = await keeper.rewards(await vault.getAddress()) - expect(rewards.nonce).to.eq(globalRewardsNonce) - expect(rewards.assets).to.eq(0) - - await snapshotGasCost(receipt) - - const newValidatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - - // fails to register twice - await expect( - depositDataRegistry.registerValidators( - await vault.getAddress(), - approveParams, - indexes, - proof.proofFlags, - proof.proof - ) - ).revertedWithCustomError(keeper, 'InvalidValidatorsRegistryRoot') - - await vault - .connect(sender) - .deposit(sender.address, referrer, { value: depositAmount * BigInt(validators.length) }) - - // reset validator index - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), ZERO_BYTES32) - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), validatorsData.root) - const newSigningData = await getEthValidatorsSigningData( - validatorsConcat, - deadline, - approveParams.exitSignaturesIpfsHash as string, - keeper, - vault, - newValidatorsRegistryRoot - ) - const newSignatures = getOraclesSignatures(newSigningData, ORACLES.length) - receipt = await depositDataRegistry.registerValidators( - await vault.getAddress(), - { - validatorsRegistryRoot: newValidatorsRegistryRoot, - deadline, - validators: validatorsConcat, - signatures: newSignatures, - exitSignaturesIpfsHash: approveParams.exitSignaturesIpfsHash, - }, - indexes, - proof.proofFlags, - proof.proof - ) - - // doesn't collateralize twice - rewards = await keeper.rewards(await vault.getAddress()) - expect(rewards.nonce).to.eq(globalRewardsNonce) - expect(rewards.assets).to.eq(0) - - await snapshotGasCost(receipt) - }) - }) - - describe('update exit signatures', () => { - let exitSignaturesIpfsHash: string - let oraclesSignatures: Buffer - let signingData: any - let deadline: number - - beforeEach(async () => { - exitSignaturesIpfsHash = exitSignatureIpfsHashes[0] - deadline = Math.floor(Date.now() / 1000) + 10000000 - signingData = await getEthValidatorsExitSignaturesSigningData( - keeper, - vault, - deadline, - exitSignaturesIpfsHash, - 0 - ) - oraclesSignatures = getOraclesSignatures(signingData, ORACLES.length) - }) - - it('fails for invalid vault', async () => { - await expect( - keeper.updateExitSignatures( - await keeper.getAddress(), - deadline, - exitSignaturesIpfsHash, - oraclesSignatures - ) - ).revertedWithCustomError(keeper, 'InvalidVault') - }) - - it('fails for not collateralized vault', async () => { - await expect( - keeper.updateExitSignatures( - await vault.getAddress(), - deadline, - exitSignaturesIpfsHash, - oraclesSignatures - ) - ).revertedWithCustomError(keeper, 'InvalidVault') - }) - - it('fails for invalid signatures', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await expect( - keeper.updateExitSignatures( - await vault.getAddress(), - deadline, - exitSignaturesIpfsHash, - getOraclesSignatures(signingData, VALIDATORS_MIN_ORACLES - 1) - ) - ).revertedWithCustomError(keeper, 'NotEnoughSignatures') - }) - - it('fails for invalid deadline', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await expect( - keeper.updateExitSignatures( - await vault.getAddress(), - deadline + 1, - exitSignaturesIpfsHash, - oraclesSignatures - ) - ).revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('fails for expired deadline', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - const newDeadline = await getLatestBlockTimestamp() - const newSigningData = await getEthValidatorsExitSignaturesSigningData( - keeper, - vault, - newDeadline, - exitSignaturesIpfsHash, - 0 - ) - await expect( - keeper.updateExitSignatures( - await vault.getAddress(), - newDeadline, - exitSignaturesIpfsHash, - getOraclesSignatures(newSigningData, ORACLES.length) - ) - ).revertedWithCustomError(keeper, 'DeadlineExpired') - }) - - it('fails to submit update twice', async () => { - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - await keeper.updateExitSignatures( - await vault.getAddress(), - deadline, - exitSignaturesIpfsHash, - oraclesSignatures - ) - - await expect( - keeper.updateExitSignatures( - await vault.getAddress(), - deadline, - exitSignaturesIpfsHash, - oraclesSignatures - ) - ).revertedWithCustomError(keeper, 'InvalidOracle') - }) - - it('succeeds', async () => { - const nonce = await keeper.exitSignaturesNonces(await vault.getAddress()) - expect(nonce).to.eq(0) - - await collateralizeEthVault(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - const receipt = await keeper - .connect(sender) - .updateExitSignatures( - await vault.getAddress(), - deadline, - exitSignaturesIpfsHash, - oraclesSignatures - ) - await expect(receipt) - .to.emit(keeper, 'ExitSignaturesUpdated') - .withArgs(sender.address, await vault.getAddress(), nonce, exitSignaturesIpfsHash) - expect(await keeper.exitSignaturesNonces(await vault.getAddress())).to.eq(nonce + 1n) - }) - }) - - describe('set validators oracles', () => { - it('fails if not owner', async () => { - await expect(keeper.connect(sender).setValidatorsMinOracles(1)).revertedWithCustomError( - keeper, - 'OwnableUnauthorizedAccount' - ) - }) - - it('fails with number larger than total oracles', async () => { - await expect( - keeper.connect(dao).setValidatorsMinOracles(ORACLES.length + 1) - ).revertedWithCustomError(keeper, 'InvalidOracles') - }) - - it('fails with zero', async () => { - await expect(keeper.connect(dao).setValidatorsMinOracles(0)).revertedWithCustomError( - keeper, - 'InvalidOracles' - ) - }) - - it('succeeds', async () => { - const receipt = await keeper.connect(dao).setValidatorsMinOracles(1) - await expect(receipt).to.emit(keeper, 'ValidatorsMinOraclesUpdated').withArgs(1) - expect(await keeper.validatorsMinOracles()).to.be.eq(1) - await snapshotGasCost(receipt) - }) - }) -}) diff --git a/test/MainnetFork.t.sol b/test/MainnetFork.t.sol deleted file mode 100644 index ba606093..00000000 --- a/test/MainnetFork.t.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {Test} from '../lib/forge-std/src/Test.sol'; -import {ForkTest} from './Fork.t.sol'; - - -abstract contract MainnetForkTest is Test, ForkTest { - - function setUp() public virtual { - forkBlockNumber = 21737000; - - keeper = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; - validatorsRegistry = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - vaultsRegistry = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; - osTokenVaultController = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; - osTokenConfig = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; - osTokenVaultEscrow = 0x09e84205DF7c68907e619D07aFD90143c5763605; - sharedMevEscrow = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; - depositDataRegistry = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; - exitingAssetsClaimDelay = 24 hours; - v2VaultFactory = 0xfaa05900019f6E465086bcE16Bb3F06992715D53; - erc20VaultFactory = 0x978302cAcAdEDE5d503390E176e86F3889Df6Ce6; - vaultV3Impl = 0x9747e1fF73f1759217AFD212Dd36d21360D0880A; - genesisVault = 0xAC0F906E433d58FA868F936E8A43230473652885; - poolEscrow = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; - rewardEthToken = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; - - vm.createSelectFork(vm.envString('MAINNET_RPC_URL'), forkBlockNumber); - } -} diff --git a/test/OsToken.spec.ts b/test/OsToken.spec.ts deleted file mode 100644 index 9b3d5c64..00000000 --- a/test/OsToken.spec.ts +++ /dev/null @@ -1,582 +0,0 @@ -import { ethers, network } from 'hardhat' -import { Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - OsTokenVaultController, - OsToken, - EthVault, - Keeper, - DepositDataRegistry, -} from '../typechain-types' -import snapshotGasCost from './shared/snapshotGasCost' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { - EIP712Domain, - MAX_UINT256, - ONE_DAY, - OSTOKEN_NAME, - OSTOKEN_SYMBOL, - PermitSig, - ZERO_ADDRESS, -} from './shared/constants' -import { collateralizeEthVault, setAvgRewardPerSecond } from './shared/rewards' -import EthereumWallet from 'ethereumjs-wallet' -import { - domainSeparator, - getSignatureFromTypedData, - increaseTime, - getLatestBlockTimestamp, -} from './shared/utils' - -describe('OsToken', () => { - const assets = ethers.parseEther('2') - const initialHolderShares = 1000n - let initialSupply: bigint - let initialHolder: Wallet, spender: Wallet, admin: Signer, dao: Wallet, recipient: Wallet - let osTokenVaultController: OsTokenVaultController, - osToken: OsToken, - vault: EthVault, - keeper: Keeper, - depositDataRegistry: DepositDataRegistry - - before('create fixture loader', async () => { - ;[dao, initialHolder, admin, spender, recipient] = await (ethers as any).getSigners() - }) - - beforeEach('deploy fixture', async () => { - const fixture = await loadFixture(ethVaultFixture) - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - osTokenVaultController = fixture.osTokenVaultController - keeper = fixture.keeper - osToken = fixture.osToken - depositDataRegistry = fixture.depositDataRegistry - - vault = await fixture.createEthVault(admin, vaultParams) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - // collateralize vault - await collateralizeEthVault( - vault, - fixture.keeper, - depositDataRegistry, - admin, - fixture.validatorsRegistry - ) - await vault - .connect(initialHolder) - .deposit(initialHolder.address, ZERO_ADDRESS, { value: assets }) - await vault - .connect(initialHolder) - .mintOsToken(initialHolder.address, initialHolderShares, ZERO_ADDRESS) - initialSupply = await osToken.totalSupply() - }) - - describe('capacity', () => { - it('not owner cannot change', async () => { - await expect( - osTokenVaultController.connect(initialHolder).setCapacity(0) - ).to.be.revertedWithCustomError(osToken, 'OwnableUnauthorizedAccount') - }) - - it('owner can change', async () => { - const receipt = await osTokenVaultController.connect(dao).setCapacity(0) - await expect(receipt).to.emit(osTokenVaultController, 'CapacityUpdated').withArgs(0) - expect(await osTokenVaultController.capacity()).to.eq(0) - await snapshotGasCost(receipt) - }) - }) - - describe('treasury', () => { - it('not owner cannot change', async () => { - await expect( - osTokenVaultController.connect(initialHolder).setTreasury(dao.address) - ).to.be.revertedWithCustomError(osToken, 'OwnableUnauthorizedAccount') - }) - - it('cannot set to zero address', async () => { - await expect( - osTokenVaultController.connect(dao).setTreasury(ZERO_ADDRESS) - ).to.be.revertedWithCustomError(osToken, 'ZeroAddress') - }) - - it('owner can change', async () => { - const receipt = await osTokenVaultController.connect(dao).setTreasury(dao.address) - await expect(receipt).to.emit(osTokenVaultController, 'TreasuryUpdated').withArgs(dao.address) - expect(await osTokenVaultController.treasury()).to.eq(dao.address) - await snapshotGasCost(receipt) - }) - }) - - describe('controllers', () => { - it('not owner cannot change', async () => { - await expect( - osToken.connect(initialHolder).setController(dao.address, true) - ).to.be.revertedWithCustomError(osToken, 'OwnableUnauthorizedAccount') - }) - - it('cannot set to zero address', async () => { - await expect( - osToken.connect(dao).setController(ZERO_ADDRESS, true) - ).to.be.revertedWithCustomError(osToken, 'ZeroAddress') - }) - - it('owner can change', async () => { - let receipt = await osToken.connect(dao).setController(dao.address, true) - await expect(receipt).to.emit(osToken, 'ControllerUpdated').withArgs(dao.address, true) - expect(await osToken.controllers(dao.address)).to.eq(true) - await snapshotGasCost(receipt) - - receipt = await osToken.connect(dao).setController(dao.address, false) - await expect(receipt).to.emit(osToken, 'ControllerUpdated').withArgs(dao.address, false) - expect(await osToken.controllers(dao.address)).to.eq(false) - await snapshotGasCost(receipt) - }) - - it('not controller cannot mint', async () => { - await expect( - osToken.connect(initialHolder).mint(dao.address, 1) - ).to.be.revertedWithCustomError(osToken, 'AccessDenied') - }) - - it('controller can mint', async () => { - await osToken.connect(dao).setController(initialHolder.address, true) - const receipt = await osToken.connect(initialHolder).mint(recipient.address, 1) - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(ZERO_ADDRESS, recipient.address, 1) - expect(await osToken.balanceOf(recipient.address)).to.eq(1) - }) - - it('not controller cannot burn', async () => { - await expect( - osToken.connect(initialHolder).burn(dao.address, 1) - ).to.be.revertedWithCustomError(osToken, 'AccessDenied') - }) - - it('controller can burn', async () => { - await osToken.connect(dao).setController(initialHolder.address, true) - await osToken.connect(initialHolder).mint(recipient.address, 1) - const receipt = await osToken.connect(initialHolder).burn(recipient.address, 1) - await expect(receipt) - .to.emit(osToken, 'Transfer') - .withArgs(recipient.address, ZERO_ADDRESS, 1) - expect(await osToken.balanceOf(recipient.address)).to.eq(0) - }) - }) - - describe('fee percent', () => { - it('not owner cannot change', async () => { - await expect( - osTokenVaultController.connect(initialHolder).setFeePercent(100) - ).to.be.revertedWithCustomError(osToken, 'OwnableUnauthorizedAccount') - }) - - it('cannot set to more than 100%', async () => { - await expect( - osTokenVaultController.connect(dao).setFeePercent(10001) - ).to.be.revertedWithCustomError(osTokenVaultController, 'InvalidFeePercent') - }) - - it('owner can change', async () => { - await setAvgRewardPerSecond(dao, vault, keeper, 1005987242) - await increaseTime(ONE_DAY * 1000) - const receipt = await osTokenVaultController.connect(dao).setFeePercent(100) - await expect(receipt).to.emit(osTokenVaultController, 'FeePercentUpdated').withArgs(100) - await expect(receipt).to.emit(osTokenVaultController, 'StateUpdated') - expect(await osTokenVaultController.feePercent()).to.eq(100) - await snapshotGasCost(receipt) - }) - }) - - describe('keeper', () => { - it('not owner cannot change', async () => { - await expect( - osTokenVaultController.connect(initialHolder).setKeeper(dao.address) - ).to.be.revertedWithCustomError(osTokenVaultController, 'OwnableUnauthorizedAccount') - }) - - it('cannot set to zero address', async () => { - await expect( - osTokenVaultController.connect(dao).setKeeper(ZERO_ADDRESS) - ).to.be.revertedWithCustomError(osTokenVaultController, 'ZeroAddress') - }) - - it('owner can change', async () => { - const receipt = await osTokenVaultController.connect(dao).setKeeper(dao.address) - await expect(receipt).to.emit(osTokenVaultController, 'KeeperUpdated').withArgs(dao.address) - expect(await osTokenVaultController.keeper()).to.eq(dao.address) - await snapshotGasCost(receipt) - }) - }) - - describe('avg reward per second', () => { - it('not owner cannot change', async () => { - await expect( - osTokenVaultController.connect(dao).setAvgRewardPerSecond(0) - ).to.be.revertedWithCustomError(osTokenVaultController, 'AccessDenied') - }) - }) - - it('has a name', async () => { - expect(await osToken.name()).to.eq(OSTOKEN_NAME) - }) - - it('has a symbol', async () => { - expect(await osToken.symbol()).to.eq(OSTOKEN_SYMBOL) - }) - - it('has 18 decimals', async () => { - expect(await osToken.decimals()).to.eq(18) - }) - - describe('total supply', () => { - it('returns the total amount of tokens', async () => { - expect(await osToken.totalSupply()).to.eq(initialSupply) - expect(await osTokenVaultController.totalShares()).to.eq(initialSupply) - }) - }) - - describe('balanceOf', () => { - describe('when the requested account has no tokens', () => { - it('returns zero', async () => { - expect(await osToken.balanceOf(spender.address)).to.eq(0) - }) - }) - - describe('when the requested account has some tokens', () => { - it('returns the total amount of tokens', async () => { - expect(await osToken.balanceOf(initialHolder.address)).to.eq(initialHolderShares) - }) - }) - }) - - describe('transfer', () => { - const balance = initialHolderShares - - it('reverts when the sender does not have enough balance', async () => { - const amount = balance + 1n - await expect( - osToken.connect(initialHolder).transfer(recipient.address, amount) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - - it('reverts with zero address recipient', async () => { - await expect( - osToken.connect(initialHolder).transfer(ZERO_ADDRESS, balance) - ).to.be.revertedWithCustomError(osToken, 'ERC20InvalidReceiver') - }) - - describe('when the sender transfers all balance', () => { - const amount = initialHolderShares - - it('transfers the requested amount', async () => { - const receipt = await osToken.connect(initialHolder).transfer(recipient.address, amount) - expect(await osToken.balanceOf(initialHolder.address)).to.eq(0) - expect(await osToken.balanceOf(recipient.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - - it('emits a transfer event', async () => { - await expect(osToken.connect(initialHolder).transfer(recipient.address, amount)) - .to.emit(osToken, 'Transfer') - .withArgs(initialHolder.address, recipient.address, amount) - }) - }) - - describe('when the sender transfers zero tokens', () => { - const amount = 0 - const balance = initialHolderShares - - it('transfers the requested amount', async () => { - const receipt = await osToken.connect(initialHolder).transfer(recipient.address, amount) - expect(await osToken.balanceOf(initialHolder.address)).to.eq(balance) - expect(await osToken.balanceOf(recipient.address)).to.eq(0) - await snapshotGasCost(receipt) - }) - - it('emits a transfer event', async () => { - await expect(osToken.connect(initialHolder).transfer(recipient.address, amount)) - .to.emit(osToken, 'Transfer') - .withArgs(initialHolder.address, recipient.address, amount) - }) - }) - }) - - describe('transfer from', () => { - describe('when the spender has enough allowance', () => { - beforeEach(async () => { - await osToken.connect(initialHolder).approve(spender.address, initialHolderShares) - }) - - describe('when the token owner has enough balance', () => { - const amount = initialHolderShares - - it('transfers the requested amount', async () => { - const receipt = await osToken - .connect(spender) - .transferFrom(initialHolder.address, spender.address, amount) - expect(await osToken.balanceOf(initialHolder.address)).to.eq(0) - expect(await osToken.balanceOf(spender.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - - it('decreases the spender allowance', async () => { - await osToken - .connect(spender) - .transferFrom(initialHolder.address, spender.address, amount) - expect(await osToken.allowance(initialHolder.address, spender.address)).to.eq(0) - }) - - it('emits a transfer event', async () => { - await expect( - osToken.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ) - .emit(osToken, 'Transfer') - .withArgs(initialHolder.address, spender.address, amount) - }) - }) - - describe('when the token owner does not have enough balance', () => { - const amount = initialHolderShares - - beforeEach('reducing balance', async () => { - await osToken.connect(initialHolder).transfer(spender.address, 1) - }) - - it('reverts', async () => { - await expect( - osToken.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - }) - }) - - describe('when the spender does not have enough allowance', () => { - const allowance = initialHolderShares - 1n - - beforeEach(async () => { - await osToken.connect(initialHolder).approve(spender.address, allowance) - }) - - describe('when the token owner has enough balance', () => { - const amount = initialHolderShares - - it('reverts', async () => { - await expect( - osToken.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientAllowance') - }) - }) - - describe('when the token owner does not have enough balance', () => { - const amount = allowance - - beforeEach('reducing balance', async () => { - await osToken.connect(initialHolder).transfer(spender.address, 2) - }) - - it('reverts', async () => { - await expect( - osToken.connect(spender).transferFrom(initialHolder.address, spender.address, amount) - ).to.be.revertedWithCustomError(osToken, 'ERC20InsufficientBalance') - }) - }) - }) - - describe('when the spender has unlimited allowance', () => { - beforeEach(async () => { - await osToken.connect(initialHolder).approve(spender.address, MAX_UINT256) - }) - - it('does not decrease the spender allowance', async () => { - const receipt = await osToken - .connect(spender) - .transferFrom(initialHolder.address, spender.address, 1) - expect(await osToken.allowance(initialHolder.address, spender.address)).to.eq(MAX_UINT256) - await snapshotGasCost(receipt) - }) - }) - }) - - describe('approve', () => { - it('fails to approve zero address', async () => { - const amount = ethers.parseEther('1') - await expect( - osToken.connect(initialHolder).approve(ZERO_ADDRESS, amount) - ).to.be.revertedWithCustomError(osToken, 'ERC20InvalidSpender') - }) - - describe('when the sender has enough balance', () => { - const amount = initialHolderShares - - it('emits an approval event', async () => { - await expect(osToken.connect(initialHolder).approve(spender.address, amount)) - .emit(osToken, 'Approval') - .withArgs(initialHolder.address, spender.address, amount) - }) - - describe('when there was no approved amount before', () => { - it('approves the requested amount', async () => { - const receipt = await osToken.connect(initialHolder).approve(spender.address, amount) - expect(await osToken.allowance(initialHolder.address, spender.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - }) - - describe('when the spender had an approved amount', () => { - beforeEach(async () => { - await osToken.connect(initialHolder).approve(spender.address, 1) - }) - - it('approves the requested amount and replaces the previous one', async () => { - const receipt = await osToken.connect(initialHolder).approve(spender.address, amount) - expect(await osToken.allowance(initialHolder.address, spender.address)).to.eq(amount) - await snapshotGasCost(receipt) - }) - }) - }) - - describe('when the sender does not have enough balance', () => { - const amount = initialHolderShares + 1n - - it('emits an approval event', async () => { - await expect(osToken.connect(initialHolder).approve(spender.address, amount)) - .emit(osToken, 'Approval') - .withArgs(initialHolder.address, spender.address, amount) - }) - - describe('when there was no approved amount before', () => { - it('approves the requested amount', async () => { - await osToken.connect(initialHolder).approve(spender.address, amount) - expect(await osToken.allowance(initialHolder.address, spender.address)).to.eq(amount) - }) - }) - - describe('when the spender had an approved amount', () => { - beforeEach(async () => { - await osToken.connect(initialHolder).approve(spender.address, 1) - }) - - it('approves the requested amount and replaces the previous one', async () => { - await osToken.connect(initialHolder).approve(spender.address, amount) - - expect(await osToken.allowance(initialHolder.address, spender.address)).to.eq(amount) - }) - }) - }) - }) - - describe('permit', () => { - const value = 42 - const nonce = 0 - const maxDeadline = MAX_UINT256.toString() - const chainId = network.config.chainId - - const owner = new EthereumWallet( - Buffer.from( - ethers.getBytes('0x35a1c4d02b06d93778758410e5c09e010760268cf98b1af33c2d0646f27a8b70') - ) - ) - const ownerAddress = owner.getChecksumAddressString() - const ownerPrivateKey = owner.getPrivateKey() - - const buildData = async (deadline = maxDeadline, spender) => ({ - primaryType: 'Permit', - types: { EIP712Domain, Permit: PermitSig }, - domain: { - name: OSTOKEN_NAME, - version: '1', - chainId, - verifyingContract: await osToken.getAddress(), - }, - message: { owner: ownerAddress, spender, value, nonce, deadline }, - }) - - it('initial nonce is 0', async () => { - expect(await osToken.nonces(ownerAddress)).to.eq(0) - }) - - it('domain separator', async () => { - expect(await osToken.DOMAIN_SEPARATOR()).to.equal( - await domainSeparator(OSTOKEN_NAME, '1', chainId, await osToken.getAddress()) - ) - }) - - it('accepts owner signature', async () => { - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(maxDeadline, spender.address) - ) - - const receipt = await osToken.permit( - ownerAddress, - spender.address, - value, - maxDeadline, - v, - r, - s - ) - await snapshotGasCost(receipt) - - await expect(receipt) - .to.emit(osToken, 'Approval') - .withArgs(ownerAddress, spender.address, value) - - expect(await osToken.nonces(ownerAddress)).to.eq('1') - expect(await osToken.allowance(ownerAddress, spender.address)).to.eq(value) - }) - - it('rejects reused signature', async () => { - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(maxDeadline, spender.address) - ) - - await osToken.permit(ownerAddress, spender.address, value, maxDeadline, v, r, s) - - await expect( - osToken.permit(initialHolder.address, spender.address, value, maxDeadline, v, r, s) - ).to.be.revertedWithCustomError(osToken, 'ERC2612InvalidSigner') - }) - - it('rejects other signature', async () => { - const otherWallet = EthereumWallet.generate() - const data = await buildData(maxDeadline, spender.address) - const { v, r, s } = getSignatureFromTypedData(otherWallet.getPrivateKey(), data) - - await expect( - osToken.permit(ownerAddress, spender.address, value, maxDeadline, v, r, s) - ).to.be.revertedWithCustomError(osToken, 'ERC2612InvalidSigner') - }) - - it('rejects expired permit', async () => { - const deadline = ((await getLatestBlockTimestamp()) - 500).toString() - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(deadline, spender.address) - ) - - await expect( - osToken.permit(ownerAddress, spender.address, value, deadline, v, r, s) - ).to.be.revertedWithCustomError(osToken, 'ERC2612ExpiredSignature') - }) - - it('rejects zero address', async () => { - const deadline = ((await getLatestBlockTimestamp()) - 500).toString() - const { v, r, s } = getSignatureFromTypedData( - ownerPrivateKey, - await buildData(deadline, ZERO_ADDRESS) - ) - - await expect( - osToken.permit(ownerAddress, ZERO_ADDRESS, value, deadline, v, r, s) - ).to.be.revertedWithCustomError(osToken, 'ERC2612ExpiredSignature') - }) - }) -}) diff --git a/test/OsTokenConfig.spec.ts b/test/OsTokenConfig.spec.ts deleted file mode 100644 index 5f3be4fc..00000000 --- a/test/OsTokenConfig.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { ethers } from 'hardhat' -import { parseEther, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { OsTokenConfig } from '../typechain-types' -import { ethVaultFixture } from './shared/fixtures' -import { expect } from './shared/expect' -import { - OSTOKEN_LIQ_BONUS, - OSTOKEN_LIQ_THRESHOLD, - OSTOKEN_LTV, - ZERO_ADDRESS, - MAX_UINT64, -} from './shared/constants' -import snapshotGasCost from './shared/snapshotGasCost' -import { MAINNET_FORK } from '../helpers/constants' - -describe('OsTokenConfig', () => { - const newConfig = { - liqThresholdPercent: OSTOKEN_LIQ_THRESHOLD + 1n, - liqBonusPercent: OSTOKEN_LIQ_BONUS + 1n, - ltvPercent: OSTOKEN_LTV + 1n, - } - const maxPercent = parseEther('1') - let dao: Wallet, other: Wallet - let osTokenConfig: OsTokenConfig - - beforeEach('deploy fixtures', async () => { - ;[dao, other] = await (ethers as any).getSigners() - ;({ osTokenConfig } = await loadFixture(ethVaultFixture)) - }) - - it('updates in constructor', async () => { - if (MAINNET_FORK.enabled) return - const config = await osTokenConfig.getConfig(ZERO_ADDRESS) - expect(config.liqThresholdPercent).to.be.eq(OSTOKEN_LIQ_THRESHOLD) - expect(config.liqBonusPercent).to.be.eq(OSTOKEN_LIQ_BONUS) - expect(config.ltvPercent).to.be.eq(OSTOKEN_LTV) - expect(await osTokenConfig.redeemer()).to.eq(dao.address) - }) - - describe('redeemer', () => { - it('not owner cannot update redeemer', async () => { - await expect( - osTokenConfig.connect(other).setRedeemer(other.address) - ).to.revertedWithCustomError(osTokenConfig, 'OwnableUnauthorizedAccount') - }) - - it('cannot set redeemer to the same address', async () => { - const currentRedeemer = await osTokenConfig.redeemer() - await expect( - osTokenConfig.connect(dao).setRedeemer(currentRedeemer) - ).to.revertedWithCustomError(osTokenConfig, 'ValueNotChanged') - }) - - it('owner can update redeemer', async () => { - const tx = await osTokenConfig.connect(dao).setRedeemer(other.address) - await expect(tx).to.emit(osTokenConfig, 'RedeemerUpdated').withArgs(other.address) - expect(await osTokenConfig.redeemer()).to.be.eq(other.address) - await snapshotGasCost(tx) - }) - }) - - describe('config', () => { - it('not owner cannot update config', async () => { - await expect( - osTokenConfig.connect(other).updateConfig(other.address, newConfig) - ).to.revertedWithCustomError(osTokenConfig, 'OwnableUnauthorizedAccount') - }) - - it('fails with invalid ltvPercent', async () => { - await expect( - osTokenConfig.connect(dao).updateConfig(other.address, { ...newConfig, ltvPercent: 0 }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLtvPercent') - - await expect( - osTokenConfig - .connect(dao) - .updateConfig(other.address, { ...newConfig, ltvPercent: maxPercent + 1n }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLtvPercent') - }) - - it('fails to disable liquidations with non zero liquidation bonus percent', async () => { - await expect( - osTokenConfig.connect(dao).updateConfig(other.address, { - ...newConfig, - liqThresholdPercent: MAX_UINT64, - liqBonusPercent: 1n, - }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqBonusPercent') - }) - - it('fails with invalid liqThresholdPercent', async () => { - await expect( - osTokenConfig - .connect(dao) - .updateConfig(other.address, { ...newConfig, liqThresholdPercent: 0 }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqThresholdPercent') - - await expect( - osTokenConfig - .connect(dao) - .updateConfig(other.address, { ...newConfig, liqThresholdPercent: maxPercent }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqThresholdPercent') - - await expect( - osTokenConfig.connect(dao).updateConfig(other.address, { - ...newConfig, - ltvPercent: newConfig.liqThresholdPercent + 1n, - }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqThresholdPercent') - }) - - it('fails with invalid liqBonusPercent', async () => { - await expect( - osTokenConfig - .connect(dao) - .updateConfig(other.address, { ...newConfig, liqBonusPercent: maxPercent - 1n }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqBonusPercent') - - await expect( - osTokenConfig.connect(dao).updateConfig(other.address, { - ...newConfig, - liqThresholdPercent: parseEther('0.95'), - liqBonusPercent: parseEther('1.1'), - }) - ).to.revertedWithCustomError(osTokenConfig, 'InvalidLiqBonusPercent') - }) - - it('owner can update config for a vault', async () => { - const tx = await osTokenConfig.connect(dao).updateConfig(other.address, newConfig) - await expect(tx) - .to.emit(osTokenConfig, 'OsTokenConfigUpdated') - .withArgs( - other.address, - newConfig.liqBonusPercent, - newConfig.liqThresholdPercent, - newConfig.ltvPercent - ) - const config = await osTokenConfig.getConfig(other.address) - expect(config.liqThresholdPercent).to.be.eq(newConfig.liqThresholdPercent) - expect(config.liqBonusPercent).to.be.eq(newConfig.liqBonusPercent) - expect(config.ltvPercent).to.be.eq(newConfig.ltvPercent) - - const defaultConfig = await osTokenConfig.getConfig(dao.address) - expect(defaultConfig.liqThresholdPercent).to.be.eq(OSTOKEN_LIQ_THRESHOLD) - expect(defaultConfig.liqBonusPercent).to.be.eq(OSTOKEN_LIQ_BONUS) - expect(defaultConfig.ltvPercent).to.be.eq(OSTOKEN_LTV) - await snapshotGasCost(tx) - }) - - it('owner can update default config', async () => { - const tx = await osTokenConfig.connect(dao).updateConfig(ZERO_ADDRESS, newConfig) - await expect(tx) - .to.emit(osTokenConfig, 'OsTokenConfigUpdated') - .withArgs( - ZERO_ADDRESS, - newConfig.liqBonusPercent, - newConfig.liqThresholdPercent, - newConfig.ltvPercent - ) - const config = await osTokenConfig.getConfig(dao.address) - expect(config.liqThresholdPercent).to.be.eq(newConfig.liqThresholdPercent) - expect(config.liqBonusPercent).to.be.eq(newConfig.liqBonusPercent) - expect(config.ltvPercent).to.be.eq(newConfig.ltvPercent) - await snapshotGasCost(tx) - }) - }) -}) diff --git a/test/OsTokenFlashLoans.spec.ts b/test/OsTokenFlashLoans.spec.ts deleted file mode 100644 index 46dfd254..00000000 --- a/test/OsTokenFlashLoans.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { parseEther } from 'ethers' -import { - OsToken, - OsTokenFlashLoanRecipientMock, - OsTokenFlashLoanRecipientMock__factory, - OsTokenFlashLoans, -} from '../typechain-types' -import { ethVaultFixture } from './shared/fixtures' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import snapshotGasCost from './shared/snapshotGasCost' - -describe('OsTokenFlashLoans', () => { - let osToken: OsToken - let osTokenFlashLoans: OsTokenFlashLoans - let osTokenFlashLoanRecipientMock: OsTokenFlashLoanRecipientMock - let maxFlashLoanAmount: bigint - - beforeEach(async () => { - const signer = (await ethers.getSigners())[1] - const fixture = await loadFixture(ethVaultFixture) - osToken = fixture.osToken - osTokenFlashLoans = fixture.osTokenFlashLoans - const contract = await ethers.deployContract('OsTokenFlashLoanRecipientMock', [ - await osToken.getAddress(), - await osTokenFlashLoans.getAddress(), - ]) - await contract.waitForDeployment() - osTokenFlashLoanRecipientMock = OsTokenFlashLoanRecipientMock__factory.connect( - await contract.getAddress(), - signer - ) - maxFlashLoanAmount = parseEther('100000') // 100000 ether - }) - - describe('flashLoan', () => { - it('should revert if requested amount is zero', async () => { - await expect( - osTokenFlashLoanRecipientMock.executeFlashLoan(0, '0x') - ).to.be.revertedWithCustomError(osTokenFlashLoans, 'InvalidShares') - }) - - it('should revert if requested amount exceeds maximum limit', async () => { - const excessiveAmount = maxFlashLoanAmount + 1n - - await expect( - osTokenFlashLoanRecipientMock.executeFlashLoan(excessiveAmount, '0x') - ).to.be.revertedWithCustomError(osTokenFlashLoans, 'InvalidShares') - }) - - it('should mint OsTokens for the recipient and successfully repay the loan', async () => { - const flashLoanAmount = parseEther('100') - - // Ensure the mock will repay the loan - await osTokenFlashLoanRecipientMock.setShouldRepayLoan(true) - - // Before flash loan - const preLoanBalance = await osToken.balanceOf(await osTokenFlashLoans.getAddress()) - - // Execute the flash loan - const tx = await osTokenFlashLoanRecipientMock.executeFlashLoan(flashLoanAmount, '0x') - - // After flash loan - const postLoanBalance = await osToken.balanceOf(await osTokenFlashLoans.getAddress()) - expect(postLoanBalance).to.equal(preLoanBalance) - - // Check if the event was emitted correctly - await expect(tx) - .to.emit(osTokenFlashLoans, 'OsTokenFlashLoan') - .withArgs(await osTokenFlashLoanRecipientMock.getAddress(), flashLoanAmount) - await snapshotGasCost(tx) - }) - - it('should revert if the loan is not repaid', async () => { - const flashLoanAmount = parseEther('100') - - // Ensure the mock will not repay the loan - await osTokenFlashLoanRecipientMock.setShouldRepayLoan(false) - await expect( - osTokenFlashLoanRecipientMock.executeFlashLoan(flashLoanAmount, '0x') - ).to.be.revertedWithCustomError(osTokenFlashLoans, 'FlashLoanFailed') - }) - }) -}) diff --git a/test/PriceFeed.test.ts b/test/PriceFeed.test.ts deleted file mode 100644 index 9ff6ed3d..00000000 --- a/test/PriceFeed.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { ethers } from 'hardhat' -import { Signer, Wallet } from 'ethers' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { - EthVault, - IKeeperRewards, - OsTokenVaultController, - PriceFeed, - DepositDataRegistry, -} from '../typechain-types' -import { expect } from './shared/expect' -import { createPriceFeed, ethVaultFixture } from './shared/fixtures' -import { ONE_DAY, ZERO_ADDRESS } from './shared/constants' -import { - collateralizeEthVault, - getHarvestParams, - getRewardsRootProof, - updateRewards, -} from './shared/rewards' -import { increaseTime } from './shared/utils' -import { MAINNET_FORK } from '../helpers/constants' - -describe('PriceFeed', () => { - const shares = ethers.parseEther('2') - const osTokenShares = ethers.parseEther('1') - const unlockedMevReward = ethers.parseEther('0') - const description = 'osETH/ETH' - const vaultParams = { - capacity: ethers.parseEther('1000'), - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u', - } - let sender: Wallet, admin: Signer, dao: Wallet - let osTokenVaultController: OsTokenVaultController, - priceFeed: PriceFeed, - vault: EthVault, - depositDataRegistry: DepositDataRegistry - - before('create fixture loader', async () => { - ;[sender, dao, admin] = await (ethers as any).getSigners() - }) - - beforeEach('deploy fixture', async () => { - const fixture = await loadFixture(ethVaultFixture) - vault = await fixture.createEthVault(admin, vaultParams) - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - osTokenVaultController = fixture.osTokenVaultController - depositDataRegistry = fixture.depositDataRegistry - priceFeed = await createPriceFeed(osTokenVaultController, description) - - // collateralize vault - await collateralizeEthVault( - vault, - fixture.keeper, - depositDataRegistry, - admin, - fixture.validatorsRegistry - ) - await vault.connect(sender).deposit(sender.address, ZERO_ADDRESS, { value: shares }) - - const reward = ethers.parseEther('1') - const vaultReward = getHarvestParams(await vault.getAddress(), reward, unlockedMevReward) - const tree = await updateRewards(fixture.keeper, [vaultReward]) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, vaultReward), - } - await vault.connect(dao).updateState(harvestParams) - }) - - it('has osToken address', async () => { - expect(await priceFeed.osTokenVaultController()).to.eq( - await osTokenVaultController.getAddress() - ) - }) - - it('has decimals', async () => { - expect(await priceFeed.decimals()).to.eq(18) - }) - - it('has description', async () => { - expect(await priceFeed.description()).to.eq(description) - }) - - it('has version', async () => { - expect(await priceFeed.version()).to.eq(0) - }) - - it('has timestamp', async () => { - expect(await priceFeed.latestTimestamp()).to.be.above(0) - }) - - it('works with zero supply', async () => { - if (MAINNET_FORK.enabled) return - const expectedValue = ethers.parseEther('1') - expect(await osTokenVaultController.totalShares()).to.eq(0) - expect(await priceFeed.latestAnswer()).to.eq(expectedValue) - - const latestRoundData = await priceFeed.latestRoundData() - expect(latestRoundData[1]).to.eq(expectedValue) - }) - - it('increments over time', async () => { - await vault.connect(sender).mintOsToken(sender.address, osTokenShares, ZERO_ADDRESS) - const value = await priceFeed.latestAnswer() - - let latestRoundData = await priceFeed.latestRoundData() - expect(latestRoundData[1]).to.eq(value) - - await increaseTime(ONE_DAY) - latestRoundData = await priceFeed.latestRoundData() - expect(await priceFeed.latestAnswer()).to.be.above(value) - expect(latestRoundData[1]).to.be.above(value) - }) -}) diff --git a/test/Rewards.t.sol b/test/Rewards.t.sol deleted file mode 100644 index efad9ed9..00000000 --- a/test/Rewards.t.sol +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IValidatorsRegistry} from '../contracts/interfaces/IValidatorsRegistry.sol'; -import {Keeper} from '../contracts/keeper/Keeper.sol'; -import {Test} from '../lib/forge-std/src/Test.sol'; -import {ForkTest} from './Fork.t.sol'; - - -abstract contract RewardsTest is Test, ForkTest { - address public oracle; - uint256 public oraclePrivateKey; - - function setUp() public virtual { - oracle = address(this); - oraclePrivateKey = 1; - - // setup oracle - (oracle, oraclePrivateKey) = makeAddrAndKey('oracle'); - address keeperOwner = Keeper(keeper).owner(); - vm.startPrank(keeperOwner); - Keeper(keeper).setValidatorsMinOracles(1); - Keeper(keeper).addOracle(oracle); - vm.stopPrank(); - } - - function _collateralizeVault(address _vault) internal { - IKeeperValidators.ApprovalParams memory approvalParams = IKeeperValidators.ApprovalParams({ - validatorsRegistryRoot: IValidatorsRegistry(validatorsRegistry).get_deposit_root(), - deadline: vm.getBlockTimestamp() + 1, - validators: 'validator1', - signatures: '', - exitSignaturesIpfsHash: 'ipfsHash' - }); - bytes32 digest = _hashTypedDataV4( - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' - ), - approvalParams.validatorsRegistryRoot, - _vault, - keccak256(approvalParams.validators), - keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), - approvalParams.deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(oraclePrivateKey, digest); - approvalParams.signatures = abi.encodePacked(r, s, v); - - vm.prank(_vault); - Keeper(keeper).approveValidators(approvalParams); - } - - - function _setVaultRewards( - address _vault, - int256 reward, - uint256 unlockedMevReward, - uint256 avgRewardPerSecond - ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { - address keeperOwner = Keeper(keeper).owner(); - vm.startPrank(keeperOwner); - Keeper(keeper).setRewardsMinOracles(1); - vm.stopPrank(); - - bytes32 root = keccak256( - bytes.concat( - keccak256( - abi.encode(_vault, SafeCast.toInt160(reward), SafeCast.toUint160(unlockedMevReward)) - ) - ) - ); - IKeeperRewards.RewardsUpdateParams memory params = IKeeperRewards.RewardsUpdateParams({ - rewardsRoot: root, - avgRewardPerSecond: avgRewardPerSecond, - updateTimestamp: uint64(vm.getBlockTimestamp()), - rewardsIpfsHash: 'ipfsHash', - signatures: '' - }); - bytes32 digest = _hashTypedDataV4( - keccak256( - abi.encode( - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' - ), - root, - keccak256(bytes(params.rewardsIpfsHash)), - params.avgRewardPerSecond, - params.updateTimestamp, - Keeper(keeper).rewardsNonce() - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(oraclePrivateKey, digest); - params.signatures = abi.encodePacked(r, s, v); - Keeper(keeper).updateRewards(params); - bytes32[] memory proof = new bytes32[](0); - harvestParams = IKeeperRewards.HarvestParams({ - rewardsRoot: root, - reward: SafeCast.toInt160(reward), - unlockedMevReward: SafeCast.toUint160(unlockedMevReward), - proof: proof - }); - } - - function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) { - return - MessageHashUtils.toTypedDataHash( - keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes('KeeperOracles')), - keccak256(bytes('1')), - block.chainid, - keeper - ) - ), - structHash - ); - } -} \ No newline at end of file diff --git a/test/ValidatorsChecker.spec.ts b/test/ValidatorsChecker.spec.ts deleted file mode 100644 index f78e4028..00000000 --- a/test/ValidatorsChecker.spec.ts +++ /dev/null @@ -1,389 +0,0 @@ -import { SignTypedDataVersion, signTypedData } from '@metamask/eth-sig-util' -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { Contract, Signer, Wallet } from 'ethers' -import { ethers } from 'hardhat' -import { - DepositDataRegistry, - EthValidatorsChecker, - GnoValidatorsChecker, - EthVault, - Keeper, - VaultsRegistry, -} from '../typechain-types' -import { MAX_UINT256, ZERO_ADDRESS } from './shared/constants' -import { getEthVaultV1Factory } from './shared/contracts' -import { expect } from './shared/expect' -import { - createEthValidatorsChecker, - deployEthVaultV1, - encodeEthVaultInitParams, - ethVaultFixture, -} from './shared/fixtures' -import { - EthValidatorsData, - createEthValidatorsData, - getValidatorsManagerSigningData, - getValidatorsMultiProof, -} from './shared/validators' -import { createGnoValidatorsChecker } from './shared/gnoFixtures' - -const networks = ['ETHEREUM', 'GNOSIS'] - -enum Status { - SUCCEEDED, - INVALID_VALIDATORS_REGISTRY_ROOT, - INVALID_VAULT, - INSUFFICIENT_ASSETS, - INVALID_SIGNATURE, - INVALID_VALIDATORS_MANAGER, - INVALID_VALIDATORS_COUNT, - INVALID_VALIDATORS_LENGTH, - INVALID_PROOF, -} - -networks.forEach((network) => { - describe(`ValidatorsChecker [${network}]`, () => { - let validatorDeposit = ethers.parseEther('32') - if (network == 'GNOSIS') { - validatorDeposit = ethers.parseEther('1') - } - - const capacity = MAX_UINT256 - const feePercent = 1000 - const metadataIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - - let admin: Signer, adminV1: Signer, other: Wallet - let vault: EthVault, - keeper: Keeper, - validatorsRegistry: Contract, - vaultsRegistry: VaultsRegistry, - depositDataRegistry: DepositDataRegistry, - validatorsChecker: EthValidatorsChecker | GnoValidatorsChecker, - vaultV1: Contract, - vaultNotDeposited: EthVault - let validatorsData: EthValidatorsData - let validators: Buffer[] - let validatorsRegistryRoot: string - - beforeEach('deploy fixture', async () => { - ;[admin, adminV1, other] = await (ethers as any).getSigners() - - const fixture = await loadFixture(ethVaultFixture) - validatorsRegistry = fixture.validatorsRegistry - keeper = fixture.keeper - depositDataRegistry = fixture.depositDataRegistry - vaultsRegistry = fixture.vaultsRegistry - - if (network == 'ETHEREUM') { - validatorsChecker = await createEthValidatorsChecker( - validatorsRegistry, - keeper, - vaultsRegistry, - depositDataRegistry - ) - } else if (network == 'GNOSIS') { - validatorsChecker = await createGnoValidatorsChecker( - validatorsRegistry, - keeper, - vaultsRegistry, - depositDataRegistry - ) - } else { - throw Error('unknown network') - } - - vault = await fixture.createEthVault(admin, { - capacity, - feePercent, - metadataIpfsHash, - }) - vaultV1 = await deployEthVaultV1( - await getEthVaultV1Factory(), - adminV1, - keeper, - vaultsRegistry, - validatorsRegistry, - fixture.osTokenVaultController, - fixture.osTokenConfig, - fixture.sharedMevEscrow, - encodeEthVaultInitParams({ - capacity, - feePercent, - metadataIpfsHash, - }) - ) - // get real admin in the case of mainnet fork - admin = await ethers.getImpersonatedSigner(await vault.admin()) - - validatorsData = await createEthValidatorsData(vault) - const numValidators = 5 - validators = validatorsData.validators.slice(0, numValidators) - - validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - await vault.connect(other).deposit(other.address, ZERO_ADDRESS, { value: validatorDeposit }) - await vaultV1.connect(other).deposit(other.address, ZERO_ADDRESS, { value: validatorDeposit }) - - vaultNotDeposited = await fixture.createEthVault( - admin, - { - capacity, - feePercent, - metadataIpfsHash, - }, - true, // own mev escrow - true // skip fork - ) - // Remember about security deposit 1 gwei, so vault balance is not zero at this point. - let validatorDepositIncomplete = ethers.parseEther('31') - if (network == 'GNOSIS') { - validatorDepositIncomplete = ethers.parseEther('0.9') - } - await vaultNotDeposited - .connect(other) - .deposit(other.address, ZERO_ADDRESS, { value: validatorDepositIncomplete }) - - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vault.getAddress(), validatorsData.root) - - await vaultV1.connect(adminV1).setValidatorsRoot(validatorsData.root) - await depositDataRegistry - .connect(admin) - .setDepositDataRoot(await vaultNotDeposited.getAddress(), validatorsData.root) - }) - - describe('check validators manager signature', () => { - // I need explicit privateKey to create EIP-712 signature - const validatorsManager = new Wallet( - '0x798ce32ec683f3287dab0594b9ead26403a6da9c1d216d00e5aa088c9cf36864' - ) - const fakeValidatorsManager = new Wallet( - '0xb4942e4f87ddfd23ddf833a47ebcf6bb37e0da344a2d6e229fd593c0b22bdb68' - ) - - beforeEach('set validators manager', async () => { - await vault.connect(admin).setValidatorsManager(validatorsManager.address) - }) - - it('fails for invalid validators registry root', async () => { - const fakeRoot = Buffer.alloc(32).fill(1) - const response = await validatorsChecker.checkValidatorsManagerSignature( - await vault.getAddress(), - fakeRoot, - '0x', - '0x' - ) - expect(response.status).to.eq(Status.INVALID_VALIDATORS_REGISTRY_ROOT) - }) - - it('fails for non-vault', async () => { - const response = await validatorsChecker.checkValidatorsManagerSignature( - other.address, - validatorsRegistryRoot, - '0x', - '0x' - ) - expect(response.status).to.eq(Status.INVALID_VAULT) - }) - - it('fails for vault v1', async () => { - const response = await validatorsChecker.checkValidatorsManagerSignature( - await vaultV1.getAddress(), - validatorsRegistryRoot, - '0x', - '0x' - ) - expect(response.status).to.eq(Status.INVALID_VAULT) - }) - - it('fails for vault not collateralized not deposited', async () => { - const response = await validatorsChecker.checkValidatorsManagerSignature( - await vaultNotDeposited.getAddress(), - validatorsRegistryRoot, - '0x', - '0x' - ) - expect(response.status).to.eq(Status.INSUFFICIENT_ASSETS) - }) - - it('fails for signer who is not validators manager', async () => { - const vaultAddress = await vault.getAddress() - const typedData = await getValidatorsManagerSigningData( - Buffer.concat(validators), - vault, - validatorsRegistryRoot - ) - const signature = signTypedData({ - privateKey: Buffer.from(ethers.getBytes(fakeValidatorsManager.privateKey)), - data: typedData, - version: SignTypedDataVersion.V4, - }) - const response = await validatorsChecker.checkValidatorsManagerSignature( - vaultAddress, - validatorsRegistryRoot, - Buffer.concat(validators), - ethers.getBytes(signature) - ) - expect(response.status).to.eq(Status.INVALID_SIGNATURE) - }) - - it('succeeds', async () => { - const vaultAddress = await vault.getAddress() - const typedData = await getValidatorsManagerSigningData( - Buffer.concat(validators), - vault, - validatorsRegistryRoot - ) - const signature = signTypedData({ - privateKey: Buffer.from(ethers.getBytes(validatorsManager.privateKey)), - data: typedData, - version: SignTypedDataVersion.V4, - }) - const blockNumber = await ethers.provider.getBlockNumber() - const response = await validatorsChecker.checkValidatorsManagerSignature( - vaultAddress, - validatorsRegistryRoot, - Buffer.concat(validators), - ethers.getBytes(signature) - ) - expect(response.blockNumber).to.eq(blockNumber) - expect(response.status).to.eq(Status.SUCCEEDED) - }) - }) - - describe('check deposit data root', () => { - let proof: string[], proofFlags: boolean[], proofIndexes: number[] - - beforeEach('set multiproof', () => { - // Proof is empty list when passing all validators - // I need non-empty proof for some test cases - // Slice validators because of that - - const multiProof = getValidatorsMultiProof(validatorsData.tree, validators, [ - ...Array(validators.length).keys(), - ]) - const sortedVals = multiProof.leaves.map((v) => v[0]) - - proof = multiProof.proof - proofFlags = multiProof.proofFlags - proofIndexes = validators.map((v) => sortedVals.indexOf(v)) - }) - - it('fails for invalid validators registry root', async () => { - const fakeRoot = Buffer.alloc(32).fill(1) - - const response = await validatorsChecker.checkDepositDataRoot( - await vault.getAddress(), - fakeRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.status).to.eq(Status.INVALID_VALIDATORS_REGISTRY_ROOT) - }) - - it('fails for non-vault', async () => { - const response = await validatorsChecker.checkDepositDataRoot( - other.address, - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.status).to.eq(Status.INVALID_VAULT) - }) - - it('fails for vault not collateralized not deposited', async () => { - const response = await validatorsChecker.checkDepositDataRoot( - await vaultNotDeposited.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.status).to.eq(Status.INSUFFICIENT_ASSETS) - }) - - it('fails for validators manager not equal to deposit data registry', async () => { - await vault.connect(admin).setValidatorsManager(other.address) - const response = await validatorsChecker.checkDepositDataRoot( - await vault.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.status).to.eq(Status.INVALID_VALIDATORS_MANAGER) - }) - - it('fails for invalid proof', async () => { - proof[0] = '0x' + '1'.repeat(64) - const response = await validatorsChecker.checkDepositDataRoot( - await vault.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.status).to.eq(Status.INVALID_PROOF) - }) - - it('fails for invalid proof indexes', async () => { - const response = await validatorsChecker.checkDepositDataRoot( - await vault.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - [] - ) - expect(response.status).to.eq(Status.INVALID_VALIDATORS_COUNT) - }) - - it('fails for invalid validators', async () => { - const response = await validatorsChecker.checkDepositDataRoot( - await vault.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators.slice(0, -1)), - proof, - proofFlags, - proofIndexes - ) - expect(response.status).to.eq(Status.INVALID_VALIDATORS_LENGTH) - }) - - it('succeeds for vault v1', async () => { - const blockNumber = await ethers.provider.getBlockNumber() - const response = await validatorsChecker.checkDepositDataRoot( - await vaultV1.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.blockNumber).to.eq(blockNumber) - expect(response.status).to.eq(Status.SUCCEEDED) - }) - - it('succeeds for vault v3', async () => { - const blockNumber = await ethers.provider.getBlockNumber() - const response = await validatorsChecker.checkDepositDataRoot( - await vault.getAddress(), - validatorsRegistryRoot, - Buffer.concat(validators), - proof, - proofFlags, - proofIndexes - ) - expect(response.blockNumber).to.eq(blockNumber) - expect(response.status).to.eq(Status.SUCCEEDED) - }) - }) - }) -}) diff --git a/test/__snapshots__/DepositDataRegistry.spec.ts.snap b/test/__snapshots__/DepositDataRegistry.spec.ts.snap deleted file mode 100644 index b222ea00..00000000 --- a/test/__snapshots__/DepositDataRegistry.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DepositDataRegistry deposit data manager update succeeds 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 63853, -} -`; - -exports[`DepositDataRegistry deposit data root update success 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 64595, -} -`; - -exports[`DepositDataRegistry multiple validators succeeds 1`] = ` -Object { - "calldataByteLength": 3364, - "gasUsed": 688299, -} -`; - -exports[`DepositDataRegistry single validator can update state and register validator 1`] = ` -Object { - "calldataByteLength": 1668, - "gasUsed": 408598, -} -`; - -exports[`DepositDataRegistry single validator succeeds 1`] = ` -Object { - "calldataByteLength": 1188, - "gasUsed": 334676, -} -`; diff --git a/test/__snapshots__/EthBlocklistErc20Vault.spec.ts.snap b/test/__snapshots__/EthBlocklistErc20Vault.spec.ts.snap deleted file mode 100644 index 23551cf1..00000000 --- a/test/__snapshots__/EthBlocklistErc20Vault.spec.ts.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthBlocklistErc20Vault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 71159, -} -`; - -exports[`EthBlocklistErc20Vault deposit deposit through receive fallback can be called by not blocked sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 78347, -} -`; - -exports[`EthBlocklistErc20Vault mint osToken can mint from not blocked user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178597, -} -`; - -exports[`EthBlocklistErc20Vault transfer can transfer 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 58932, -} -`; diff --git a/test/__snapshots__/EthBlocklistVault.spec.ts.snap b/test/__snapshots__/EthBlocklistVault.spec.ts.snap deleted file mode 100644 index 03d16286..00000000 --- a/test/__snapshots__/EthBlocklistVault.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthBlocklistVault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 69034, -} -`; - -exports[`EthBlocklistVault deposit deposit through receive fallback can be called by not blocked sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 76519, -} -`; - -exports[`EthBlocklistVault mint osToken can mint from not blocked user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178408, -} -`; diff --git a/test/__snapshots__/EthErc20Vault.spec.ts.snap b/test/__snapshots__/EthErc20Vault.spec.ts.snap deleted file mode 100644 index 6481e3b4..00000000 --- a/test/__snapshots__/EthErc20Vault.spec.ts.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthErc20Vault can deposit and mint osToken in one transaction 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 209316, -} -`; - -exports[`EthErc20Vault can deposit and mint osToken in one transaction 2`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 175008, -} -`; - -exports[`EthErc20Vault can update state, deposit, and mint osToken in one transaction 1`] = ` -Object { - "calldataByteLength": 292, - "gasUsed": 235905, -} -`; - -exports[`EthErc20Vault deposit emits transfer event 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 68842, -} -`; - -exports[`EthErc20Vault deposit through receive fallback function emits transfer event 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 76122, -} -`; - -exports[`EthErc20Vault enter exit queue emits transfer event 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 91284, -} -`; - -exports[`EthErc20Vault update exit queue emits transfer event 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 139813, -} -`; diff --git a/test/__snapshots__/EthFoxVault.spec.ts.snap b/test/__snapshots__/EthFoxVault.spec.ts.snap deleted file mode 100644 index 29e68b66..00000000 --- a/test/__snapshots__/EthFoxVault.spec.ts.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthFoxVault blocklist can be updated by blocklist manager 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 53699, -} -`; - -exports[`EthFoxVault blocklist can be updated by blocklist manager 2`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 31787, -} -`; - -exports[`EthFoxVault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 68880, -} -`; - -exports[`EthFoxVault deposit deposit through receive fallback can be called by not blocked sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 76530, -} -`; - -exports[`EthFoxVault ejecting user blocklist manager can eject all of the user assets for collateralized vault 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 116988, -} -`; - -exports[`EthFoxVault ejecting user does not fail for user with no vault shares 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 55767, -} -`; - -exports[`EthFoxVault set blocklist manager admin can update blocklist manager 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 35897, -} -`; diff --git a/test/__snapshots__/EthGenesisVault.spec.ts.snap b/test/__snapshots__/EthGenesisVault.spec.ts.snap deleted file mode 100644 index fbc7ea64..00000000 --- a/test/__snapshots__/EthGenesisVault.spec.ts.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthGenesisVault can deposit through receive fallback function 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 74334, -} -`; - -exports[`EthGenesisVault migrate migrates from rewardEthToken 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 227940, -} -`; - -exports[`EthGenesisVault pulls assets on claim exited assets 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 62472, -} -`; - -exports[`EthGenesisVault pulls withdrawals on multiple validators registration 1`] = ` -Object { - "calldataByteLength": 3748, - "gasUsed": 652813, -} -`; - -exports[`EthGenesisVault pulls withdrawals on single validator registration 1`] = ` -Object { - "calldataByteLength": 1188, - "gasUsed": 313004, -} -`; - -exports[`EthGenesisVault update state deducts rewards on first state update 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 152896, -} -`; - -exports[`EthGenesisVault update state skips updating legacy with zero total assets 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 148465, -} -`; - -exports[`EthGenesisVault update state splits penalty between rewardEthToken and vault 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 105682, -} -`; - -exports[`EthGenesisVault update state splits reward between rewardEthToken and vault 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 169996, -} -`; diff --git a/test/__snapshots__/EthOsTokenVaultEscrow.spec.ts.snap b/test/__snapshots__/EthOsTokenVaultEscrow.spec.ts.snap deleted file mode 100644 index abadfaf8..00000000 --- a/test/__snapshots__/EthOsTokenVaultEscrow.spec.ts.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthOsTokenVaultEscrow claim exited assets succeeds succeeds for all osToken shares 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 77635, -} -`; - -exports[`EthOsTokenVaultEscrow claim exited assets succeeds succeeds for partial osToken shares 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 88008, -} -`; - -exports[`EthOsTokenVaultEscrow liquidate can liquidate 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 96969, -} -`; - -exports[`EthOsTokenVaultEscrow process exited assets processes exited assets 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 64607, -} -`; - -exports[`EthOsTokenVaultEscrow redeem can redeem 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 96248, -} -`; - -exports[`EthOsTokenVaultEscrow register keeps LTV for the position left 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 170313, -} -`; - -exports[`EthOsTokenVaultEscrow register removes position if all the osToken shares transferred 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 160159, -} -`; - -exports[`EthOsTokenVaultEscrow set authenticator owner can update authenticator 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 30077, -} -`; - -exports[`EthOsTokenVaultEscrow update config owner can update config 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 35826, -} -`; diff --git a/test/__snapshots__/EthPrivErc20Vault.spec.ts.snap b/test/__snapshots__/EthPrivErc20Vault.spec.ts.snap deleted file mode 100644 index cc45c543..00000000 --- a/test/__snapshots__/EthPrivErc20Vault.spec.ts.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthPrivErc20Vault deposit can be called by whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 71147, -} -`; - -exports[`EthPrivErc20Vault deposit deposit through receive fallback can be called by whitelisted sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 78350, -} -`; - -exports[`EthPrivErc20Vault mint osToken can mint from whitelisted user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178622, -} -`; - -exports[`EthPrivErc20Vault transfer can transfer to whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 58960, -} -`; diff --git a/test/__snapshots__/EthPrivVault.spec.ts.snap b/test/__snapshots__/EthPrivVault.spec.ts.snap deleted file mode 100644 index ff0c0160..00000000 --- a/test/__snapshots__/EthPrivVault.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthPrivVault mint osToken can mint from not whitelisted user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178433, -} -`; diff --git a/test/__snapshots__/EthVault.burn.spec.ts.snap b/test/__snapshots__/EthVault.burn.spec.ts.snap deleted file mode 100644 index 1b0f87e5..00000000 --- a/test/__snapshots__/EthVault.burn.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - burn burns osTokens 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 84108, -} -`; - -exports[`EthVault - burn updates position accumulated fee 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 84108, -} -`; diff --git a/test/__snapshots__/EthVault.deposit.spec.ts.snap b/test/__snapshots__/EthVault.deposit.spec.ts.snap deleted file mode 100644 index 9d8d8b3d..00000000 --- a/test/__snapshots__/EthVault.deposit.spec.ts.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - deposit empty vault: no assets & no shares deposit 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 66717, -} -`; - -exports[`EthVault - deposit full vault: assets & shares deposit 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 66717, -} -`; - -exports[`EthVault - deposit full vault: assets & shares deposit through receive fallback function 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 74294, -} -`; - -exports[`EthVault - deposit full vault: assets & shares update state and deposit 1`] = ` -Object { - "calldataByteLength": 260, - "gasUsed": 209774, -} -`; diff --git a/test/__snapshots__/EthVault.liquidate.spec.ts.snap b/test/__snapshots__/EthVault.liquidate.spec.ts.snap deleted file mode 100644 index af40e501..00000000 --- a/test/__snapshots__/EthVault.liquidate.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - liquidate calculates liquidation correctly 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 112487, -} -`; - -exports[`EthVault - liquidate can liquidate 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 112487, -} -`; diff --git a/test/__snapshots__/EthVault.mint.spec.ts.snap b/test/__snapshots__/EthVault.mint.spec.ts.snap deleted file mode 100644 index 426b2c44..00000000 --- a/test/__snapshots__/EthVault.mint.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - mint can deposit and mint osToken in one transaction 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 206798, -} -`; - -exports[`EthVault - mint can deposit and mint osToken in one transaction 2`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 155825, -} -`; - -exports[`EthVault - mint can update state, deposit, and mint osToken in one transaction 1`] = ` -Object { - "calldataByteLength": 292, - "gasUsed": 261491, -} -`; - -exports[`EthVault - mint mints osTokens to the receiver 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 176133, -} -`; - -exports[`EthVault - mint updates position accumulated fee 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 122561, -} -`; diff --git a/test/__snapshots__/EthVault.multicall.spec.ts.snap b/test/__snapshots__/EthVault.multicall.spec.ts.snap deleted file mode 100644 index 63e95dad..00000000 --- a/test/__snapshots__/EthVault.multicall.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - multicall can update state and queue for exit 1`] = ` -Object { - "calldataByteLength": 516, - "gasUsed": 166598, -} -`; - -exports[`EthVault - multicall can update state and queue for exit 2`] = ` -Object { - "calldataByteLength": 548, - "gasUsed": 139630, -} -`; diff --git a/test/__snapshots__/EthVault.redeem.spec.ts.snap b/test/__snapshots__/EthVault.redeem.spec.ts.snap deleted file mode 100644 index 61bd5b58..00000000 --- a/test/__snapshots__/EthVault.redeem.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - redeem osToken calculates redeem correctly 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 126849, -} -`; - -exports[`EthVault - redeem osToken can redeem 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 126849, -} -`; diff --git a/test/__snapshots__/EthVault.register.spec.ts.snap b/test/__snapshots__/EthVault.register.spec.ts.snap deleted file mode 100644 index 52ea1545..00000000 --- a/test/__snapshots__/EthVault.register.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - register multiple validators succeeds from validators manager 1`] = ` -Object { - "calldataByteLength": 2596, - "gasUsed": 631284, -} -`; - -exports[`EthVault - register single validator succeeds from validators manager 1`] = ` -Object { - "calldataByteLength": 1028, - "gasUsed": 298460, -} -`; diff --git a/test/__snapshots__/EthVault.settings.spec.ts.snap b/test/__snapshots__/EthVault.settings.spec.ts.snap deleted file mode 100644 index c34489e3..00000000 --- a/test/__snapshots__/EthVault.settings.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - settings fee recipient can update 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 44042, -} -`; - -exports[`EthVault - settings metadata IPFS hash only admin can update 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 32689, -} -`; - -exports[`EthVault - settings validators manager can be updated by admin 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 52819, -} -`; diff --git a/test/__snapshots__/EthVault.state.spec.ts.snap b/test/__snapshots__/EthVault.state.spec.ts.snap deleted file mode 100644 index 947b320b..00000000 --- a/test/__snapshots__/EthVault.state.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - state allocates fee to recipient when delta is above zero 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 120077, -} -`; - -exports[`EthVault - state applies penalty when delta is below zero 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 117862, -} -`; - -exports[`EthVault - state updates exit queue 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 147039, -} -`; diff --git a/test/__snapshots__/EthVault.token.spec.ts.snap b/test/__snapshots__/EthVault.token.spec.ts.snap deleted file mode 100644 index b5d7f764..00000000 --- a/test/__snapshots__/EthVault.token.spec.ts.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - token approve when the sender has enough balance when the spender had an approved amount approves the requested amount and replaces the previous one 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 33732, -} -`; - -exports[`EthVault - token approve when the sender has enough balance when there was no approved amount before approves the requested amount 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 50832, -} -`; - -exports[`EthVault - token permit accepts owner signature 1`] = ` -Object { - "calldataByteLength": 228, - "gasUsed": 82411, -} -`; - -exports[`EthVault - token transfer from when the spender has enough allowance when the token owner has enough balance transfers the requested amount 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54747, -} -`; - -exports[`EthVault - token transfer from when the spender has unlimited allowance does not decrease the spender allowance 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 61223, -} -`; - -exports[`EthVault - token transfer when the sender transfers all balance transfers the requested amount 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 54410, -} -`; - -exports[`EthVault - token transfer when the sender transfers zero tokens transfers the requested amount 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 36486, -} -`; diff --git a/test/__snapshots__/EthVault.upgrade.spec.ts.snap b/test/__snapshots__/EthVault.upgrade.spec.ts.snap deleted file mode 100644 index fed994e8..00000000 --- a/test/__snapshots__/EthVault.upgrade.spec.ts.snap +++ /dev/null @@ -1,57 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - upgrade does not modify the state variables 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 53997, -} -`; - -exports[`EthVault - upgrade does not modify the state variables 2`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54211, -} -`; - -exports[`EthVault - upgrade does not modify the state variables 3`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54101, -} -`; - -exports[`EthVault - upgrade does not modify the state variables 4`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54661, -} -`; - -exports[`EthVault - upgrade does not modify the state variables 5`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54875, -} -`; - -exports[`EthVault - upgrade does not modify the state variables 6`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54765, -} -`; - -exports[`EthVault - upgrade does not modify the state variables 7`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 54109, -} -`; - -exports[`EthVault - upgrade works with valid call data 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 76331, -} -`; diff --git a/test/__snapshots__/EthVault.whitelist.spec.ts.snap b/test/__snapshots__/EthVault.whitelist.spec.ts.snap deleted file mode 100644 index 12d07156..00000000 --- a/test/__snapshots__/EthVault.whitelist.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - whitelist deposit can be called by whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 69022, -} -`; - -exports[`EthVault - whitelist deposit deposit through receive fallback can be called by whitelisted sender 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 76522, -} -`; - -exports[`EthVault - whitelist set whitelister admin can update whitelister 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 36201, -} -`; - -exports[`EthVault - whitelist whitelist can be updated by whitelister 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 53149, -} -`; - -exports[`EthVault - whitelist whitelist can be updated by whitelister 2`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 31237, -} -`; diff --git a/test/__snapshots__/EthVault.withdraw.spec.ts.snap b/test/__snapshots__/EthVault.withdraw.spec.ts.snap deleted file mode 100644 index f0f4cade..00000000 --- a/test/__snapshots__/EthVault.withdraw.spec.ts.snap +++ /dev/null @@ -1,59 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVault - withdraw claim exited assets for single user in multiple checkpoints in multiple transactions 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 75090, -} -`; - -exports[`EthVault - withdraw claim exited assets for single user in multiple checkpoints in multiple transactions 2`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 48095, -} -`; - -exports[`EthVault - withdraw claim exited assets for single user in multiple checkpoints in single transaction 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 50657, -} -`; - -exports[`EthVault - withdraw claim exited assets for single user in single checkpoint 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 48095, -} -`; - -exports[`EthVault - withdraw enter exit queue locks shares for the time of exit 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 89271, -} -`; - -exports[`EthVault - withdraw get checkpoint index works with many checkpoints 1`] = `29876`; - -exports[`EthVault - withdraw redeem redeem transfers assets to receiver 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 55658, -} -`; - -exports[`EthVault - withdraw update exit queue adds checkpoint 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 105743, -} -`; - -exports[`EthVault - withdraw update exit queue for not all the queued shares 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 105739, -} -`; diff --git a/test/__snapshots__/EthVaultFactory.spec.ts.snap b/test/__snapshots__/EthVaultFactory.spec.ts.snap deleted file mode 100644 index 4eb283ba..00000000 --- a/test/__snapshots__/EthVaultFactory.spec.ts.snap +++ /dev/null @@ -1,57 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EthVaultFactory EthErc20Vault private vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 516, - "gasUsed": 599781, -} -`; - -exports[`EthVaultFactory EthErc20Vault private vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 516, - "gasUsed": 450962, -} -`; - -exports[`EthVaultFactory EthErc20Vault public vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 516, - "gasUsed": 575861, -} -`; - -exports[`EthVaultFactory EthErc20Vault public vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 516, - "gasUsed": 427042, -} -`; - -exports[`EthVaultFactory EthVault private vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 525659, -} -`; - -exports[`EthVaultFactory EthVault private vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 376840, -} -`; - -exports[`EthVaultFactory EthVault public vault deployment with own escrow gas 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 501739, -} -`; - -exports[`EthVaultFactory EthVault public vault deployment with shared escrow gas 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 352920, -} -`; diff --git a/test/__snapshots__/KeeperOracles.spec.ts.snap b/test/__snapshots__/KeeperOracles.spec.ts.snap deleted file mode 100644 index 615b2b1e..00000000 --- a/test/__snapshots__/KeeperOracles.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`KeeperOracles add oracle succeeds 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 52947, -} -`; - -exports[`KeeperOracles remove oracle succeeds 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 31129, -} -`; - -exports[`KeeperOracles update config succeeds 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 27005, -} -`; diff --git a/test/__snapshots__/KeeperRewards.spec.ts.snap b/test/__snapshots__/KeeperRewards.spec.ts.snap deleted file mode 100644 index 6a85d802..00000000 --- a/test/__snapshots__/KeeperRewards.spec.ts.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`KeeperRewards harvest (own escrow) succeeds for latest rewards root 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 113879, -} -`; - -exports[`KeeperRewards harvest (own escrow) succeeds for previous rewards root 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 116033, -} -`; - -exports[`KeeperRewards harvest (own escrow) succeeds for previous rewards root 2`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 76797, -} -`; - -exports[`KeeperRewards harvest (shared escrow) succeeds for latest rewards root 1`] = ` -Object { - "calldataByteLength": 292, - "gasUsed": 146467, -} -`; - -exports[`KeeperRewards harvest (shared escrow) succeeds for previous rewards root 1`] = ` -Object { - "calldataByteLength": 292, - "gasUsed": 148621, -} -`; - -exports[`KeeperRewards harvest (shared escrow) succeeds for previous rewards root 2`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 92986, -} -`; - -exports[`KeeperRewards set min rewards oracles succeeds 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 32275, -} -`; - -exports[`KeeperRewards update rewards succeeds 1`] = ` -Object { - "calldataByteLength": 772, - "gasUsed": 140739, -} -`; - -exports[`KeeperRewards update rewards succeeds 2`] = ` -Object { - "calldataByteLength": 772, - "gasUsed": 123639, -} -`; - -exports[`KeeperRewards update rewards succeeds with all signatures 1`] = ` -Object { - "calldataByteLength": 1156, - "gasUsed": 146943, -} -`; diff --git a/test/__snapshots__/KeeperValidators.spec.ts.snap b/test/__snapshots__/KeeperValidators.spec.ts.snap deleted file mode 100644 index eb71e955..00000000 --- a/test/__snapshots__/KeeperValidators.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`KeeperValidators register multiple validators succeeds 1`] = ` -Object { - "calldataByteLength": 3748, - "gasUsed": 694692, -} -`; - -exports[`KeeperValidators register multiple validators succeeds 2`] = ` -Object { - "calldataByteLength": 3748, - "gasUsed": 602888, -} -`; - -exports[`KeeperValidators register single validator succeeds 1`] = ` -Object { - "calldataByteLength": 1572, - "gasUsed": 341102, -} -`; - -exports[`KeeperValidators register single validator succeeds 2`] = ` -Object { - "calldataByteLength": 1540, - "gasUsed": 286718, -} -`; - -exports[`KeeperValidators set validators oracles succeeds 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 32165, -} -`; diff --git a/test/__snapshots__/OsToken.spec.ts.snap b/test/__snapshots__/OsToken.spec.ts.snap deleted file mode 100644 index 84b9ba29..00000000 --- a/test/__snapshots__/OsToken.spec.ts.snap +++ /dev/null @@ -1,92 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OsToken approve when the sender has enough balance when the spender had an approved amount approves the requested amount and replaces the previous one 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 28855, -} -`; - -exports[`OsToken approve when the sender has enough balance when there was no approved amount before approves the requested amount 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 45955, -} -`; - -exports[`OsToken capacity owner can change 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 25068, -} -`; - -exports[`OsToken controllers owner can change 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 48051, -} -`; - -exports[`OsToken controllers owner can change 2`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 26139, -} -`; - -exports[`OsToken fee percent owner can change 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 77683, -} -`; - -exports[`OsToken keeper owner can change 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 30104, -} -`; - -exports[`OsToken permit accepts owner signature 1`] = ` -Object { - "calldataByteLength": 228, - "gasUsed": 74566, -} -`; - -exports[`OsToken transfer from when the spender has enough allowance when the token owner has enough balance transfers the requested amount 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 47366, -} -`; - -exports[`OsToken transfer from when the spender has unlimited allowance does not decrease the spender allowance 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 53815, -} -`; - -exports[`OsToken transfer when the sender transfers all balance transfers the requested amount 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 46569, -} -`; - -exports[`OsToken transfer when the sender transfers zero tokens transfers the requested amount 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 28645, -} -`; - -exports[`OsToken treasury owner can change 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 27690, -} -`; diff --git a/test/__snapshots__/OsTokenConfig.spec.ts.snap b/test/__snapshots__/OsTokenConfig.spec.ts.snap deleted file mode 100644 index 6962656d..00000000 --- a/test/__snapshots__/OsTokenConfig.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OsTokenConfig config owner can update config for a vault 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 49519, -} -`; - -exports[`OsTokenConfig config owner can update default config 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 32132, -} -`; - -exports[`OsTokenConfig redeemer owner can update redeemer 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 29967, -} -`; diff --git a/test/__snapshots__/OsTokenFlashLoans.spec.ts.snap b/test/__snapshots__/OsTokenFlashLoans.spec.ts.snap deleted file mode 100644 index 9e78c19d..00000000 --- a/test/__snapshots__/OsTokenFlashLoans.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OsTokenFlashLoans flashLoan should mint OsTokens for the recipient and successfully repay the loan 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 96072, -} -`; diff --git a/test/__snapshots__/OsTokenVaultEscrow.spec.ts.snap b/test/__snapshots__/OsTokenVaultEscrow.spec.ts.snap deleted file mode 100644 index 73b8df9a..00000000 --- a/test/__snapshots__/OsTokenVaultEscrow.spec.ts.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OsTokenVaultEscrow claim exited assets succeeds succeeds for all osToken shares 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 77572, -} -`; - -exports[`OsTokenVaultEscrow claim exited assets succeeds succeeds for partial osToken shares 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 87969, -} -`; - -exports[`OsTokenVaultEscrow liquidate can liquidate 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 96837, -} -`; - -exports[`OsTokenVaultEscrow process exited assets processes exited assets 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 64327, -} -`; - -exports[`OsTokenVaultEscrow redeem can redeem 1`] = ` -Object { - "calldataByteLength": 132, - "gasUsed": 96176, -} -`; - -exports[`OsTokenVaultEscrow register keeps LTV for the position left 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 172530, -} -`; - -exports[`OsTokenVaultEscrow register removes position if all the osToken shares transferred 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 162351, -} -`; - -exports[`OsTokenVaultEscrow set authenticator owner can update authenticator 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 30077, -} -`; - -exports[`OsTokenVaultEscrow update config owner can update config 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 35657, -} -`; diff --git a/test/__snapshots__/OwnMevEscrow.spec.ts.snap b/test/__snapshots__/OwnMevEscrow.spec.ts.snap deleted file mode 100644 index 99842664..00000000 --- a/test/__snapshots__/OwnMevEscrow.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OwnMevEscrow vault deployment gas 1`] = ` -Object { - "calldataByteLength": 638, - "gasUsed": 156091, -} -`; diff --git a/test/__snapshots__/RewardSplitter.spec.ts.snap b/test/__snapshots__/RewardSplitter.spec.ts.snap deleted file mode 100644 index fc92bb9b..00000000 --- a/test/__snapshots__/RewardSplitter.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RewardSplitter decrease shares owner can decrease shares 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 67129, -} -`; - -exports[`RewardSplitter increase shares owner can increase shares 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 78767, -} -`; - -exports[`RewardSplitter sync rewards anyone can sync rewards 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 73154, -} -`; - -exports[`RewardSplitter withdraw rewards can claim vault tokens for ERC-20 vault 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 78147, -} -`; - -exports[`RewardSplitter withdraw rewards can enter exit queue with multicall 1`] = ` -Object { - "calldataByteLength": 612, - "gasUsed": 171281, -} -`; diff --git a/test/__snapshots__/RewardSplitterFactory.spec.ts.snap b/test/__snapshots__/RewardSplitterFactory.spec.ts.snap deleted file mode 100644 index 6f652604..00000000 --- a/test/__snapshots__/RewardSplitterFactory.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RewardSplitterFactory splitter deployment gas 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 138096, -} -`; diff --git a/test/__snapshots__/SharedMevEscrow.spec.ts.snap b/test/__snapshots__/SharedMevEscrow.spec.ts.snap deleted file mode 100644 index d26d366c..00000000 --- a/test/__snapshots__/SharedMevEscrow.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SharedMevEscrow vault deployment gas 1`] = ` -Object { - "calldataByteLength": 683, - "gasUsed": 167457, -} -`; diff --git a/test/__snapshots__/VaultsRegistry.spec.ts.snap b/test/__snapshots__/VaultsRegistry.spec.ts.snap deleted file mode 100644 index 6926a4ab..00000000 --- a/test/__snapshots__/VaultsRegistry.spec.ts.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`VaultsRegistry factory can add vault 1`] = ` -Object { - "calldataByteLength": 324, - "gasUsed": 352920, -} -`; - -exports[`VaultsRegistry owner can add factory 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 47318, -} -`; - -exports[`VaultsRegistry owner can add vault 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 49672, -} -`; - -exports[`VaultsRegistry owner can register implementation contract 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 47489, -} -`; - -exports[`VaultsRegistry owner can remove factory 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 25481, -} -`; - -exports[`VaultsRegistry owner can remove implementation 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 25432, -} -`; diff --git a/test/gnosis/GnoRewardSplitter.t.sol b/test/gnosis/GnoRewardSplitter.t.sol new file mode 100644 index 00000000..b3e969aa --- /dev/null +++ b/test/gnosis/GnoRewardSplitter.t.sol @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; +import {IRewardSplitter} from '../../contracts/interfaces/IRewardSplitter.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {IVaultGnoStaking} from '../../contracts/interfaces/IVaultGnoStaking.sol'; +import {IVaultEnterExit} from '../../contracts/interfaces/IVaultEnterExit.sol'; +import {IVaultFee} from '../../contracts/interfaces/IVaultFee.sol'; +import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; +import {Errors} from '../../contracts/libraries/Errors.sol'; +import {GnoRewardSplitter} from '../../contracts/misc/GnoRewardSplitter.sol'; +import {RewardSplitterFactory} from '../../contracts/misc/RewardSplitterFactory.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; + +contract GnoRewardSplitterTest is Test, GnoHelpers { + ForkContracts public contracts; + address public vault; + GnoRewardSplitter public rewardSplitter; + RewardSplitterFactory public splitterFactory; + + address public admin; + address public shareholder1; + address public shareholder2; + address public depositor; + + uint128 public constant SHARE1 = 7000; // 70% + uint128 public constant SHARE2 = 3000; // 30% + uint256 public constant DEPOSIT_AMOUNT = 100 ether; // 100 GNO tokens + + function setUp() public { + // Get fork contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr('admin'); + shareholder1 = makeAddr('shareholder1'); + shareholder2 = makeAddr('shareholder2'); + depositor = makeAddr('depositor'); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(depositor, 100 ether); + + // Fund accounts with GNO for testing + _mintGnoToken(admin, 100 ether); + _mintGnoToken(depositor, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + name: 'Test GNO Vault', + symbol: 'TGNO', + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + vault = _getOrCreateVault(VaultType.GnoErc20Vault, admin, initParams, false); + + // Deploy GnoRewardSplitter implementation + GnoRewardSplitter impl = new GnoRewardSplitter(address(contracts.gnoToken)); + + // Deploy RewardSplitterFactory + splitterFactory = new RewardSplitterFactory(address(impl)); + + // Create GnoRewardSplitter for the vault + vm.prank(admin); + address splitterAddr = splitterFactory.createRewardSplitter(vault); + rewardSplitter = GnoRewardSplitter(payable(splitterAddr)); + + // Set RewardSplitter as fee recipient + vm.prank(admin); + IVaultFee(vault).setFeeRecipient(address(rewardSplitter)); + + // Configure shares in RewardSplitter + vm.startPrank(admin); + rewardSplitter.increaseShares(shareholder1, SHARE1); + rewardSplitter.increaseShares(shareholder2, SHARE2); + vm.stopPrank(); + + // Collateralize vault to enable rewards + _collateralizeGnoVault(vault); + } + + function test_initialization() public view { + assertEq(rewardSplitter.vault(), vault, 'Vault address not set correctly'); + assertEq(rewardSplitter.totalShares(), SHARE1 + SHARE2, 'Total shares not set correctly'); + assertEq( + rewardSplitter.sharesOf(shareholder1), + SHARE1, + 'Shareholder1 shares not set correctly' + ); + assertEq( + rewardSplitter.sharesOf(shareholder2), + SHARE2, + 'Shareholder2 shares not set correctly' + ); + } + + function test_generateAndDistributeRewards() public { + // Generate rewards by depositing and simulating profit + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + // Get initial vault shares of reward splitter + uint256 initialShares = IVaultState(vault).getShares(address(rewardSplitter)); + + // Simulate rewards/profit + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), // 1 GNO reward + 0 + ); + + // Update vault state to distribute rewards + IVaultState(vault).updateState(harvestParams); + + // Verify RewardSplitter has received vault shares as rewards + uint256 newShares = IVaultState(vault).getShares(address(rewardSplitter)); + assertGt(newShares, initialShares, 'RewardSplitter should have received vault shares'); + + // Sync rewards in the splitter + _startSnapshotGas('GnoRewardSplitter_syncRewards'); + rewardSplitter.syncRewards(); + _stopSnapshotGas(); + + // Check available rewards + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + assertGt(rewards1, 0, 'Shareholder1 should have rewards'); + assertGt(rewards2, 0, 'Shareholder2 should have rewards'); + + // Record initial GNO balances + uint256 shareholder1BalanceBefore = IERC20(contracts.gnoToken).balanceOf(shareholder1); + + // Shareholder1 enters exit queue with their vault shares + vm.prank(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas('GnoRewardSplitter_enterExitQueue'); + uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); + _stopSnapshotGas(); + + // Process the exit queue + harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Shareholder1 claims exited assets + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, 'Exit queue index not found'); + + vm.prank(shareholder1); + IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify shareholder1 received GNO rewards + assertGt( + IERC20(contracts.gnoToken).balanceOf(shareholder1) - shareholder1BalanceBefore, + 0, + 'Shareholder1 should receive GNO rewards' + ); + + // Shareholder2 directly claims tokens without going through exit queue + vm.prank(shareholder2); + _startSnapshotGas('GnoRewardSplitter_claimVaultTokens'); + rewardSplitter.claimVaultTokens(rewards2, shareholder2); + _stopSnapshotGas(); + + // Verify shareholder2 received vault tokens + assertGt(IVaultState(vault).getShares(shareholder2), 0, 'Shareholder2 should receive vault tokens directly'); + } + + function test_maxWithdrawal() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Get total rewards available + uint256 totalRewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(totalRewards, 0, 'Should have rewards to withdraw'); + + // Withdraw using max value (should withdraw all available rewards) + vm.prank(shareholder1); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); + _startSnapshotGas('GnoRewardSplitter_enterExitQueueMaxWithdrawal'); + rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); + _stopSnapshotGas(); + + // Check rewards were fully claimed + assertEq(rewardSplitter.rewardsOf(shareholder1), 0, 'All rewards should be withdrawn'); + } + + function test_notHarvestedInSyncRewards() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + // Force vault to need harvesting without actually harvesting + // First set a reward to make it need harvesting + _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + // Mock the isStateUpdateRequired to return true + vm.mockCall( + vault, + abi.encodeWithSelector(IVaultState.isStateUpdateRequired.selector), + abi.encode(true) + ); + + // Attempt to sync rewards when vault needs harvesting + vm.expectRevert(IRewardSplitter.NotHarvested.selector); + rewardSplitter.syncRewards(); + } + + function test_exitRequestNotProcessedInClaimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + rewardSplitter.setClaimOnBehalf(true); + + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Enter exit queue on behalf of shareholder1 + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(admin); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + + // Try to claim without waiting for the delay period + // (Exit request is not yet processed) + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + + vm.prank(admin); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_accessDeniedInEnterExitQueueOnBehalf() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Claim on behalf is disabled by default + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + + // Should fail with AccessDenied since claim-on-behalf is disabled + vm.prank(admin); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + } + + function test_claimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); + _startSnapshotGas('GnoRewardSplitter_setClaimOnBehalf'); + rewardSplitter.setClaimOnBehalf(true); + _stopSnapshotGas(); + + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + + IVaultState(vault).updateState(harvestParams); + + // Sync rewards + rewardSplitter.syncRewards(); + + // Check available rewards + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(rewards, 0, 'Shareholder should have rewards'); + + // Someone else enters exit queue on behalf of shareholder1 + vm.prank(admin); + uint256 timestamp = vm.getBlockTimestamp(); + vm.expectEmit(true, false, false, false); + emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point + _startSnapshotGas('GnoRewardSplitter_enterExitQueueOnBehalf'); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + _stopSnapshotGas(); + + // Verify position is tracked correctly + assertEq( + rewardSplitter.exitPositions(positionTicket), + shareholder1, + 'Exit position should be tracked' + ); + + // Process the exit queue + harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Someone else claims on behalf of shareholder1 + uint256 shareholder1BalanceBefore = IERC20(contracts.gnoToken).balanceOf(shareholder1); + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + + // Expected reward amount to be claimed + (, , uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( + address(rewardSplitter), + positionTicket, + timestamp, + uint256(exitQueueIndex) + ); + + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); + _startSnapshotGas('GnoRewardSplitter_claimExitedAssetsOnBehalf'); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify shareholder1 received GNO tokens + assertGt( + IERC20(contracts.gnoToken).balanceOf(shareholder1) - shareholder1BalanceBefore, + 0, + 'Shareholder should receive claimed GNO tokens' + ); + } + + function test_gnoTokenTransfer() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Get shareholder1's rewards + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(rewards, 0, 'Shareholder should have rewards'); + + // Set up for exit and claim + vm.prank(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = rewardSplitter.enterExitQueue(rewards, shareholder1); + + // Process exit queue + harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Check GNO token balance before claim + uint256 initialBalance = IERC20(contracts.gnoToken).balanceOf(shareholder1); + + // Claim exited assets (this should transfer GNO tokens) + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + + vm.prank(shareholder1); + _startSnapshotGas('GnoRewardSplitter_claimExitedAssets'); + IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify GNO tokens were transferred to shareholder1 + uint256 finalBalance = IERC20(contracts.gnoToken).balanceOf(shareholder1); + assertGt(finalBalance, initialBalance, 'GNO tokens should be transferred to shareholder'); + } + + function test_manageShares() public { + // Initial shares amount + uint256 initialSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); + uint256 initialTotalShares = rewardSplitter.totalShares(); + + // Test increase shares + uint128 increaseAmount = 1000; + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesIncreased(shareholder1, increaseAmount); + _startSnapshotGas('GnoRewardSplitter_increaseShares'); + rewardSplitter.increaseShares(shareholder1, increaseAmount); + _stopSnapshotGas(); + + uint256 newSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); + uint256 newTotalShares = rewardSplitter.totalShares(); + assertEq(newSharesShareholder1, initialSharesShareholder1 + increaseAmount, "Shares should be increased correctly"); + assertEq(newTotalShares, initialTotalShares + increaseAmount, "Total shares should be increased correctly"); + + // Test decrease shares + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesDecreased(shareholder1, increaseAmount); + _startSnapshotGas('GnoRewardSplitter_decreaseShares'); + rewardSplitter.decreaseShares(shareholder1, increaseAmount); + _stopSnapshotGas(); + + uint256 finalSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); + uint256 finalTotalShares = rewardSplitter.totalShares(); + assertEq(finalSharesShareholder1, initialSharesShareholder1, "Shares should be decreased back to original amount"); + assertEq(finalTotalShares, initialTotalShares, "Total shares should be decreased back to original amount"); + } + + function test_syncRewards() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + // Set reward and update vault state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + IVaultState(vault).updateState(harvestParams); + + // Initial state before sync + uint256 initialTotalRewards = rewardSplitter.totalRewards(); + + // Should be able to sync rewards + assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards'); + + // Sync rewards + vm.expectEmit(false, false, false, false); // We don't check the parameters + emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values + _startSnapshotGas('GnoRewardSplitter_syncRewardsDetailed'); + rewardSplitter.syncRewards(); + _stopSnapshotGas(); + + // Verify rewards were synced + uint256 newTotalRewards = rewardSplitter.totalRewards(); + assertGt(newTotalRewards, initialTotalRewards, 'Total rewards should increase after sync'); + + // Verify proportional distribution + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + + assertGt(rewards1, 0, 'Shareholder1 should have rewards after sync'); + assertGt(rewards2, 0, 'Shareholder2 should have rewards after sync'); + + // Verify distribution is proportional to shares + uint256 expectedRewards1 = (newTotalRewards * SHARE1) / (SHARE1 + SHARE2); + uint256 expectedRewards2 = (newTotalRewards * SHARE2) / (SHARE1 + SHARE2); + + assertApproxEqRel( + rewards1, + expectedRewards1, + 0.0001e18, // 0.01% tolerance + 'Shareholder1 rewards should be proportional to shares' + ); + + assertApproxEqRel( + rewards2, + expectedRewards2, + 0.0001e18, // 0.01% tolerance + 'Shareholder2 rewards should be proportional to shares' + ); + } + + function test_updateVaultState() public { + // Generate rewards with a callback from reward splitter + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), + 0 + ); + + // Update vault state through reward splitter + _startSnapshotGas('GnoRewardSplitter_updateVaultState'); + rewardSplitter.updateVaultState(harvestParams); + _stopSnapshotGas(); + + // Verify rewards can be synced + assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards after update'); + + // Sync and verify rewards + rewardSplitter.syncRewards(); + uint256 totalRewards = rewardSplitter.totalRewards(); + assertGt(totalRewards, 0, 'Total rewards should be greater than zero'); + } +} diff --git a/test/gnosis/__snapshots__/GnoBlocklistErc20Vault.spec.ts.snap b/test/gnosis/__snapshots__/GnoBlocklistErc20Vault.spec.ts.snap deleted file mode 100644 index b4ed778a..00000000 --- a/test/gnosis/__snapshots__/GnoBlocklistErc20Vault.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoBlocklistErc20Vault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 86543, -} -`; - -exports[`GnoBlocklistErc20Vault mint osToken can mint from not blocked user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178454, -} -`; - -exports[`GnoBlocklistErc20Vault transfer can transfer 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 58878, -} -`; diff --git a/test/gnosis/__snapshots__/GnoBlocklistVault.spec.ts.snap b/test/gnosis/__snapshots__/GnoBlocklistVault.spec.ts.snap deleted file mode 100644 index f1bf009d..00000000 --- a/test/gnosis/__snapshots__/GnoBlocklistVault.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoBlocklistVault deposit can be called by not blocked user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 84627, -} -`; - -exports[`GnoBlocklistVault mint osToken can mint from not blocked user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178265, -} -`; diff --git a/test/gnosis/__snapshots__/GnoErc20Vault.spec.ts.snap b/test/gnosis/__snapshots__/GnoErc20Vault.spec.ts.snap deleted file mode 100644 index 3e362807..00000000 --- a/test/gnosis/__snapshots__/GnoErc20Vault.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoErc20Vault deposit emits transfer event 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 82082, -} -`; - -exports[`GnoErc20Vault enter exit queue emits transfer event 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 91197, -} -`; diff --git a/test/gnosis/__snapshots__/GnoGenesisVault.spec.ts.snap b/test/gnosis/__snapshots__/GnoGenesisVault.spec.ts.snap deleted file mode 100644 index 98ad4b66..00000000 --- a/test/gnosis/__snapshots__/GnoGenesisVault.spec.ts.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoGenesisVault migrate migrates from rewardToken 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 227808, -} -`; - -exports[`GnoGenesisVault pulls withdrawals on claim exited assets 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 125488, -} -`; - -exports[`GnoGenesisVault update state deducts rewards on first state update 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 170019, -} -`; - -exports[`GnoGenesisVault update state skips updating legacy with zero total assets 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 165588, -} -`; - -exports[`GnoGenesisVault update state splits penalty between rewardToken and vault 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 120294, -} -`; - -exports[`GnoGenesisVault update state splits reward between rewardToken and vault 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 187107, -} -`; diff --git a/test/gnosis/__snapshots__/GnoOwnMevEscrow.spec.ts.snap b/test/gnosis/__snapshots__/GnoOwnMevEscrow.spec.ts.snap deleted file mode 100644 index 83e41998..00000000 --- a/test/gnosis/__snapshots__/GnoOwnMevEscrow.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoOwnMevEscrow vault deployment gas 1`] = ` -Object { - "calldataByteLength": 719, - "gasUsed": 173636, -} -`; diff --git a/test/gnosis/__snapshots__/GnoPrivErc20Vault.spec.ts.snap b/test/gnosis/__snapshots__/GnoPrivErc20Vault.spec.ts.snap deleted file mode 100644 index 59cc2e56..00000000 --- a/test/gnosis/__snapshots__/GnoPrivErc20Vault.spec.ts.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoPrivErc20Vault deposit can be called by whitelisted user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 84571, -} -`; - -exports[`GnoPrivErc20Vault mint osToken can mint from not whitelisted user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178479, -} -`; - -exports[`GnoPrivErc20Vault transfer can transfer to whitelisted user 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 58906, -} -`; diff --git a/test/gnosis/__snapshots__/GnoPrivVault.spec.ts.snap b/test/gnosis/__snapshots__/GnoPrivVault.spec.ts.snap deleted file mode 100644 index 4388deb5..00000000 --- a/test/gnosis/__snapshots__/GnoPrivVault.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoPrivVault deposit can be called by whitelisted user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 82655, -} -`; - -exports[`GnoPrivVault mint osToken can mint from not whitelisted user 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 178290, -} -`; diff --git a/test/gnosis/__snapshots__/GnoSharedMevEscrow.spec.ts.snap b/test/gnosis/__snapshots__/GnoSharedMevEscrow.spec.ts.snap deleted file mode 100644 index 0c6ecffa..00000000 --- a/test/gnosis/__snapshots__/GnoSharedMevEscrow.spec.ts.snap +++ /dev/null @@ -1,8 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoSharedMevEscrow vault deployment gas 1`] = ` -Object { - "calldataByteLength": 728, - "gasUsed": 177185, -} -`; diff --git a/test/gnosis/__snapshots__/GnoVault.register.spec.ts.snap b/test/gnosis/__snapshots__/GnoVault.register.spec.ts.snap deleted file mode 100644 index 9757e799..00000000 --- a/test/gnosis/__snapshots__/GnoVault.register.spec.ts.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoVault - register multiple validators pulls withdrawals on multiple validators registration 1`] = ` -Object { - "calldataByteLength": 3364, - "gasUsed": 701776, -} -`; - -exports[`GnoVault - register multiple validators succeeds 1`] = ` -Object { - "calldataByteLength": 3364, - "gasUsed": 721972, -} -`; - -exports[`GnoVault - register single validator pulls withdrawals on single validator registration 1`] = ` -Object { - "calldataByteLength": 1188, - "gasUsed": 364662, -} -`; - -exports[`GnoVault - register single validator succeeds 1`] = ` -Object { - "calldataByteLength": 1188, - "gasUsed": 384858, -} -`; diff --git a/test/gnosis/__snapshots__/GnoVault.spec.ts.snap b/test/gnosis/__snapshots__/GnoVault.spec.ts.snap deleted file mode 100644 index 7e792258..00000000 --- a/test/gnosis/__snapshots__/GnoVault.spec.ts.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoVault deposit deposit 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 80406, -} -`; - -exports[`GnoVault pulls withdrawals on claim exited assets 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 95889, -} -`; - -exports[`GnoVault swap xdai to gno can swap all xdai to gno 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 130585, -} -`; - -exports[`GnoVault swap xdai to gno skips swapping when balance less than 1 gwei xdai 1`] = ` -Object { - "calldataByteLength": 4, - "gasUsed": 29184, -} -`; diff --git a/test/gnosis/__snapshots__/GnoVault.state.spec.ts.snap b/test/gnosis/__snapshots__/GnoVault.state.spec.ts.snap deleted file mode 100644 index 7606eafd..00000000 --- a/test/gnosis/__snapshots__/GnoVault.state.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoVault Own MEV Escrow does not include MEV rewards in total assets delta 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 113154, -} -`; - -exports[`GnoVault Shared MEV Escrow does not include MEV rewards in total assets delta 1`] = ` -Object { - "calldataByteLength": 196, - "gasUsed": 120218, -} -`; diff --git a/test/gnosis/__snapshots__/GnoVault.upgrade.spec.ts.snap b/test/gnosis/__snapshots__/GnoVault.upgrade.spec.ts.snap deleted file mode 100644 index 6f69a6d8..00000000 --- a/test/gnosis/__snapshots__/GnoVault.upgrade.spec.ts.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GnoVault - upgrade does not modify the state variables 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 105491, -} -`; - -exports[`GnoVault - upgrade does not modify the state variables 2`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 105705, -} -`; - -exports[`GnoVault - upgrade does not modify the state variables 3`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 105583, -} -`; - -exports[`GnoVault - upgrade does not modify the state variables 4`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 106160, -} -`; - -exports[`GnoVault - upgrade does not modify the state variables 5`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 106374, -} -`; - -exports[`GnoVault - upgrade does not modify the state variables 6`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 106264, -} -`; - -exports[`GnoVault - upgrade does not modify the state variables 7`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 105581, -} -`; diff --git a/test/gnosis/__snapshots__/XdaiExchange.spec.ts.snap b/test/gnosis/__snapshots__/XdaiExchange.spec.ts.snap deleted file mode 100644 index 12d824c0..00000000 --- a/test/gnosis/__snapshots__/XdaiExchange.spec.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`XdaiExchange balancer pool id can be set by the admin 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 52057, -} -`; - -exports[`XdaiExchange max slippage can be set by the admin 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 34861, -} -`; - -exports[`XdaiExchange stale price time delta can be set by the admin 1`] = ` -Object { - "calldataByteLength": 36, - "gasUsed": 34783, -} -`; - -exports[`XdaiExchange swap successfully swaps 1`] = ` -Object { - "calldataByteLength": 68, - "gasUsed": 68132, -} -`; - -exports[`XdaiExchange upgrade upgrades 1`] = ` -Object { - "calldataByteLength": 100, - "gasUsed": 36983, -} -`; diff --git a/test/shared/artifacts/EthBlocklistErc20Vault.json b/test/shared/artifacts/EthBlocklistErc20Vault.json deleted file mode 100644 index 3202a7db..00000000 --- a/test/shared/artifacts/EthBlocklistErc20Vault.json +++ /dev/null @@ -1,2057 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthBlocklistErc20Vault", - "sourceName": "contracts/vaults/ethereum/EthBlocklistErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61020034620001f25762005d0838819003601f8101601f191683016001600160401b03811184821017620001f65783928291604052833961012091829181010312620001f25762000050826200020a565b6200005e602084016200020a565b6200006c604085016200020a565b916200007b606086016200020a565b62000089608087016200020a565b916200009860a088016200020a565b93620000a760c089016200020a565b95620000b660e08a016200020a565b91610100809a01519360805260a05260c0523060e052620000d66200021f565b468852865261014046815261016091825260018060a01b038061018094168452806101a0951685526101c0951685526101e0958652620001156200021f565b60405196615a499889620002bf8a396080518981816117f3015281816119c70152818161316901528181613e0501526158b6015260a0518961148a015260c0518981816140f60152614217015260e0518981816116090152613bc70152518861272b01525187612d6001525186613e7b01525185611b6d0152518481816104dd01528181610b0601528181612e42015281816135a80152818161476f015281816148ca0152614a71015251838181610bc5015281816111860152818161366701526149f501525182611e6001525181818161270601526131b10152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620001f257565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620002ac576001600160401b036002600160401b0319828216016200026d57505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe60806040526004361015610022575b3615610018575f80fd5b610020612e1a565b005b5f3560e01c806301d523b6146103c757806301e1d114146103c2578063066055e0146103bd57806306fdde03146103b857806307a2d13a146103b3578063095ea7b3146103ae57806314c4184b146103a957806318160ddd1461036d57806318f72950146103a45780631a7ff5531461039f578063201b9eb51461039a57806323b872dd146103955780632999ad3f146103905780632cdf74011461038b578063313ce567146103865780633229fa951461038157806333194c0a1461037c5780633644e5151461037757806336fe59d2146103725780633a98ef391461036d578063439fab911461036857806343e82a7914610363578063469048401461035e5780634ec96b22146103595780634f1ef2861461035457806352d1902d1461034f57806353156f281461034a57806354fd4d50146103455780635c60da1b146103405780635cfc1a511461033b57806360d60e6e1461033657806370a08231146102be57806372b410a814610331578063754c38881461032c57806376b58b90146103275780637ecebe00146103225780637fd6f15c1461031d57806383d430d5146103185780638697d2c2146103135780638ceab9aa1461030e5780639267842a1461030957806395d89b4114610304578063a49a1e7d146102ff578063a9059cbb146102fa578063ac9650d8146102f5578063ad3cb1cc146102f0578063b1f0e7c7146102eb578063b45a1eb5146102e6578063c6e6f592146102e1578063d0a64ddc146102dc578063d505accf146102d7578063d83ad00c146102d2578063dd62ed3e146102cd578063e74b981b146102c8578063ee3bd5df146102c3578063f04da65b146102be578063f45bf3d2146102b9578063f851a440146102b45763f9609f080361000e57612585565b61255d565b61251c565b61178d565b6124f6565b6124c9565b612485565b61243a565b612225565b6121ed565b6121cf565b61219d565b612179565b612134565b6120cf565b61202e565b611fdc565b611f38565b611d44565b611cec565b611b41565b611971565b61194d565b611912565b6118c1565b611855565b6117c8565b6116ed565b6116d3565b61169f565b611684565b611660565b6115f7565b611372565b61128c565b611264565b611157565b611091565b6108f5565b611022565b611008565b610fce565b610fa2565b610f87565b610f6d565b610adc565b610a00565b6109dd565b610981565b61091b565b6108cc565b61082a565b61080c565b610746565b61048d565b61045c565b6103ef565b6001600160a01b038116036103dd57565b5f80fd5b908160809103126103dd5790565b60803660031901126103dd57600435610407816103cc565b604435610413816103cc565b606435906001600160401b0382116103dd5760209261044161043c61044a9436906004016103e1565b612670565b6024359061275d565b604051908152f35b5f9103126103dd57565b346103dd575f3660031901126103dd57602060cf5460801c604051908152f35b6001600160801b038116036103dd57565b346103dd5760203660031901126103dd576004356104aa8161047c565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561062c575f916105fd575b50335f90815261016e60205260409020610526906125b7565b916001600160801b0361054084516001600160801b031690565b16156105eb57610599836105566105e795612e2d565b6105806105738461056e84516001600160801b031690565b612608565b6001600160801b03168252565b335f90815261016e60205260409020612621565b612621565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61061f915060203d602011610625575b61061781836106cb565b81019061259d565b5f61050d565b503d61060d565b6125ac565b90600182811c9216801561065f575b602083101461064b57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610640565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761069857604052565b610669565b6001600160401b03811161069857604052565b608081019081106001600160401b0382111761069857604052565b90601f801991011681019081106001600160401b0382111761069857604052565b5f5b8381106106fd5750505f910152565b81810151838201526020016106ee565b90602091610726815180928185528580860191016106ec565b601f01601f1916010190565b90602061074392818152019061070d565b90565b346103dd575f3660031901126103dd576040515f805461076581610631565b808452906020906001908181169081156107e2575060011461079e575b6105e785610792818703826106cb565b60405191829182610732565b5f80805293505f805160206159748339815191525b8385106107cf57505050508101602001610792826105e7610782565b80548686018401529382019381016107b3565b8695506105e79693506020925061079294915060ff191682840152151560051b8201019293610782565b346103dd5760203660031901126103dd57602061044a60043561264a565b346103dd5760403660031901126103dd57600435610847816103cc565b6001600160a01b038116906024359082156108ba576108828291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b346103dd575f3660031901126103dd5761026a546040516001600160a01b039091168152602090f35b346103dd575f3660031901126103dd5760206001600160801b0360cf5416604051908152f35b60603660031901126103dd57600435610933816103cc565b60243561093f816103cc565b604435906001600160401b0382116103dd5760209261096861043c61044a9436906004016103e1565b61097133613464565b61097a81613464565b34906145e9565b346103dd5760203660031901126103dd576004356001600160401b0381116103dd5761043c6100209136906004016103e1565b60609060031901126103dd576004356109cc816103cc565b9060243590604435610743816103cc565b346103dd57602061044a6109f0366109b4565b916109fa33613464565b336146b0565b346103dd5760603660031901126103dd57600435610a1d816103cc565b60243590610a2a826103cc565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610a7a575b610a6e84610a69858883614944565b613485565b60405160018152602090f35b919093818503948511610aae575f928352600260209081526040808520338652909152909220939093559180610a6e610a5a565b6125dc565b60609060031901126103dd5760043590602435610acf816103cc565b90604435610743816103cc565b346103dd57610aea36610ab3565b906001600160a01b03808316156108ba57610b03613dea565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103dd5760408051631d8557d760e01b815260049491905f81878183875af1801561062c57610f54575b506001600160a01b0383165f90815261016e60205260409020610b76906125b7565b6001600160801b039283610b9183516001600160801b031690565b1615610f4457610ba082612e2d565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561062c575f98610f13575b50602097888101956001600160401b03918280610c198a516001600160401b031690565b1614610f0357908c92918751918c8380610c456303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561062c57610c71938e5f94610ede575b5050516001600160801b03165b1690612f5c565b96610c95610c8f8a60018060a01b03165f5260d360205260405f2090565b5461264a565b928389118015610ece575b610ebe57908b610cde9392610cbc89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561062c57670de0b6b3a764000094610d2d948e5f95610e91575b5050610d1f610d11610d2592612b36565b93516001600160401b031690565b93612b36565b921690612fd0565b1015610e83578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561062c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610e6095610dd793610e65575b5050610dba610573610daa8c61431c565b83516001600160801b0316612608565b6001600160a01b0386165f90815261016e60205260409020612621565b610de0826143e9565b90610e1f610e04610df08561431c565b60cf5460801c5b036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610e29828661537b565b610e33838961434f565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610e7b92903d106106255761061781836106cb565b505f80610d99565b835163185cfc6d60e11b8152fd5b610d25929550610eb4610d1f9282610d1193903d106106255761061781836106cb565b959250508e610d00565b875163efda1a2760e01b81528590fd5b50610ed76126b7565b8911610ca0565b610c6a9294509081610efb92903d106106255761061781836106cb565b92908e610c5d565b8651630709133160e01b81528490fd5b610f3691985060603d606011610f3d575b610f2e81836106cb565b810190613530565b965f610bf5565b503d610f24565b825163673f032f60e11b81528790fd5b80610f61610f679261069d565b80610452565b5f610b54565b346103dd575f3660031901126103dd57602061044a6126b7565b346103dd575f3660031901126103dd57602060405160128152f35b346103dd575f3660031901126103dd576020610fbc6126ed565b6040516001600160a01b039091168152f35b346103dd575f3660031901126103dd5760206040517fad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c8152f35b346103dd575f3660031901126103dd57602061044a612728565b602061044a611030366109b4565b9161275d565b9181601f840112156103dd578235916001600160401b0383116103dd57602083818601950101116103dd57565b60206003198201126103dd57600435906001600160401b0382116103dd5761108d91600401611036565b9091565b61109a36611063565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015611143575b61113157680100000000000000036110f49368ffffffffffffffffff1916178455612868565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b03841610156110ce565b346103dd5761116536610ab3565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561062c5782915f91611235575b501633036112235781610e606111f086867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd39661358a565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611257915060203d60201161125d575b61124f81836106cb565b81019061278a565b5f6111b8565b503d611245565b346103dd575f3660031901126103dd57609c546040516001600160a01b039091168152602090f35b346103dd5760203660031901126103dd576004356112a9816103cc565b60018060a01b03165f5261016e602052602060405f20604051906112cc8261067d565b54906001600160801b03918281169081835260801c848301526112f4575b5116604051908152f35b6112fd81612e2d565b6112ea565b6040519060a082018281106001600160401b0382111761069857604052565b6001600160401b03811161069857601f01601f191660200190565b92919261134882611321565b9161135660405193846106cb565b8294818452818301116103dd578281602093845f960137010152565b6040806003193601126103dd57600490813561138d816103cc565b6024356001600160401b0381116103dd57366023820112156103dd576113bc903690602481870135910161133c565b916113c5613bbd565b8051926113fc846113ee60209363439fab9160e01b85840152846024840152604483019061070d565b03601f1981018652856106cb565b611404613bbd565b61140c613c16565b6001600160a01b038381168015929190879084156115c2575b8415611554575b84156114f1575b5050821561145b575b505061144c576100208383614dc1565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561062c575f926114c4575b5050155f8061143c565b6114e39250803d106114ea575b6114db81836106cb565b810190612946565b5f806114ba565b503d6114d1565b855163054fd4d560e41b81529294508391839182905afa90811561062c57879160ff915f91611527575b5016141591865f611433565b6115479150843d861161154d575b61153f81836106cb565b810190614dac565b5f61151b565b503d611535565b935050835163198ca60560e11b815282818981875afa90811561062c5788917fad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c915f916115a5575b5014159361142c565b6115bc9150853d87116106255761061781836106cb565b5f61159c565b5f805160206159b48339815191525490945084906115f0906001600160a01b03165b6001600160a01b031690565b1493611425565b346103dd575f3660031901126103dd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361164e5760206040515f805160206159b48339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126103dd576001600160a01b0361167b6126ed565b16330361122357005b346103dd575f3660031901126103dd57602060405160038152f35b346103dd575f3660031901126103dd575f805160206159b4833981519152546040516001600160a01b039091168152602090f35b346103dd575f3660031901126103dd57602061044a612938565b346103dd5760203660031901126103dd5760d180549081905f6004355b84821061173b57505050811015611730576105e7905b6040519081529081906020820190565b506105e75f19611720565b909193808316906001818518811c8301809311610aae575f8790525f805160206159f48339815191528301546001600160a01b0316841015611782575050935b919061170a565b90959101925061177b565b346103dd5760203660031901126103dd576004356117aa816103cc565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561062c576020915f91611838575b506040519015158152f35b61184f9150823d84116114ea576114db81836106cb565b5f61182d565b346103dd5760203660031901126103dd57600435611872816103cc565b61187a613c16565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103dd5760803660031901126103dd576105e76118f56004356118e4816103cc565b606435906044359060243590612968565b604080519384526020840192909252908201529081906060820190565b346103dd5760203660031901126103dd5760043561192f816103cc565b60018060a01b03165f526003602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57602061ffff609c5460a01c16604051908152f35b346103dd576003196040368201126103dd5760049081356001600160401b038082116103dd5760a08285019383360301126103dd576024359081116103dd576119bd9036908501611036565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103dd5760405163837d444160e01b8152905f908290818381611a108c828f01612a4a565b03925af1801561062c57611b2e575b50611a28613dea565b611a30612d4b565b9081163314159182611aff575b50509050611aee576044019160b0611a558484612ac8565b90500480158015611ad6575b611ac657611a76611a706126b7565b91612b1d565b11611ab7575060b0611a888383612ac8565b9050145f14611aa45761002091611a9e91612ac8565b90614209565b61002091611ab191612ac8565b906140e1565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611ae18484612ac8565b905060b082021415611a61565b604051634ca8886760e01b81528390fd5b611b229250611b1c611b2694611b1488613e75565b92369161133c565b91613f50565b1590565b805f80611a3d565b80610f61611b3b9261069d565b5f611a1f565b346103dd5760603660031901126103dd57600435602435611b66604435828433612968565b9192611b927f000000000000000000000000000000000000000000000000000000000000000082612b53565b42108015611ce4575b8015611cdc575b611cca577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611bfd611be2611bd78661431c565b60d05460801c612608565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611c419190611c306080826106cb565b5190205f5260d260205260405f2090565b555f9360018311611c7a575b50505050611c5b823361434f565b604080519485526020850191909152830152339180606081015b0390a2005b611cc092939450611c8b9088612b53565b60408051336020820190815291810193909352606083018290529094909190611c309082608081015b039081018352826106cb565b555f808080611c4d565b604051630e3d8e8d60e11b8152600490fd5b508215611ba2565b508115611b9b565b346103dd5760403660031901126103dd576020600435611d18602435611d11816103cc565b8233614fae565b90611d2233613485565b60405190815230905f805160206159d4833981519152843392a3604051908152f35b346103dd5760203660031901126103dd57600435611d60613dea565b335f90815261016e60205260409020611d78906125b7565b6001600160801b0380611d9283516001600160801b031690565b16156105eb578290611da383612e2d565b82516001600160801b03161610611f2657335f90815260d3602052604090205482611de4611dd884516001600160801b031690565b6001600160801b031690565b14611f1057611e089083611e02611dd885516001600160801b031690565b91612fd0565b91611e35611e28611e188361431c565b84516001600160801b0316610df7565b6001600160801b03168352565b335f90815261016e60205260409020611e4f908390612621565b611e976020611e8860018060a01b037f000000000000000000000000000000000000000000000000000000000000000016809633614fae565b9301516001600160801b031690565b833b156103dd5760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af191821561062c576105e792611efd575b506040519081529081906020820190565b80610f61611f0a9261069d565b5f611eec565b335f90815261016e602052604081205591611e4f565b604051636edcc52360e01b8152600490fd5b346103dd575f3660031901126103dd576040515f60018054611f5981610631565b80855291602091600181169081156107e25750600114611f83576105e785610792818703826106cb565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510611fc957505050508101602001610792826105e7610782565b8054868601840152938201938101611fad565b346103dd57611c757f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61200e36611063565b9290612018613c16565b6040519182916020835233956020840191612a2a565b346103dd5760403660031901126103dd5761205860043561204e816103cc565b6024359033614944565b61206133613485565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120a15750505050505090565b90919293949584806120bf600193603f198682030187528a5161070d565b9801930193019194939290612091565b346103dd5760203660031901126103dd576001600160401b036004358181116103dd57366023820112156103dd5780600401359182116103dd573660248360051b830101116103dd576105e79160246121289201612c9e565b6040519182918261206c565b346103dd575f3660031901126103dd576105e76040516121538161067d565b60058152640352e302e360dc1b602082015260405191829160208352602083019061070d565b346103dd575f3660031901126103dd576020610fbc612d4b565b801515036103dd57565b346103dd5760403660031901126103dd576100206004356121bd816103cc565b602435906121ca82612193565b612d82565b346103dd5760203660031901126103dd57602061044a6004356143e9565b346103dd5760203660031901126103dd5761002060043561220d816103cc565b612215613c16565b614478565b60ff8116036103dd57565b346103dd5760e03660031901126103dd57600435612242816103cc565b60243561224e816103cc565b6044359060643592608435906122638261221a565b6001600160a01b038381169590929086156108ba57428110612428576020915f91611cb461235689878a612319612298612728565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039161232d601f19938481018352826106cb565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa1561062c575f5192828416801590811561241b575b50612409576123f685916123e17f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610e60565b6040516323389ba560e21b8152600490fd5b905083831614155f61239c565b604051631ab7da6b60e01b8152600490fd5b346103dd575f3660031901126103dd5760206001600160801b0360d05416604051908152f35b60409060031901126103dd57600435612478816103cc565b90602435610743816103cc565b346103dd5760206124c061249836612460565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346103dd5760203660031901126103dd576100206004356124e9816103cc565b6124f1613c16565b6144bf565b346103dd575f3660031901126103dd5760206001600160801b0360d55416604051908152f35b346103dd5760203660031901126103dd57600435612539816103cc565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b346103dd575f3660031901126103dd576037546040516001600160a01b039091168152602090f35b602061044a61259336612460565b9061097133613464565b908160209103126103dd575190565b6040513d5f823e3d90fd5b906040516125c48161067d565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f190191908211610aae57565b6001600160801b039182169082160391908211610aae57565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161266257505090565b916107439260801c90612fd0565b61267c61268391613138565b91906132ce565b61268957565b6126916151c9565b8061269a575b50565b5f906040519081525f805160206159d483398151915260203092a3565b4760d0546001600160801b036126ce81831661264a565b9060d55416019060801c01908181115f146126e7570390565b50505f90565b6101a1546001600160a01b031680156127035790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036127555760045490565b6107436138a3565b90610743929161276c33613464565b61277533613464565b6127808334336145e9565b506109fa33613464565b908160209103126103dd5751610743816103cc565b359061ffff821682036103dd57565b9080601f830112156103dd578160206107439335910161133c565b906020828203126103dd5781356001600160401b03928382116103dd57019060a0828203126103dd576127fa611302565b928235845261280b6020840161279f565b602085015260408301358181116103dd57826128289185016127ae565b604085015260608301358181116103dd57826128459185016127ae565b606085015260808301359081116103dd5761286092016127ae565b608082015290565b6037549091906001600160a01b031661292e5760405163e7f6f22560e01b8152906020908183600481335afa92831561062c575f9361290f575b50604051636f4fa30f60e01b8152938285600481335afa90811561062c576128ea956128e5945f936128ec575b50506128de91928101906127c9565b9083613af1565b613bb1565b565b6128de9350908161290892903d1061125d5761124f81836106cb565b915f6128cf565b612927919350823d841161125d5761124f81836106cb565b915f6128a2565b50506128ea6139c9565b60d4548061074357505f1990565b908160209103126103dd575161074381612193565b91908203918211610aae57565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906129a681608081015b03601f1981018352826106cb565b5190205f5260d260205260405f20549182156129d6576129c7918391613c4f565b9091828103908111610aae5792565b5050505f905f905f90565b9035601e19823603018112156103dd5701602081359101916001600160401b0382116103dd5781360383136103dd57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061074392602081528235602082015260208301356040820152612a86612a7660408501856129e1565b84606085015260c0840191612a2a565b90612ab9612aae612a9a60608701876129e1565b601f19858703810160808701529591612a2a565b9460808101906129e1565b93909282860301910152612a2a565b903590601e19813603018212156103dd57018035906001600160401b0382116103dd576020019181360383136103dd57565b634e487b7160e01b5f52601260045260245ffd5b8115612b18570490565b612afa565b906801bc16d674ec8000009180830292830403610aae57565b90670de0b6b3a764000091828102928184041490151715610aae57565b91908201809211610aae57565b6001600160401b0381116106985760051b60200190565b90612b8182612b60565b612b8e60405191826106cb565b8281528092612b9f601f1991612b60565b01905f5b828110612baf57505050565b806060602080938501015201612ba3565b634e487b7160e01b5f52603260045260245ffd5b90821015612beb5761108d9160051b810190612ac8565b612bc0565b908092918237015f815290565b3d15612c27573d90612c0e82611321565b91612c1c60405193846106cb565b82523d5f602084013e565b606090565b6020818303126103dd578051906001600160401b0382116103dd570181601f820112156103dd578051612c5e81611321565b92612c6c60405194856106cb565b818452602082840101116103dd5761074391602080850191016106ec565b8051821015612beb5760209160051b010190565b919091612caa83612b77565b925f5b818110612cb957505050565b5f80612cc6838587612bd4565b60409391612cd8855180938193612bf0565b0390305af490612ce6612bfd565b9115612d0d575090600191612cfb8288612c8a565b52612d068187612c8a565b5001612cad565b9060448151106103dd57612d47612d3260049283810151602480918301019101612c2c565b925162461bcd60e51b81529283928301610732565b0390fd5b610109546001600160a01b03168061074357507f000000000000000000000000000000000000000000000000000000000000000090565b61026a546001600160a01b03919082163303611223576001600160a01b0381165f90815261026b60205260409020549215159260ff1615158314612e15576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b612e2333613464565b6126973433614521565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91612ec3575b5060208201916001600160801b03918284511691828214612ebc5783612eaf612eaa612eb7958584865116612fd0565b61431c565b16905261431c565b169052565b5050505050565b612edc915060203d6020116106255761061781836106cb565b5f612e7a565b90808202905f1981840990828083109203918083039214612f51576127109082821115612f3f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612fbf57670de0b6b3a76400009082821115612f3f577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146130435784831115612f3f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107439250612b0e565b908160609103126103dd578051916040602083015192015161074381612193565b81835290916001600160fb1b0383116103dd5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036103dd57604083015260408101356130c4816103cc565b6001600160a01b031660608381019190915281013536829003601e19018112156103dd5701602081359101906001600160401b0381116103dd578060051b360382136103dd5760a0836080806107439601520191613071565b9190915f8382019384129112908015821691151617610aae57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906131639060048301613095565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561062c575f915f905f95613289575b50841561323657816131ad6126ed565b16917f000000000000000000000000000000000000000000000000000000000000000016821461322f57509060205f92600460405180958193634641257d60e01b83525af190811561062c5761320a925f9261320e575b5061311d565b9190565b61322891925060203d6020116106255761061781836106cb565b905f613204565b908161323c575b50509190565b803b156103dd57604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561062c57613276575b80613236565b80610f616132839261069d565b5f613270565b919450506132af915060603d6060116132b7575b6132a781836106cb565b810190613050565b93905f61319d565b503d61329d565b600160ff1b8114610aae575f0390565b8015612697576132e3611dd860cf5460801c90565b5f82126133b557816132f491612b53565b90613301610e048361431c565b613316609c549161ffff8360a01c1690612ee2565b8015612e1557807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613354611dd860cf546001600160801b031690565b8061339f57505061339a90925b6001600160a01b0316916133758484615161565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b61339a926133af92039084612fd0565b92613361565b906133bf906132be565b6133d4611dd860d5546001600160801b031690565b806133f4575b50806133e4575050565b612eaa610e04916128ea9361295b565b9061345b7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161172061343f61343461342d8888612b53565b8785612fd0565b80809403960361431c565b6001600160801b03166001600160801b031960d554161760d555565b0390a15f6133da565b6001600160a01b03165f90815261026b602052604090205460ff1661122357565b60018060a01b0381165f5261016e60205260405f2090604051916134a88361067d565b54906001600160801b03918281169081855260801c602085015215612e15576134fb610c8f613500926134d9613dea565b6134e286612e2d565b6001600160a01b03165f90815260d36020526040902090565b6149d2565b9151161161350a57565b604051633684c65960e01b8152600490fd5b51906001600160401b03821682036103dd57565b908160609103126103dd5760405190606082018281106001600160401b038211176106985761358291604091825280516135698161047c565b84526135776020820161351c565b60208501520161351c565b604082015290565b92906001600160a01b0390818116156108ba576135a5613dea565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156103dd57604094855193631d8557d760e01b85526004945f81878183895af1801561062c57613890575b506001600160a01b0388165f90815261016e60205260409020613618906125b7565b906001600160801b0361363283516001600160801b031690565b16156138805761364182612e2d565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561062c57613861575b508651936303d1689d60e11b978886526020918287806136bb888c83019190602083019252565b0381845afa96871561062c575f97613842575b5086996136ee610c8f8d60018060a01b03165f5260d360205260405f2090565b88118015613832575b6138225790836137349261371287516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561062c575f859488946137799c613805575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561062c57610daa6137c0946137a393610573936128ea9a6137e7575b505061431c565b6001600160a01b0388165f90815261016e60205260409020612621565b6137e26137cc836143e9565b80976137dd610e04610df08761431c565b61537b565b61434f565b816137fd92903d106106255761061781836106cb565b505f8061379c565b61381b90873d89116106255761061781836106cb565b505f61374e565b825163efda1a2760e01b81528990fd5b5061383b6126b7565b88116136f7565b61385a919750833d85116106255761061781836106cb565b955f6136ce565b6138799060603d606011610f3d57610f2e81836106cb565b505f613694565b875163673f032f60e11b81528690fd5b80610f6161389d9261069d565b5f6135f6565b6040515f905f54906138b482610631565b9283825260209384830193600190866001821691825f146139a9575050600114613966575b505091816138ef613960936129989503826106cb565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f805160206159748339815191525b82841061399457505050820101816138ef6138d9565b8054868501860152879490930192810161397e565b60ff1916875292151560051b850190920192508391506138ef90506138d9565b6139d1614afe565b6139e6611dd860d0546001600160801b031690565b60018111613adf57600114613a5a575b60d654613a0161557b565b90808210613a1d575b5050613a155f60d655565b6128ea614adc565b5f8051602061599483398151915291613a509103613a3a816154a6565b604080519182525f602083015290918291820190565b0390a15f80613a0a565b613a93613a77613a7260cf546001600160801b031690565b6125f0565b6001600160801b03166001600160801b031960cf54161760cf55565b613aa86001600160801b031960d0541660d055565b613ab0615444565b5f8051602061599483398151915260405180613ad781905f60206040840193600181520152565b0390a16139f6565b604051630299325160e41b8152600490fd5b9190613afb614afe565b608082015190613b09614afe565b6001600160a01b03841680156108ba57613ba994613b9993613b82926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613b703394602083019061070d565b0390a2602085015161ffff1690614b3f565b613b8c8351614b90565b613b94614bc0565b614bed565b6060604082015191015190614c1c565b6128ea614d49565b6128ea90612215614afe565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613bfb575b505061164e57565b5f805160206159b48339815191525416141590505f80613bf3565b6037546001600160a01b0316330361122357565b90604051613c378161067d565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590613de2575b613dd55783613d9f575f5b60d15f526001600160a01b0316613c945f805160206159f48339815191528601613c2a565b8051909790613cab906001600160a01b03166115e4565b98613cd0613cc46020809b01516001600160601b031690565b6001600160601b031690565b948381108015613d95575b613d835791600193979a95613cfa613d06939488035b838c0390614e6c565b80920198870391612fd0565b01970193808611801590613d79575b613d6e5760d15f528290613d375f805160206159f48339815191528701613c2a565b805190890151969992966001600160a01b039091169460019392613d069290916001600160601b0390911690613cfa908803613cf1565b945050509250509190565b5081851015613d15565b60405163e8722f8f60e01b8152600490fd5b50808b1115613cdb565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316613c6f565b505093505050505f905f90565b508415613c64565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91613e56575b50613e4457565b60405163e775715160e01b8152600490fd5b613e6f915060203d6020116114ea576114db81836106cb565b5f613e3d565b604290467f000000000000000000000000000000000000000000000000000000000000000003613f245761010a54905b613ebc613eb56040830183612ac8565b369161133c565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613f07816106b0565b5190206040519161190160f01b8352600283015260228201522090565b613f2c614e7e565b90613ea5565b60041115613f3c57565b634e487b7160e01b5f52602160045260245ffd5b613f5a8383614f4b565b50613f6781959295613f32565b159384614003575b508315613f7d575b50505090565b5f929350908291604051613fb5816129986020820194630b135d3f60e11b998a8752602484015260406044840152606483019061070d565b51915afa90613fc2612bfd565b82613ff5575b82613fd8575b50505f8080613f77565b613fed9192506020808251830101910161259d565b145f80613fce565b915060208251101591613fc8565b6001600160a01b0383811691161493505f613f6f565b906030116103dd5790603090565b906090116103dd5760300190606090565b9060b0116103dd5760900190602090565b909392938483116103dd5784116103dd578101920390565b35906020811061406f575090565b5f199060200360031b1b1690565b969594906140ba9361409e6140ac926060979560808c5260808c0191612a2a565b9089820360208b015261070d565b918783036040890152612a2a565b930152565b906020610743928181520190612a12565b916020610743938181520191612a2a565b60b091828104915f90816140f3614f85565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b87841061413557505050505050505050565b82614144910180928887614049565b9061414f8282614019565b9161416e6141686141608684614027565b969093614038565b90614061565b90893b156103dd575f908d61419b604094855198899485946304512a2360e31b86528a8a6004880161407d565b03816801bc16d674ec8000008d5af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1946141e7926141f6575b5051928392836140d0565b0390a160018193019290614123565b80610f616142039261069d565b5f6141dc565b816030116103dd57614168917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614247614f85565b9061425e6142558486614027565b96909486614038565b94813b156103dd576801bc16d674ec8000005f946142c497604051988996879586946304512a2360e31b8652608060048701526142b56142a28d6084890190612a12565b60031994858983030160248a015261070d565b92868403016044870152612a2a565b90606483015203925af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19261339a9261430d575b50604051918291826140bf565b6143169061069d565b5f614300565b6001600160801b0390818111614330571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146143d757600283558147106143bf575f918291829182916001600160a01b03165af16143a1612bfd565b50156143ad5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614418575b1561440b5750905090565b6107439260801c91612fd0565b508015614400565b60cf546001600160801b0381169082158015614470575b1561444157505090565b60801c90614450828285612fd0565b928215612b18570961445f5790565b6001810180911115610743576125dc565b508115614437565b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b6144c7613dea565b6001600160a01b0316801561450f57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b919061452b613dea565b6001600160a01b0383169081156108ba5780156145d75780614552611dd860cf5460801c90565b019361455c612938565b85116145c557610e04946145839161457e61457685614420565b97889361431c565b615161565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926145f5613dea565b6001600160a01b0382169182156108ba5781156145d7578161461c611dd860cf5460801c90565b01614625612938565b81116145c557610e049561466c6145c0927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461457e61466488614420565b9a8b9361431c565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b9190916001600160801b0380809416911601918211610aae57565b93929190916146bd61535a565b6146c5613dea565b6001600160a01b0385165f90815261016e602052604090206146e6906125b7565b946001600160801b0361470087516001600160801b031690565b16156148b55761470f86612e2d565b6001600160a01b0381165f90815260d360205260409020614733906134fb90610c8f565b955f198414614885575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af195861561062c575f96614864575b5085986147cf6147c26147b28461431c565b86516001600160801b0316614695565b6001600160801b03168552565b6147e3611dd885516001600160801b031690565b1161350a577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e589561482c61485f946105948760018060a01b03165f5261016e60205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b61487e91965060203d6020116106255761061781836106cb565b945f6147a0565b925061489b611dd884516001600160801b031690565b808711156148ab5786039261473d565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c5761492091614910915f91614925575b5061431c565b6001600160801b03166020880152565b61470f565b61493e915060203d6020116106255761061781836106cb565b5f61490a565b9061494e82613464565b61495781613464565b6001600160a01b0391821691821580156149c8575b6108ba57825f5260d360205260405f2090815492858403938411610aae575f805160206159d483398151915293602093556149b78160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b508082161561496c565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561062c57614a6d936001600160401b03610c6a6040614a4c946020975f91614abd575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561062c575f91614aa4575090565b610743915060203d6020116106255761061781836106cb565b614ad6915060603d606011610f3d57610f2e81836106cb565b5f614a3d565b614ae4614afe565b614aec614e7e565b61010a80548203614afb575050565b55565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614b2d57565b604051631afcd79f60e31b8152600490fd5b614b47614afe565b61271061ffff831611614b7e57614b5d906144bf565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614b98614afe565b8015614bae5760018101614ba95750565b60d455565b6040516331278a8760e01b8152600490fd5b614bc8614afe565b6801bc16d674ec800000614bda612938565b10614bae57614be7614e7e565b61010a55565b614bf5614afe565b6001600160a01b031680614c065750565b6101a180546001600160a01b0319169091179055565b614c24614afe565b601e8151118015614d3e575b614d2c57614c3c614afe565b8051906001600160401b03821161069857614c6082614c5b5f54610631565b6155bd565b602090816001601f851114614cb857509180614c9692614c9d95945f92614cad575b50508160011b915f199060031b1c19161790565b5f55615687565b6128ea614ca86138a3565b600455565b015190505f80614c82565b5f80529190601f1984165f80516020615974833981519152935f905b828210614d14575050916001939185614c9d97969410614cfc575b505050811b015f55615687565b01515f1960f88460031b161c191690555f8080614cef565b80600186978294978701518155019601940190614cd4565b604051632d3f993760e21b8152600490fd5b50600a825111614c30565b614d51614afe565b614d59614afe565b614d61614afe565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614d9a576126973430614521565b60405163ea2559bb60e01b8152600490fd5b908160209103126103dd57516107438161221a565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614e4b575b50614e1157604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206159b48339815191528403614e32576128ea929350615765565b604051632a87526960e21b815260048101859052602490fd5b614e6591955060203d6020116106255761061781836106cb565b935f614deb565b9080821015614e79575090565b905090565b6e5661756c7456616c696461746f727360881b6020604051614e9f8161067d565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176106985760405251902090565b8151919060418303614f7b57614f749250602082015190606060408401519301515f1a90615807565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c820152602081526107438161067d565b9291908015611f26576001600160a01b038281169283156108ba57614fd4611b2261589b565b6150dd5790611c30956150c16150a5857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161507a61501f611dd860d0546001600160801b031690565b9261299861504c8561504761503261557b565b615041611dd860d55460801c90565b90612b53565b612b53565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f90815260d36020526040902061509d83825461295b565b90550161431c565b6001600160801b03166001600160801b031960d054161760d055565b60408051888152602081019590955291169290819081016145c0565b9293946150e98361264a565b9384156145d7577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361513e8661515993615134610e046151298461431c565b60cf5460801c612608565b6137e2848761537b565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b5f805160206159d483398151915260205f9261517c8561431c565b60cf54906151946001600160801b0391828416614695565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b6151e2476151dc611dd860d05460801c90565b9061295b565b9081156153555760d5546001600160801b03811690816152dd575b5050615214611dd860d0546001600160801b031690565b91821580156152d5575b6152cf576152359061522f8461264a565b90614e6c565b80156152cf57615244816143e9565b9283156152c8576151296128ea926152656150a5612eaa88610e049661295b565b61527f611be26152748361431c565b60d05460801c614695565b61528981876154f1565b60408051878152602081018390525f805160206159948339815191529190a1612eaa613a776152b78861431c565b60cf546001600160801b0316612608565b505f925050565b505f9150565b50801561521e565b81849294106152c85761527484615325935f8051602061599483398151915282611be29560801c61530e82826154f1565b604080519182526020820192909252a1039461431c565b6153396001600160801b0360d5541660d555565b61534e6001600160801b031960d5541660d555565b5f806151fd565b5f9150565b61536261589b565b1561536957565b604051630a62fbdb60e11b8152600490fd5b6001600160a01b03165f81815260d360205260409020805483810391908211610aae575f935f805160206159d483398151915292602092556153bc8161431c565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b60d154906801000000000000000082101561069857600182018060d155821015612beb5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206159f483398151915290910155565b61544c61557b565b60018101809111610aae576001600160a01b0380821161548657906128ea91604051916154788361067d565b1681525f60208201526153e6565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b80156154df576154b461557b565b908101809111610aae576001600160a01b0380821161548657906128ea91604051916154788361067d565b604051632ec8835b60e21b8152600490fd5b91909180156154df5761550261557b565b908101809111610aae576001600160a01b03808211615486576001600160601b039081851161555b57906128ea939461555692604051946155428661067d565b168452166001600160601b03166020830152565b6153e6565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60d1548061558857505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b03166115e4565b601f81116155c9575050565b5f80525f80516020615974833981519152906020601f840160051c8301931061560c575b601f0160051c01905b818110615601575050565b5f81556001016155f6565b90915081906155ed565b90601f8211615623575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931061567d575b601f0160051c01905b81811061567357505050565b5f81558201615667565b909150819061565e565b9081516001600160401b038111610698576001906156ae816156a98454610631565b615616565b602080601f83116001146156e3575081906156df9394955f92614cad5750508160011b915f199060031b1c19161790565b9055565b90601f1983169561571560015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061574e5750508385969710615736575b505050811b019055565b01515f1960f88460031b161c191690555f808061572c565b808785968294968601518155019501930190615719565b90813b156157e6575f805160206159b483398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156157cb576126979161590a565b5050346157d457565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161589057906158606020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561062c575f516001600160a01b0381161561588657905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f916158f1575090565b610743915060203d6020116114ea576114db81836106cb565b5f8061074393602081519101845af4615921612bfd565b919061593757508051156143ad57805190602001fd5b8151158061596a575b615948575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561594056fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a26469706673582212209ddcbe02370e402e806e07916e47bf7898eab2f13568b1f607282f6308231d9464736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612e1a565b005b5f3560e01c806301d523b6146103c757806301e1d114146103c2578063066055e0146103bd57806306fdde03146103b857806307a2d13a146103b3578063095ea7b3146103ae57806314c4184b146103a957806318160ddd1461036d57806318f72950146103a45780631a7ff5531461039f578063201b9eb51461039a57806323b872dd146103955780632999ad3f146103905780632cdf74011461038b578063313ce567146103865780633229fa951461038157806333194c0a1461037c5780633644e5151461037757806336fe59d2146103725780633a98ef391461036d578063439fab911461036857806343e82a7914610363578063469048401461035e5780634ec96b22146103595780634f1ef2861461035457806352d1902d1461034f57806353156f281461034a57806354fd4d50146103455780635c60da1b146103405780635cfc1a511461033b57806360d60e6e1461033657806370a08231146102be57806372b410a814610331578063754c38881461032c57806376b58b90146103275780637ecebe00146103225780637fd6f15c1461031d57806383d430d5146103185780638697d2c2146103135780638ceab9aa1461030e5780639267842a1461030957806395d89b4114610304578063a49a1e7d146102ff578063a9059cbb146102fa578063ac9650d8146102f5578063ad3cb1cc146102f0578063b1f0e7c7146102eb578063b45a1eb5146102e6578063c6e6f592146102e1578063d0a64ddc146102dc578063d505accf146102d7578063d83ad00c146102d2578063dd62ed3e146102cd578063e74b981b146102c8578063ee3bd5df146102c3578063f04da65b146102be578063f45bf3d2146102b9578063f851a440146102b45763f9609f080361000e57612585565b61255d565b61251c565b61178d565b6124f6565b6124c9565b612485565b61243a565b612225565b6121ed565b6121cf565b61219d565b612179565b612134565b6120cf565b61202e565b611fdc565b611f38565b611d44565b611cec565b611b41565b611971565b61194d565b611912565b6118c1565b611855565b6117c8565b6116ed565b6116d3565b61169f565b611684565b611660565b6115f7565b611372565b61128c565b611264565b611157565b611091565b6108f5565b611022565b611008565b610fce565b610fa2565b610f87565b610f6d565b610adc565b610a00565b6109dd565b610981565b61091b565b6108cc565b61082a565b61080c565b610746565b61048d565b61045c565b6103ef565b6001600160a01b038116036103dd57565b5f80fd5b908160809103126103dd5790565b60803660031901126103dd57600435610407816103cc565b604435610413816103cc565b606435906001600160401b0382116103dd5760209261044161043c61044a9436906004016103e1565b612670565b6024359061275d565b604051908152f35b5f9103126103dd57565b346103dd575f3660031901126103dd57602060cf5460801c604051908152f35b6001600160801b038116036103dd57565b346103dd5760203660031901126103dd576004356104aa8161047c565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561062c575f916105fd575b50335f90815261016e60205260409020610526906125b7565b916001600160801b0361054084516001600160801b031690565b16156105eb57610599836105566105e795612e2d565b6105806105738461056e84516001600160801b031690565b612608565b6001600160801b03168252565b335f90815261016e60205260409020612621565b612621565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61061f915060203d602011610625575b61061781836106cb565b81019061259d565b5f61050d565b503d61060d565b6125ac565b90600182811c9216801561065f575b602083101461064b57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610640565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761069857604052565b610669565b6001600160401b03811161069857604052565b608081019081106001600160401b0382111761069857604052565b90601f801991011681019081106001600160401b0382111761069857604052565b5f5b8381106106fd5750505f910152565b81810151838201526020016106ee565b90602091610726815180928185528580860191016106ec565b601f01601f1916010190565b90602061074392818152019061070d565b90565b346103dd575f3660031901126103dd576040515f805461076581610631565b808452906020906001908181169081156107e2575060011461079e575b6105e785610792818703826106cb565b60405191829182610732565b5f80805293505f805160206159748339815191525b8385106107cf57505050508101602001610792826105e7610782565b80548686018401529382019381016107b3565b8695506105e79693506020925061079294915060ff191682840152151560051b8201019293610782565b346103dd5760203660031901126103dd57602061044a60043561264a565b346103dd5760403660031901126103dd57600435610847816103cc565b6001600160a01b038116906024359082156108ba576108828291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b346103dd575f3660031901126103dd5761026a546040516001600160a01b039091168152602090f35b346103dd575f3660031901126103dd5760206001600160801b0360cf5416604051908152f35b60603660031901126103dd57600435610933816103cc565b60243561093f816103cc565b604435906001600160401b0382116103dd5760209261096861043c61044a9436906004016103e1565b61097133613464565b61097a81613464565b34906145e9565b346103dd5760203660031901126103dd576004356001600160401b0381116103dd5761043c6100209136906004016103e1565b60609060031901126103dd576004356109cc816103cc565b9060243590604435610743816103cc565b346103dd57602061044a6109f0366109b4565b916109fa33613464565b336146b0565b346103dd5760603660031901126103dd57600435610a1d816103cc565b60243590610a2a826103cc565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610a7a575b610a6e84610a69858883614944565b613485565b60405160018152602090f35b919093818503948511610aae575f928352600260209081526040808520338652909152909220939093559180610a6e610a5a565b6125dc565b60609060031901126103dd5760043590602435610acf816103cc565b90604435610743816103cc565b346103dd57610aea36610ab3565b906001600160a01b03808316156108ba57610b03613dea565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103dd5760408051631d8557d760e01b815260049491905f81878183875af1801561062c57610f54575b506001600160a01b0383165f90815261016e60205260409020610b76906125b7565b6001600160801b039283610b9183516001600160801b031690565b1615610f4457610ba082612e2d565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561062c575f98610f13575b50602097888101956001600160401b03918280610c198a516001600160401b031690565b1614610f0357908c92918751918c8380610c456303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561062c57610c71938e5f94610ede575b5050516001600160801b03165b1690612f5c565b96610c95610c8f8a60018060a01b03165f5260d360205260405f2090565b5461264a565b928389118015610ece575b610ebe57908b610cde9392610cbc89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561062c57670de0b6b3a764000094610d2d948e5f95610e91575b5050610d1f610d11610d2592612b36565b93516001600160401b031690565b93612b36565b921690612fd0565b1015610e83578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561062c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610e6095610dd793610e65575b5050610dba610573610daa8c61431c565b83516001600160801b0316612608565b6001600160a01b0386165f90815261016e60205260409020612621565b610de0826143e9565b90610e1f610e04610df08561431c565b60cf5460801c5b036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610e29828661537b565b610e33838961434f565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610e7b92903d106106255761061781836106cb565b505f80610d99565b835163185cfc6d60e11b8152fd5b610d25929550610eb4610d1f9282610d1193903d106106255761061781836106cb565b959250508e610d00565b875163efda1a2760e01b81528590fd5b50610ed76126b7565b8911610ca0565b610c6a9294509081610efb92903d106106255761061781836106cb565b92908e610c5d565b8651630709133160e01b81528490fd5b610f3691985060603d606011610f3d575b610f2e81836106cb565b810190613530565b965f610bf5565b503d610f24565b825163673f032f60e11b81528790fd5b80610f61610f679261069d565b80610452565b5f610b54565b346103dd575f3660031901126103dd57602061044a6126b7565b346103dd575f3660031901126103dd57602060405160128152f35b346103dd575f3660031901126103dd576020610fbc6126ed565b6040516001600160a01b039091168152f35b346103dd575f3660031901126103dd5760206040517fad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c8152f35b346103dd575f3660031901126103dd57602061044a612728565b602061044a611030366109b4565b9161275d565b9181601f840112156103dd578235916001600160401b0383116103dd57602083818601950101116103dd57565b60206003198201126103dd57600435906001600160401b0382116103dd5761108d91600401611036565b9091565b61109a36611063565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015611143575b61113157680100000000000000036110f49368ffffffffffffffffff1916178455612868565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b03841610156110ce565b346103dd5761116536610ab3565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561062c5782915f91611235575b501633036112235781610e606111f086867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd39661358a565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611257915060203d60201161125d575b61124f81836106cb565b81019061278a565b5f6111b8565b503d611245565b346103dd575f3660031901126103dd57609c546040516001600160a01b039091168152602090f35b346103dd5760203660031901126103dd576004356112a9816103cc565b60018060a01b03165f5261016e602052602060405f20604051906112cc8261067d565b54906001600160801b03918281169081835260801c848301526112f4575b5116604051908152f35b6112fd81612e2d565b6112ea565b6040519060a082018281106001600160401b0382111761069857604052565b6001600160401b03811161069857601f01601f191660200190565b92919261134882611321565b9161135660405193846106cb565b8294818452818301116103dd578281602093845f960137010152565b6040806003193601126103dd57600490813561138d816103cc565b6024356001600160401b0381116103dd57366023820112156103dd576113bc903690602481870135910161133c565b916113c5613bbd565b8051926113fc846113ee60209363439fab9160e01b85840152846024840152604483019061070d565b03601f1981018652856106cb565b611404613bbd565b61140c613c16565b6001600160a01b038381168015929190879084156115c2575b8415611554575b84156114f1575b5050821561145b575b505061144c576100208383614dc1565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561062c575f926114c4575b5050155f8061143c565b6114e39250803d106114ea575b6114db81836106cb565b810190612946565b5f806114ba565b503d6114d1565b855163054fd4d560e41b81529294508391839182905afa90811561062c57879160ff915f91611527575b5016141591865f611433565b6115479150843d861161154d575b61153f81836106cb565b810190614dac565b5f61151b565b503d611535565b935050835163198ca60560e11b815282818981875afa90811561062c5788917fad566d041ad0a21d208459166a94a853aa7fc34cc68f5e214ca9b0cadefaba2c915f916115a5575b5014159361142c565b6115bc9150853d87116106255761061781836106cb565b5f61159c565b5f805160206159b48339815191525490945084906115f0906001600160a01b03165b6001600160a01b031690565b1493611425565b346103dd575f3660031901126103dd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361164e5760206040515f805160206159b48339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126103dd576001600160a01b0361167b6126ed565b16330361122357005b346103dd575f3660031901126103dd57602060405160038152f35b346103dd575f3660031901126103dd575f805160206159b4833981519152546040516001600160a01b039091168152602090f35b346103dd575f3660031901126103dd57602061044a612938565b346103dd5760203660031901126103dd5760d180549081905f6004355b84821061173b57505050811015611730576105e7905b6040519081529081906020820190565b506105e75f19611720565b909193808316906001818518811c8301809311610aae575f8790525f805160206159f48339815191528301546001600160a01b0316841015611782575050935b919061170a565b90959101925061177b565b346103dd5760203660031901126103dd576004356117aa816103cc565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561062c576020915f91611838575b506040519015158152f35b61184f9150823d84116114ea576114db81836106cb565b5f61182d565b346103dd5760203660031901126103dd57600435611872816103cc565b61187a613c16565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103dd5760803660031901126103dd576105e76118f56004356118e4816103cc565b606435906044359060243590612968565b604080519384526020840192909252908201529081906060820190565b346103dd5760203660031901126103dd5760043561192f816103cc565b60018060a01b03165f526003602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57602061ffff609c5460a01c16604051908152f35b346103dd576003196040368201126103dd5760049081356001600160401b038082116103dd5760a08285019383360301126103dd576024359081116103dd576119bd9036908501611036565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103dd5760405163837d444160e01b8152905f908290818381611a108c828f01612a4a565b03925af1801561062c57611b2e575b50611a28613dea565b611a30612d4b565b9081163314159182611aff575b50509050611aee576044019160b0611a558484612ac8565b90500480158015611ad6575b611ac657611a76611a706126b7565b91612b1d565b11611ab7575060b0611a888383612ac8565b9050145f14611aa45761002091611a9e91612ac8565b90614209565b61002091611ab191612ac8565b906140e1565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611ae18484612ac8565b905060b082021415611a61565b604051634ca8886760e01b81528390fd5b611b229250611b1c611b2694611b1488613e75565b92369161133c565b91613f50565b1590565b805f80611a3d565b80610f61611b3b9261069d565b5f611a1f565b346103dd5760603660031901126103dd57600435602435611b66604435828433612968565b9192611b927f000000000000000000000000000000000000000000000000000000000000000082612b53565b42108015611ce4575b8015611cdc575b611cca577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611bfd611be2611bd78661431c565b60d05460801c612608565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611c419190611c306080826106cb565b5190205f5260d260205260405f2090565b555f9360018311611c7a575b50505050611c5b823361434f565b604080519485526020850191909152830152339180606081015b0390a2005b611cc092939450611c8b9088612b53565b60408051336020820190815291810193909352606083018290529094909190611c309082608081015b039081018352826106cb565b555f808080611c4d565b604051630e3d8e8d60e11b8152600490fd5b508215611ba2565b508115611b9b565b346103dd5760403660031901126103dd576020600435611d18602435611d11816103cc565b8233614fae565b90611d2233613485565b60405190815230905f805160206159d4833981519152843392a3604051908152f35b346103dd5760203660031901126103dd57600435611d60613dea565b335f90815261016e60205260409020611d78906125b7565b6001600160801b0380611d9283516001600160801b031690565b16156105eb578290611da383612e2d565b82516001600160801b03161610611f2657335f90815260d3602052604090205482611de4611dd884516001600160801b031690565b6001600160801b031690565b14611f1057611e089083611e02611dd885516001600160801b031690565b91612fd0565b91611e35611e28611e188361431c565b84516001600160801b0316610df7565b6001600160801b03168352565b335f90815261016e60205260409020611e4f908390612621565b611e976020611e8860018060a01b037f000000000000000000000000000000000000000000000000000000000000000016809633614fae565b9301516001600160801b031690565b833b156103dd5760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af191821561062c576105e792611efd575b506040519081529081906020820190565b80610f61611f0a9261069d565b5f611eec565b335f90815261016e602052604081205591611e4f565b604051636edcc52360e01b8152600490fd5b346103dd575f3660031901126103dd576040515f60018054611f5981610631565b80855291602091600181169081156107e25750600114611f83576105e785610792818703826106cb565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510611fc957505050508101602001610792826105e7610782565b8054868601840152938201938101611fad565b346103dd57611c757f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61200e36611063565b9290612018613c16565b6040519182916020835233956020840191612a2a565b346103dd5760403660031901126103dd5761205860043561204e816103cc565b6024359033614944565b61206133613485565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120a15750505050505090565b90919293949584806120bf600193603f198682030187528a5161070d565b9801930193019194939290612091565b346103dd5760203660031901126103dd576001600160401b036004358181116103dd57366023820112156103dd5780600401359182116103dd573660248360051b830101116103dd576105e79160246121289201612c9e565b6040519182918261206c565b346103dd575f3660031901126103dd576105e76040516121538161067d565b60058152640352e302e360dc1b602082015260405191829160208352602083019061070d565b346103dd575f3660031901126103dd576020610fbc612d4b565b801515036103dd57565b346103dd5760403660031901126103dd576100206004356121bd816103cc565b602435906121ca82612193565b612d82565b346103dd5760203660031901126103dd57602061044a6004356143e9565b346103dd5760203660031901126103dd5761002060043561220d816103cc565b612215613c16565b614478565b60ff8116036103dd57565b346103dd5760e03660031901126103dd57600435612242816103cc565b60243561224e816103cc565b6044359060643592608435906122638261221a565b6001600160a01b038381169590929086156108ba57428110612428576020915f91611cb461235689878a612319612298612728565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039161232d601f19938481018352826106cb565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa1561062c575f5192828416801590811561241b575b50612409576123f685916123e17f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610e60565b6040516323389ba560e21b8152600490fd5b905083831614155f61239c565b604051631ab7da6b60e01b8152600490fd5b346103dd575f3660031901126103dd5760206001600160801b0360d05416604051908152f35b60409060031901126103dd57600435612478816103cc565b90602435610743816103cc565b346103dd5760206124c061249836612460565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346103dd5760203660031901126103dd576100206004356124e9816103cc565b6124f1613c16565b6144bf565b346103dd575f3660031901126103dd5760206001600160801b0360d55416604051908152f35b346103dd5760203660031901126103dd57600435612539816103cc565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b346103dd575f3660031901126103dd576037546040516001600160a01b039091168152602090f35b602061044a61259336612460565b9061097133613464565b908160209103126103dd575190565b6040513d5f823e3d90fd5b906040516125c48161067d565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f190191908211610aae57565b6001600160801b039182169082160391908211610aae57565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161266257505090565b916107439260801c90612fd0565b61267c61268391613138565b91906132ce565b61268957565b6126916151c9565b8061269a575b50565b5f906040519081525f805160206159d483398151915260203092a3565b4760d0546001600160801b036126ce81831661264a565b9060d55416019060801c01908181115f146126e7570390565b50505f90565b6101a1546001600160a01b031680156127035790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036127555760045490565b6107436138a3565b90610743929161276c33613464565b61277533613464565b6127808334336145e9565b506109fa33613464565b908160209103126103dd5751610743816103cc565b359061ffff821682036103dd57565b9080601f830112156103dd578160206107439335910161133c565b906020828203126103dd5781356001600160401b03928382116103dd57019060a0828203126103dd576127fa611302565b928235845261280b6020840161279f565b602085015260408301358181116103dd57826128289185016127ae565b604085015260608301358181116103dd57826128459185016127ae565b606085015260808301359081116103dd5761286092016127ae565b608082015290565b6037549091906001600160a01b031661292e5760405163e7f6f22560e01b8152906020908183600481335afa92831561062c575f9361290f575b50604051636f4fa30f60e01b8152938285600481335afa90811561062c576128ea956128e5945f936128ec575b50506128de91928101906127c9565b9083613af1565b613bb1565b565b6128de9350908161290892903d1061125d5761124f81836106cb565b915f6128cf565b612927919350823d841161125d5761124f81836106cb565b915f6128a2565b50506128ea6139c9565b60d4548061074357505f1990565b908160209103126103dd575161074381612193565b91908203918211610aae57565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906129a681608081015b03601f1981018352826106cb565b5190205f5260d260205260405f20549182156129d6576129c7918391613c4f565b9091828103908111610aae5792565b5050505f905f905f90565b9035601e19823603018112156103dd5701602081359101916001600160401b0382116103dd5781360383136103dd57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061074392602081528235602082015260208301356040820152612a86612a7660408501856129e1565b84606085015260c0840191612a2a565b90612ab9612aae612a9a60608701876129e1565b601f19858703810160808701529591612a2a565b9460808101906129e1565b93909282860301910152612a2a565b903590601e19813603018212156103dd57018035906001600160401b0382116103dd576020019181360383136103dd57565b634e487b7160e01b5f52601260045260245ffd5b8115612b18570490565b612afa565b906801bc16d674ec8000009180830292830403610aae57565b90670de0b6b3a764000091828102928184041490151715610aae57565b91908201809211610aae57565b6001600160401b0381116106985760051b60200190565b90612b8182612b60565b612b8e60405191826106cb565b8281528092612b9f601f1991612b60565b01905f5b828110612baf57505050565b806060602080938501015201612ba3565b634e487b7160e01b5f52603260045260245ffd5b90821015612beb5761108d9160051b810190612ac8565b612bc0565b908092918237015f815290565b3d15612c27573d90612c0e82611321565b91612c1c60405193846106cb565b82523d5f602084013e565b606090565b6020818303126103dd578051906001600160401b0382116103dd570181601f820112156103dd578051612c5e81611321565b92612c6c60405194856106cb565b818452602082840101116103dd5761074391602080850191016106ec565b8051821015612beb5760209160051b010190565b919091612caa83612b77565b925f5b818110612cb957505050565b5f80612cc6838587612bd4565b60409391612cd8855180938193612bf0565b0390305af490612ce6612bfd565b9115612d0d575090600191612cfb8288612c8a565b52612d068187612c8a565b5001612cad565b9060448151106103dd57612d47612d3260049283810151602480918301019101612c2c565b925162461bcd60e51b81529283928301610732565b0390fd5b610109546001600160a01b03168061074357507f000000000000000000000000000000000000000000000000000000000000000090565b61026a546001600160a01b03919082163303611223576001600160a01b0381165f90815261026b60205260409020549215159260ff1615158314612e15576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b612e2333613464565b6126973433614521565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91612ec3575b5060208201916001600160801b03918284511691828214612ebc5783612eaf612eaa612eb7958584865116612fd0565b61431c565b16905261431c565b169052565b5050505050565b612edc915060203d6020116106255761061781836106cb565b5f612e7a565b90808202905f1981840990828083109203918083039214612f51576127109082821115612f3f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612fbf57670de0b6b3a76400009082821115612f3f577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146130435784831115612f3f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107439250612b0e565b908160609103126103dd578051916040602083015192015161074381612193565b81835290916001600160fb1b0383116103dd5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036103dd57604083015260408101356130c4816103cc565b6001600160a01b031660608381019190915281013536829003601e19018112156103dd5701602081359101906001600160401b0381116103dd578060051b360382136103dd5760a0836080806107439601520191613071565b9190915f8382019384129112908015821691151617610aae57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906131639060048301613095565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561062c575f915f905f95613289575b50841561323657816131ad6126ed565b16917f000000000000000000000000000000000000000000000000000000000000000016821461322f57509060205f92600460405180958193634641257d60e01b83525af190811561062c5761320a925f9261320e575b5061311d565b9190565b61322891925060203d6020116106255761061781836106cb565b905f613204565b908161323c575b50509190565b803b156103dd57604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561062c57613276575b80613236565b80610f616132839261069d565b5f613270565b919450506132af915060603d6060116132b7575b6132a781836106cb565b810190613050565b93905f61319d565b503d61329d565b600160ff1b8114610aae575f0390565b8015612697576132e3611dd860cf5460801c90565b5f82126133b557816132f491612b53565b90613301610e048361431c565b613316609c549161ffff8360a01c1690612ee2565b8015612e1557807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613354611dd860cf546001600160801b031690565b8061339f57505061339a90925b6001600160a01b0316916133758484615161565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b61339a926133af92039084612fd0565b92613361565b906133bf906132be565b6133d4611dd860d5546001600160801b031690565b806133f4575b50806133e4575050565b612eaa610e04916128ea9361295b565b9061345b7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161172061343f61343461342d8888612b53565b8785612fd0565b80809403960361431c565b6001600160801b03166001600160801b031960d554161760d555565b0390a15f6133da565b6001600160a01b03165f90815261026b602052604090205460ff1661122357565b60018060a01b0381165f5261016e60205260405f2090604051916134a88361067d565b54906001600160801b03918281169081855260801c602085015215612e15576134fb610c8f613500926134d9613dea565b6134e286612e2d565b6001600160a01b03165f90815260d36020526040902090565b6149d2565b9151161161350a57565b604051633684c65960e01b8152600490fd5b51906001600160401b03821682036103dd57565b908160609103126103dd5760405190606082018281106001600160401b038211176106985761358291604091825280516135698161047c565b84526135776020820161351c565b60208501520161351c565b604082015290565b92906001600160a01b0390818116156108ba576135a5613dea565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156103dd57604094855193631d8557d760e01b85526004945f81878183895af1801561062c57613890575b506001600160a01b0388165f90815261016e60205260409020613618906125b7565b906001600160801b0361363283516001600160801b031690565b16156138805761364182612e2d565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561062c57613861575b508651936303d1689d60e11b978886526020918287806136bb888c83019190602083019252565b0381845afa96871561062c575f97613842575b5086996136ee610c8f8d60018060a01b03165f5260d360205260405f2090565b88118015613832575b6138225790836137349261371287516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561062c575f859488946137799c613805575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561062c57610daa6137c0946137a393610573936128ea9a6137e7575b505061431c565b6001600160a01b0388165f90815261016e60205260409020612621565b6137e26137cc836143e9565b80976137dd610e04610df08761431c565b61537b565b61434f565b816137fd92903d106106255761061781836106cb565b505f8061379c565b61381b90873d89116106255761061781836106cb565b505f61374e565b825163efda1a2760e01b81528990fd5b5061383b6126b7565b88116136f7565b61385a919750833d85116106255761061781836106cb565b955f6136ce565b6138799060603d606011610f3d57610f2e81836106cb565b505f613694565b875163673f032f60e11b81528690fd5b80610f6161389d9261069d565b5f6135f6565b6040515f905f54906138b482610631565b9283825260209384830193600190866001821691825f146139a9575050600114613966575b505091816138ef613960936129989503826106cb565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f805160206159748339815191525b82841061399457505050820101816138ef6138d9565b8054868501860152879490930192810161397e565b60ff1916875292151560051b850190920192508391506138ef90506138d9565b6139d1614afe565b6139e6611dd860d0546001600160801b031690565b60018111613adf57600114613a5a575b60d654613a0161557b565b90808210613a1d575b5050613a155f60d655565b6128ea614adc565b5f8051602061599483398151915291613a509103613a3a816154a6565b604080519182525f602083015290918291820190565b0390a15f80613a0a565b613a93613a77613a7260cf546001600160801b031690565b6125f0565b6001600160801b03166001600160801b031960cf54161760cf55565b613aa86001600160801b031960d0541660d055565b613ab0615444565b5f8051602061599483398151915260405180613ad781905f60206040840193600181520152565b0390a16139f6565b604051630299325160e41b8152600490fd5b9190613afb614afe565b608082015190613b09614afe565b6001600160a01b03841680156108ba57613ba994613b9993613b82926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613b703394602083019061070d565b0390a2602085015161ffff1690614b3f565b613b8c8351614b90565b613b94614bc0565b614bed565b6060604082015191015190614c1c565b6128ea614d49565b6128ea90612215614afe565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613bfb575b505061164e57565b5f805160206159b48339815191525416141590505f80613bf3565b6037546001600160a01b0316330361122357565b90604051613c378161067d565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590613de2575b613dd55783613d9f575f5b60d15f526001600160a01b0316613c945f805160206159f48339815191528601613c2a565b8051909790613cab906001600160a01b03166115e4565b98613cd0613cc46020809b01516001600160601b031690565b6001600160601b031690565b948381108015613d95575b613d835791600193979a95613cfa613d06939488035b838c0390614e6c565b80920198870391612fd0565b01970193808611801590613d79575b613d6e5760d15f528290613d375f805160206159f48339815191528701613c2a565b805190890151969992966001600160a01b039091169460019392613d069290916001600160601b0390911690613cfa908803613cf1565b945050509250509190565b5081851015613d15565b60405163e8722f8f60e01b8152600490fd5b50808b1115613cdb565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316613c6f565b505093505050505f905f90565b508415613c64565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91613e56575b50613e4457565b60405163e775715160e01b8152600490fd5b613e6f915060203d6020116114ea576114db81836106cb565b5f613e3d565b604290467f000000000000000000000000000000000000000000000000000000000000000003613f245761010a54905b613ebc613eb56040830183612ac8565b369161133c565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613f07816106b0565b5190206040519161190160f01b8352600283015260228201522090565b613f2c614e7e565b90613ea5565b60041115613f3c57565b634e487b7160e01b5f52602160045260245ffd5b613f5a8383614f4b565b50613f6781959295613f32565b159384614003575b508315613f7d575b50505090565b5f929350908291604051613fb5816129986020820194630b135d3f60e11b998a8752602484015260406044840152606483019061070d565b51915afa90613fc2612bfd565b82613ff5575b82613fd8575b50505f8080613f77565b613fed9192506020808251830101910161259d565b145f80613fce565b915060208251101591613fc8565b6001600160a01b0383811691161493505f613f6f565b906030116103dd5790603090565b906090116103dd5760300190606090565b9060b0116103dd5760900190602090565b909392938483116103dd5784116103dd578101920390565b35906020811061406f575090565b5f199060200360031b1b1690565b969594906140ba9361409e6140ac926060979560808c5260808c0191612a2a565b9089820360208b015261070d565b918783036040890152612a2a565b930152565b906020610743928181520190612a12565b916020610743938181520191612a2a565b60b091828104915f90816140f3614f85565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b87841061413557505050505050505050565b82614144910180928887614049565b9061414f8282614019565b9161416e6141686141608684614027565b969093614038565b90614061565b90893b156103dd575f908d61419b604094855198899485946304512a2360e31b86528a8a6004880161407d565b03816801bc16d674ec8000008d5af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1946141e7926141f6575b5051928392836140d0565b0390a160018193019290614123565b80610f616142039261069d565b5f6141dc565b816030116103dd57614168917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614247614f85565b9061425e6142558486614027565b96909486614038565b94813b156103dd576801bc16d674ec8000005f946142c497604051988996879586946304512a2360e31b8652608060048701526142b56142a28d6084890190612a12565b60031994858983030160248a015261070d565b92868403016044870152612a2a565b90606483015203925af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19261339a9261430d575b50604051918291826140bf565b6143169061069d565b5f614300565b6001600160801b0390818111614330571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146143d757600283558147106143bf575f918291829182916001600160a01b03165af16143a1612bfd565b50156143ad5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614418575b1561440b5750905090565b6107439260801c91612fd0565b508015614400565b60cf546001600160801b0381169082158015614470575b1561444157505090565b60801c90614450828285612fd0565b928215612b18570961445f5790565b6001810180911115610743576125dc565b508115614437565b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b6144c7613dea565b6001600160a01b0316801561450f57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b919061452b613dea565b6001600160a01b0383169081156108ba5780156145d75780614552611dd860cf5460801c90565b019361455c612938565b85116145c557610e04946145839161457e61457685614420565b97889361431c565b615161565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926145f5613dea565b6001600160a01b0382169182156108ba5781156145d7578161461c611dd860cf5460801c90565b01614625612938565b81116145c557610e049561466c6145c0927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461457e61466488614420565b9a8b9361431c565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b9190916001600160801b0380809416911601918211610aae57565b93929190916146bd61535a565b6146c5613dea565b6001600160a01b0385165f90815261016e602052604090206146e6906125b7565b946001600160801b0361470087516001600160801b031690565b16156148b55761470f86612e2d565b6001600160a01b0381165f90815260d360205260409020614733906134fb90610c8f565b955f198414614885575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af195861561062c575f96614864575b5085986147cf6147c26147b28461431c565b86516001600160801b0316614695565b6001600160801b03168552565b6147e3611dd885516001600160801b031690565b1161350a577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e589561482c61485f946105948760018060a01b03165f5261016e60205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b61487e91965060203d6020116106255761061781836106cb565b945f6147a0565b925061489b611dd884516001600160801b031690565b808711156148ab5786039261473d565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c5761492091614910915f91614925575b5061431c565b6001600160801b03166020880152565b61470f565b61493e915060203d6020116106255761061781836106cb565b5f61490a565b9061494e82613464565b61495781613464565b6001600160a01b0391821691821580156149c8575b6108ba57825f5260d360205260405f2090815492858403938411610aae575f805160206159d483398151915293602093556149b78160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b508082161561496c565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561062c57614a6d936001600160401b03610c6a6040614a4c946020975f91614abd575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561062c575f91614aa4575090565b610743915060203d6020116106255761061781836106cb565b614ad6915060603d606011610f3d57610f2e81836106cb565b5f614a3d565b614ae4614afe565b614aec614e7e565b61010a80548203614afb575050565b55565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614b2d57565b604051631afcd79f60e31b8152600490fd5b614b47614afe565b61271061ffff831611614b7e57614b5d906144bf565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614b98614afe565b8015614bae5760018101614ba95750565b60d455565b6040516331278a8760e01b8152600490fd5b614bc8614afe565b6801bc16d674ec800000614bda612938565b10614bae57614be7614e7e565b61010a55565b614bf5614afe565b6001600160a01b031680614c065750565b6101a180546001600160a01b0319169091179055565b614c24614afe565b601e8151118015614d3e575b614d2c57614c3c614afe565b8051906001600160401b03821161069857614c6082614c5b5f54610631565b6155bd565b602090816001601f851114614cb857509180614c9692614c9d95945f92614cad575b50508160011b915f199060031b1c19161790565b5f55615687565b6128ea614ca86138a3565b600455565b015190505f80614c82565b5f80529190601f1984165f80516020615974833981519152935f905b828210614d14575050916001939185614c9d97969410614cfc575b505050811b015f55615687565b01515f1960f88460031b161c191690555f8080614cef565b80600186978294978701518155019601940190614cd4565b604051632d3f993760e21b8152600490fd5b50600a825111614c30565b614d51614afe565b614d59614afe565b614d61614afe565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614d9a576126973430614521565b60405163ea2559bb60e01b8152600490fd5b908160209103126103dd57516107438161221a565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614e4b575b50614e1157604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206159b48339815191528403614e32576128ea929350615765565b604051632a87526960e21b815260048101859052602490fd5b614e6591955060203d6020116106255761061781836106cb565b935f614deb565b9080821015614e79575090565b905090565b6e5661756c7456616c696461746f727360881b6020604051614e9f8161067d565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176106985760405251902090565b8151919060418303614f7b57614f749250602082015190606060408401519301515f1a90615807565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c820152602081526107438161067d565b9291908015611f26576001600160a01b038281169283156108ba57614fd4611b2261589b565b6150dd5790611c30956150c16150a5857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161507a61501f611dd860d0546001600160801b031690565b9261299861504c8561504761503261557b565b615041611dd860d55460801c90565b90612b53565b612b53565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f90815260d36020526040902061509d83825461295b565b90550161431c565b6001600160801b03166001600160801b031960d054161760d055565b60408051888152602081019590955291169290819081016145c0565b9293946150e98361264a565b9384156145d7577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361513e8661515993615134610e046151298461431c565b60cf5460801c612608565b6137e2848761537b565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b5f805160206159d483398151915260205f9261517c8561431c565b60cf54906151946001600160801b0391828416614695565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b6151e2476151dc611dd860d05460801c90565b9061295b565b9081156153555760d5546001600160801b03811690816152dd575b5050615214611dd860d0546001600160801b031690565b91821580156152d5575b6152cf576152359061522f8461264a565b90614e6c565b80156152cf57615244816143e9565b9283156152c8576151296128ea926152656150a5612eaa88610e049661295b565b61527f611be26152748361431c565b60d05460801c614695565b61528981876154f1565b60408051878152602081018390525f805160206159948339815191529190a1612eaa613a776152b78861431c565b60cf546001600160801b0316612608565b505f925050565b505f9150565b50801561521e565b81849294106152c85761527484615325935f8051602061599483398151915282611be29560801c61530e82826154f1565b604080519182526020820192909252a1039461431c565b6153396001600160801b0360d5541660d555565b61534e6001600160801b031960d5541660d555565b5f806151fd565b5f9150565b61536261589b565b1561536957565b604051630a62fbdb60e11b8152600490fd5b6001600160a01b03165f81815260d360205260409020805483810391908211610aae575f935f805160206159d483398151915292602092556153bc8161431c565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b60d154906801000000000000000082101561069857600182018060d155821015612beb5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206159f483398151915290910155565b61544c61557b565b60018101809111610aae576001600160a01b0380821161548657906128ea91604051916154788361067d565b1681525f60208201526153e6565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b80156154df576154b461557b565b908101809111610aae576001600160a01b0380821161548657906128ea91604051916154788361067d565b604051632ec8835b60e21b8152600490fd5b91909180156154df5761550261557b565b908101809111610aae576001600160a01b03808211615486576001600160601b039081851161555b57906128ea939461555692604051946155428661067d565b168452166001600160601b03166020830152565b6153e6565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60d1548061558857505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b03166115e4565b601f81116155c9575050565b5f80525f80516020615974833981519152906020601f840160051c8301931061560c575b601f0160051c01905b818110615601575050565b5f81556001016155f6565b90915081906155ed565b90601f8211615623575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931061567d575b601f0160051c01905b81811061567357505050565b5f81558201615667565b909150819061565e565b9081516001600160401b038111610698576001906156ae816156a98454610631565b615616565b602080601f83116001146156e3575081906156df9394955f92614cad5750508160011b915f199060031b1c19161790565b9055565b90601f1983169561571560015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061574e5750508385969710615736575b505050811b019055565b01515f1960f88460031b161c191690555f808061572c565b808785968294968601518155019501930190615719565b90813b156157e6575f805160206159b483398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156157cb576126979161590a565b5050346157d457565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161589057906158606020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561062c575f516001600160a01b0381161561588657905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f916158f1575090565b610743915060203d6020116114ea576114db81836106cb565b5f8061074393602081519101845af4615921612bfd565b919061593757508051156143ad57805190602001fd5b8151158061596a575b615948575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561594056fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a26469706673582212209ddcbe02370e402e806e07916e47bf7898eab2f13568b1f607282f6308231d9464736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthBlocklistVault.json b/test/shared/artifacts/EthBlocklistVault.json deleted file mode 100644 index f3b6710f..00000000 --- a/test/shared/artifacts/EthBlocklistVault.json +++ /dev/null @@ -1,1745 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthBlocklistVault", - "sourceName": "contracts/vaults/ethereum/EthBlocklistVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101e034620002695762004ffe6001600160401b03601f38839003908101601f1916840190828211858310176200026d5780859460409384528539610120938491810103126200026957620000548462000281565b91620000636020860162000281565b916200007181870162000281565b93620000806060880162000281565b916200008f6080890162000281565b936200009e60a08a0162000281565b95620000ad60c08b0162000281565b97620000bc60e08c0162000281565b91610100809c01519560805260a05260c0523060e052895246885261014092835260018060a01b03806101609516855280610180961686526101a0961686526101c09687527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166200025857808083160362000213575b5050505195614d679788620002978939608051888181611436015281816115ce015281816129e4015281816136a30152614c14015260a05188611103015260c0518881816139930152613ab4015260e0518881816112820152613466015251876125db0152518661371901525185611774015251848181610427015281816106fd015281816126bd01528181612f61015281816141e9015281816143560152614a6a0152518381816107bc01528181610d800152818161302001526149ee01525182611a3e0152518181816120020152612a2c0152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200013c565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002695756fe60806040526004361015610022575b3615610018575f80fd5b610020612695565b005b5f3560e01c806301d523b61461031157806301e1d1141461030c578063066055e01461030757806307a2d13a1461030257806314c4184b146102fd57806318f72950146102f85780631a7ff553146102f3578063201b9eb5146102ee5780632999ad3f146102e95780632cdf7401146102e45780633229fa95146102df57806333194c0a146102da57806336fe59d2146102d55780633a98ef39146102d0578063439fab91146102cb57806343e82a79146102c657806346904840146102c15780634ec96b22146102bc5780634f1ef286146102b757806352d1902d146102b257806353156f28146102ad57806354fd4d50146102a85780635c60da1b146102a35780635cfc1a511461029e57806360d60e6e1461029957806372b410a814610294578063754c38881461028f57806376b58b901461028a5780637fd6f15c1461028557806383d430d5146102805780638697d2c21461027b5780638ceab9aa146102765780639267842a14610271578063a49a1e7d1461026c578063ac9650d814610267578063ad3cb1cc14610262578063b1f0e7c71461025d578063b45a1eb514610258578063c6e6f59214610253578063d0a64ddc1461024e578063d83ad00c14610249578063e74b981b14610244578063ee3bd5df1461023f578063f04da65b1461023a578063f45bf3d214610235578063f851a440146102305763f9609f080361000e57611e89565b611e62565b611e21565b611de6565b611dc0565b611d93565b611d6d565b611d40565b611d22565b611cf0565b611ccc565b611c87565b611c11565b611b16565b611922565b6118ee565b611748565b611578565b611554565b611503565b611498565b61140b565b611366565b61134c565b611318565b6112fd565b6112d9565b611270565b610feb565b610e86565b610e5e565b610d51565b610c8b565b610c0a565b610bf6565b610bbc565b610b90565b610b76565b6106d3565b610687565b610628565b6105c2565b610599565b61057b565b6103d7565b6103a6565b610339565b6001600160a01b0381160361032757565b5f80fd5b908160809103126103275790565b60803660031901126103275760043561035181610316565b60443561035d81610316565b606435906001600160401b0382116103275760209261038b61038661039494369060040161032b565b611f8f565b60243590612024565b604051908152f35b5f91031261032757565b34610327575f36600319011261032757602060985460801c604051908152f35b6001600160801b0381160361032757565b34610327576020366003190112610327576004356103f4816103c6565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610576575f91610547575b50335f9081526101376020526040902061047090611ecd565b916001600160801b0361048a84516001600160801b031690565b1615610535576104e3836104a0610531956126a8565b6104ca6104bd846104b884516001600160801b031690565b611f1e565b6001600160801b03168252565b335f90815261013760205260409020611f37565b611f37565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610569915060203d60201161056f575b6105618183610f79565b810190611eb3565b5f610457565b503d610557565b611ec2565b34610327576020366003190112610327576020610394600435611f69565b34610327575f36600319011261032757610201546040516001600160a01b039091168152602090f35b6060366003190112610327576004356105da81610316565b6024356105e681610316565b604435906001600160401b0382116103275760209261060f61038661039494369060040161032b565b61061833612ece565b61062181612ece565b3490613e86565b34610327576020366003190112610327576004356001600160401b0381116103275761038661002091369060040161032b565b60609060031901126103275760043561067381610316565b906024359060443561068481610316565b90565b3461032757602061039461069a3661065b565b916106a433612ece565b33614125565b606090600319011261032757600435906024356106c681610316565b9060443561068481610316565b34610327576106e1366106aa565b906001600160a01b0380831615610b64576106fa613688565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103275760408051631d8557d760e01b815260049491905f81878183875af1801561057657610b4b575b506001600160a01b0383165f9081526101376020526040902061076d90611ecd565b6001600160801b03928361078883516001600160801b031690565b1615610b3b57610797826126a8565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610576575f98610b0a575b50602097888101956001600160401b039182806108108a516001600160401b031690565b1614610afa57908c92918751918c838061083c6303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561057657610868938e5f94610ad5575b5050516001600160801b03165b16906127d7565b9661088c6108868a60018060a01b03165f52609c60205260405f2090565b54611f69565b928389118015610ac5575b610ab557908b6108d593926108b389516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561057657670de0b6b3a764000094610924948e5f95610a88575b505061091661090861091c926123b2565b93516001600160401b031690565b936123b2565b92169061284b565b1015610a7a578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610576577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610a57956109ce93610a5c575b50506109b16104bd6109a18c613bb9565b83516001600160801b0316611f1e565b6001600160a01b0386165f90815261013760205260409020611f37565b6109d782613c86565b90610a166109fb6109e785613bb9565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610a2082866143d0565b610a2a8389613bec565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610a7292903d1061056f576105618183610f79565b505f80610990565b835163185cfc6d60e11b8152fd5b61091c929550610aab610916928261090893903d1061056f576105618183610f79565b959250508e6108f7565b875163efda1a2760e01b81528590fd5b50610ace611fb3565b8911610897565b6108619294509081610af292903d1061056f576105618183610f79565b92908e610854565b8651630709133160e01b81528490fd5b610b2d91985060603d606011610b34575b610b258183610f79565b810190612f03565b965f6107ec565b503d610b1b565b825163673f032f60e11b81528790fd5b80610b58610b5e92610f30565b8061039c565b5f61074b565b60405163d92e233d60e01b8152600490fd5b34610327575f366003190112610327576020610394611fb3565b34610327575f366003190112610327576020610baa611fe9565b6040516001600160a01b039091168152f35b34610327575f3660031901126103275760206040517fa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d208152f35b6020610394610c043661065b565b91612024565b34610327575f3660031901126103275760206001600160801b0360985416604051908152f35b9181601f84011215610327578235916001600160401b038311610327576020838186019501011161032757565b602060031982011261032757600435906001600160401b03821161032757610c8791600401610c30565b9091565b610c9436610c5d565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610d3d575b610d2b5768010000000000000003610cee9368ffffffffffffffffff19161784556120e5565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610cc8565b3461032757610d5f366106aa565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105765782915f91610e2f575b50163303610e1d5781610a57610dea86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396612f43565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610e51915060203d602011610e57575b610e498183610f79565b810190612051565b5f610db2565b503d610e3f565b34610327575f366003190112610327576065546040516001600160a01b039091168152602090f35b3461032757602036600319011261032757600435610ea381610316565b60018060a01b03165f52610137602052602060405f2060405190610ec682610f10565b54906001600160801b03918281169081835260801c84830152610eee575b5116604051908152f35b610ef7816126a8565b610ee4565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b03821117610f2b57604052565b610efc565b6001600160401b038111610f2b57604052565b606081019081106001600160401b03821117610f2b57604052565b608081019081106001600160401b03821117610f2b57604052565b90601f801991011681019081106001600160401b03821117610f2b57604052565b6001600160401b038111610f2b57601f01601f191660200190565b929192610fc182610f9a565b91610fcf6040519384610f79565b829481845281830111610327578281602093845f960137010152565b60408060031936011261032757600490813561100681610316565b6024356001600160401b0381116103275736602382011215610327576110359036906024818701359101610fb5565b9161103e61345c565b8051926110758461106760209363439fab9160e01b858401528460248401526044830190611b89565b03601f198101865285610f79565b61107d61345c565b6110856134b5565b6001600160a01b0383811680159291908790841561123b575b84156111cd575b841561116a575b505082156110d4575b50506110c5576100208383614581565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610576575f9261113d575b5050155f806110b5565b61115c9250803d10611163575b6111548183610f79565b8101906121c2565b5f80611133565b503d61114a565b855163054fd4d560e41b81529294508391839182905afa90811561057657879160ff915f916111a0575b5016141591865f6110ac565b6111c09150843d86116111c6575b6111b88183610f79565b810190614568565b5f611194565b503d6111ae565b935050835163198ca60560e11b815282818981875afa9081156105765788917fa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20915f9161121e575b501415936110a5565b6112359150853d871161056f576105618183610f79565b5f611215565b5f80516020614d12833981519152549094508490611269906001600160a01b03165b6001600160a01b031690565b149361109e565b34610327575f366003190112610327577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036112c75760206040515f80516020614d128339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112610327576001600160a01b036112f4611fe9565b163303610e1d57005b34610327575f36600319011261032757602060405160038152f35b34610327575f366003190112610327575f80516020614d12833981519152546040516001600160a01b039091168152602090f35b34610327575f3660031901126103275760206103946121b4565b3461032757602036600319011261032757609a80549081905f6004355b8482106113b4575050508110156113a957610531905b6040519081529081906020820190565b506105315f19611399565b909193808316906001818518811c8301809311611406575f8790525f80516020614cd28339815191528301546001600160a01b03168410156113fb575050935b9190611383565b9095910192506113f4565b611ef2565b34610327575f36600319011261032757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610576576020915f9161147b575b506040519015158152f35b6114929150823d8411611163576111548183610f79565b5f611470565b34610327576020366003190112610327576004356114b581610316565b6114bd6134b5565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103275760803660031901126103275761053161153760043561152681610316565b6064359060443590602435906121e4565b604080519384526020840192909252908201529081906060820190565b34610327575f36600319011261032757602061ffff60655460a01c16604051908152f35b34610327576003196040368201126103275760049081356001600160401b038082116103275760a082850193833603011261032757602435908111610327576115c49036908501610c30565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103275760405163837d444160e01b8152905f9082908183816116178c828f016122c6565b03925af1801561057657611735575b5061162f613688565b6116376125c7565b9081163314159182611706575b505090506116f5576044019160b061165c8484612344565b905004801580156116dd575b6116cd5761167d611677611fb3565b91612399565b116116be575060b061168f8383612344565b9050145f146116ab57610020916116a591612344565b90613aa6565b610020916116b891612344565b9061397e565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506116e88484612344565b905060b082021415611668565b604051634ca8886760e01b81528390fd5b611729925061172361172d9461171b88613713565b923691610fb5565b916137ed565b1590565b805f80611644565b80610b5861174292610f30565b5f611626565b346103275760603660031901126103275760043560243561176d6044358284336121e4565b91926117997f0000000000000000000000000000000000000000000000000000000000000000826123cf565b421080156118e6575b80156118de575b6118cc577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936118046117e96117de86613bb9565b60995460801c611f1e565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916118489190611837608082610f79565b5190205f52609b60205260405f2090565b555f9360018311611881575b505050506118628233613bec565b604080519485526020850191909152830152339180606081015b0390a2005b6118c29293945061189290886123cf565b60408051336020820190815291810193909352606083018290526080958601835290949091906118379082610f79565b555f808080611854565b604051630e3d8e8d60e11b8152600490fd5b5082156117a9565b5081156117a2565b3461032757604036600319011261032757602061191960243561191081610316565b600435336147dc565b6103943361475c565b346103275760203660031901126103275760043561193e613688565b335f9081526101376020526040902061195690611ecd565b6001600160801b038061197083516001600160801b031690565b1615610535578290611981836126a8565b82516001600160801b03161610611b0457335f908152609c6020526040902054826119c26119b684516001600160801b031690565b6001600160801b031690565b14611aee576119e690836119e06119b685516001600160801b031690565b9161284b565b91611a13611a066119f683613bb9565b84516001600160801b03166109ee565b6001600160801b03168352565b335f90815261013760205260409020611a2d908390611f37565b611a756020611a6660018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336147dc565b9301516001600160801b031690565b833b156103275760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105765761053192611adb575b506040519081529081906020820190565b80610b58611ae892610f30565b5f611aca565b335f908152610137602052604081205591611a2d565b604051636edcc52360e01b8152600490fd5b346103275761187c7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611b4836610c5d565b9290611b526134b5565b60405191829160208352339560208401916122a6565b5f5b838110611b795750505f910152565b8181015183820152602001611b6a565b90602091611ba281518092818552858086019101611b68565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611be35750505050505090565b9091929394958480611c01600193603f198682030187528a51611b89565b9801930193019194939290611bd3565b34610327576020366003190112610327576001600160401b036004358181116103275736602382011215610327578060040135918211610327573660248360051b8301011161032757610531916024611c6a920161251a565b60405191829182611bae565b906020610684928181520190611b89565b34610327575f36600319011261032757610531604051611ca681610f10565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611b89565b34610327575f366003190112610327576020610baa6125c7565b8015150361032757565b3461032757604036600319011261032757610020600435611d1081610316565b60243590611d1d82611ce6565b6125fd565b34610327576020366003190112610327576020610394600435613c86565b3461032757602036600319011261032757610020600435611d6081610316565b611d686134b5565b613d15565b34610327575f3660031901126103275760206001600160801b0360995416604051908152f35b3461032757602036600319011261032757610020600435611db381610316565b611dbb6134b5565b613d5c565b34610327575f3660031901126103275760206001600160801b03609e5416604051908152f35b3461032757602036600319011261032757600435611e0381610316565b60018060a01b03165f52609c602052602060405f2054604051908152f35b3461032757602036600319011261032757600435611e3e81610316565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b34610327575f366003190112610327575f546040516001600160a01b039091168152602090f35b6040366003190112610327576020610394600435611ea681610316565b6024359061060f82610316565b90816020910312610327575190565b6040513d5f823e3d90fd5b90604051611eda81610f10565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f19019190821161140657565b6001600160801b03918216908216039190821161140657565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b0381169081611f8157505090565b916106849260801c9061284b565b611f9b611fa2916129b3565b9190612b49565b611fa857565b611fb0612cfa565b50565b476099546001600160801b03611fca818316611f69565b90609e5416019060801c01908181115f14611fe3570390565b50505f90565b61016a546001600160a01b03168015611fff5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b90610684929161203333612ece565b61203c33612ece565b612047833433613e86565b506106a433612ece565b90816020910312610327575161068481610316565b906020828203126103275781356001600160401b0392838211610327570191606083830312610327576040519261209c84610f43565b80358452602081013561ffff81168103610327576020850152604081013591821161032757019080601f83011215610327578160206120dd93359101610fb5565b604082015290565b5f549091906001600160a01b03166121aa5760405163e7f6f22560e01b8152906020908183600481335afa928315610576575f9361218b575b50604051636f4fa30f60e01b8152938285600481335afa9081156105765761216695612161945f93612168575b505061215a9192810190612066565b9083613368565b613450565b565b61215a9350908161218492903d10610e5757610e498183610f79565b915f61214b565b6121a3919350823d8411610e5757610e498183610f79565b915f61211e565b505061216661325c565b609d548061068457505f1990565b90816020910312610327575161068481611ce6565b9190820391821161140657565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061222281608081015b03601f198101835282610f79565b5190205f52609b60205260405f2054918215612252576122439183916134ed565b90918281039081116114065792565b5050505f905f905f90565b9035601e19823603018112156103275701602081359101916001600160401b03821161032757813603831361032757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610684926020815282356020820152602083013560408201526123026122f2604085018561225d565b84606085015260c08401916122a6565b9061233561232a612316606087018761225d565b601f198587038101608087015295916122a6565b94608081019061225d565b939092828603019101526122a6565b903590601e198136030182121561032757018035906001600160401b0382116103275760200191813603831361032757565b634e487b7160e01b5f52601260045260245ffd5b8115612394570490565b612376565b906801bc16d674ec800000918083029283040361140657565b90670de0b6b3a76400009182810292818404149015171561140657565b9190820180921161140657565b6001600160401b038111610f2b5760051b60200190565b906123fd826123dc565b61240a6040519182610f79565b828152809261241b601f19916123dc565b01905f5b82811061242b57505050565b80606060208093850101520161241f565b634e487b7160e01b5f52603260045260245ffd5b9082101561246757610c879160051b810190612344565b61243c565b908092918237015f815290565b3d156124a3573d9061248a82610f9a565b916124986040519384610f79565b82523d5f602084013e565b606090565b602081830312610327578051906001600160401b038211610327570181601f820112156103275780516124da81610f9a565b926124e86040519485610f79565b81845260208284010111610327576106849160208085019101611b68565b80518210156124675760209160051b010190565b919091612526836123f3565b925f5b81811061253557505050565b5f80612542838587612450565b6040939161255485518093819361246c565b0390305af490612562612479565b91156125895750906001916125778288612506565b526125828187612506565b5001612529565b906044815110610327576125c36125ae600492838101516024809183010191016124a8565b925162461bcd60e51b81529283928301611c76565b0390fd5b60d2546001600160a01b03168061068457507f000000000000000000000000000000000000000000000000000000000000000090565b610201546001600160a01b03919082163303610e1d576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612690576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b61269e33612ece565b611fb03433613dbe565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f9161273e575b5060208201916001600160801b03918284511691828214612737578361272a61272561273295858486511661284b565b613bb9565b169052613bb9565b169052565b5050505050565b612757915060203d60201161056f576105618183610f79565b5f6126f5565b90808202905f19818409908280831092039180830392146127cc5761271090828211156127ba577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461283a57670de0b6b3a764000090828211156127ba577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146128be57848311156127ba57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090610684925061238a565b90816060910312610327578051916040602083015192015161068481611ce6565b81835290916001600160fb1b0383116103275760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103610327576040830152604081013561293f81610316565b6001600160a01b031660608381019190915281013536829003601e19018112156103275701602081359101906001600160401b038111610327578060051b360382136103275760a08360808061068496015201916128ec565b9190915f838201938412911290801582169115161761140657565b6040516325f56f1160e01b81526001600160a01b039291606090829081906129de9060048301612910565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610576575f915f905f95612b04575b508415612ab15781612a28611fe9565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612aaa57509060205f92600460405180958193634641257d60e01b83525af190811561057657612a85925f92612a89575b50612998565b9190565b612aa391925060203d60201161056f576105618183610f79565b905f612a7f565b9081612ab7575b50509190565b803b1561032757604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561057657612af1575b80612ab1565b80610b58612afe92610f30565b5f612aeb565b91945050612b2a915060603d606011612b32575b612b228183610f79565b8101906128cb565b93905f612a18565b503d612b18565b600160ff1b8114611406575f0390565b8015611fb057612b5e6119b660985460801c90565b5f8212612c305781612b6f916123cf565b90612b7c6109fb83613bb9565b612b916065549161ffff8360a01c169061275d565b801561269057807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793612bcf6119b66098546001600160801b031690565b80612c1a575050612c1590925b6001600160a01b031691612bf08484613f32565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b612c1592612c2a9203908461284b565b92612bdc565b90612c3a90612b39565b612c4f6119b6609e546001600160801b031690565b80612c6f575b5080612c5f575050565b6127256109fb91612166936121d7565b90612cd67f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91611399612cba612caf612ca888886123cf565b878561284b565b808094039603613bb9565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f612c55565b9190916001600160801b038080941691160191821161140657565b612d1347612d0d6119b660995460801c90565b906121d7565b908115612ec957609e546001600160801b0381169081612e51575b5050612d456119b66099546001600160801b031690565b9182158015612e49575b612e4357612d6690612d6084611f69565b90614113565b8015612e4357612d7581613c86565b928315612e3c57612e3161216692612db2612d96612725886109fb966121d7565b6001600160801b03166001600160801b03196099541617609955565b612dcc6117e9612dc183613bb9565b60995460801c612cdf565b612dd68187613fdc565b60408051878152602081018390525f80516020614cf28339815191529190a1612725612e15612e0488613bb9565b6098546001600160801b0316611f1e565b6001600160801b03166001600160801b03196098541617609855565b60985460801c611f1e565b505f925050565b505f9150565b508015612d4f565b8184929410612e3c57612dc184612e99935f80516020614cf2833981519152826117e99560801c612e828282613fdc565b604080519182526020820192909252a10394613bb9565b612ead6001600160801b03609e5416609e55565b612ec26001600160801b0319609e5416609e55565b5f80612d2e565b5f9150565b6001600160a01b03165f908152610202602052604090205460ff16610e1d57565b51906001600160401b038216820361032757565b90816060910312610327576120dd6040805192612f1f84610f43565b8051612f2a816103c6565b8452612f3860208201612eef565b602085015201612eef565b92906001600160a01b039081811615610b6457612f5e613688565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561032757604094855193631d8557d760e01b85526004945f81878183895af1801561057657613249575b506001600160a01b0388165f90815261013760205260409020612fd190611ecd565b906001600160801b03612feb83516001600160801b031690565b161561323957612ffa826126a8565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156105765761321a575b508651936303d1689d60e11b97888652602091828780613074888c83019190602083019252565b0381845afa968715610576575f976131fb575b5086996130a76108868d60018060a01b03165f52609c60205260405f2090565b881180156131eb575b6131db5790836130ed926130cb87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610576575f859488946131329c6131be575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af1958615610576576109a16131799461315c936104bd936121669a6131a0575b5050613bb9565b6001600160a01b0388165f90815261013760205260409020611f37565b61319b61318583613c86565b80976131966109fb6109e787613bb9565b6143d0565b613bec565b816131b692903d1061056f576105618183610f79565b505f80613155565b6131d490873d891161056f576105618183610f79565b505f613107565b825163efda1a2760e01b81528990fd5b506131f4611fb3565b88116130b0565b613213919750833d851161056f576105618183610f79565b955f613087565b6132329060603d606011610b3457610b258183610f79565b505f61304d565b875163673f032f60e11b81528690fd5b80610b5861325692610f30565b5f612faf565b61326461443e565b6132796119b66099546001600160801b031690565b60018111613356576001146132ed575b609f54613294614968565b908082106132b0575b50506132a85f609f55565b61216661441d565b5f80516020614cf2833981519152916132e391036132cd816140da565b604080519182525f602083015290918291820190565b0390a15f8061329d565b61330a612e156133056098546001600160801b031690565b611f06565b61331f6001600160801b031960995416609955565b613327614098565b5f80516020614cf28339815191526040518061334e81905f60206040840193600181520152565b0390a1613289565b604051630299325160e41b8152600490fd5b61337061443e565b604083015161337d61443e565b6001600160a01b0382168015610b64576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806133d633946020830190611b89565b0390a26020830151926133e761443e565b61271061ffff85161161343e576134369361340461342993613d5c565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555161447f565b6134316144af565b6144d6565b612166614505565b604051638a81d3b360e01b8152600490fd5b61216690611d6861443e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821561349a575b50506112c757565b5f80516020614d128339815191525416141590505f80613492565b5f546001600160a01b03163303610e1d57565b906040516134d581610f10565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613680575b613673578361363d575f5b609a5f526001600160a01b03166135325f80516020614cd283398151915286016134c8565b8051909790613549906001600160a01b031661125d565b9861356e6135626020809b01516001600160601b031690565b6001600160601b031690565b948381108015613633575b6136215791600193979a956135986135a4939488035b838c0390614113565b8092019887039161284b565b01970193808611801590613617575b61360c57609a5f5282906135d55f80516020614cd283398151915287016134c8565b805190890151969992966001600160a01b0390911694600193926135a49290916001600160601b039091169061359890880361358f565b945050509250509190565b50818510156135b3565b60405163e8722f8f60e01b8152600490fd5b50808b1115613579565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031661350d565b505093505050505f905f90565b508415613502565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f916136f4575b506136e257565b60405163e775715160e01b8152600490fd5b61370d915060203d602011611163576111548183610f79565b5f6136db565b604290467f0000000000000000000000000000000000000000000000000000000000000000036137c15760d354905b6137596137526040830183612344565b3691610fb5565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526137a481610f5e565b5190206040519161190160f01b8352600283015260228201522090565b6137c961462c565b90613742565b600411156137d957565b634e487b7160e01b5f52602160045260245ffd5b6137f783836146f9565b50613804819592956137cf565b1593846138a0575b50831561381a575b50505090565b5f929350908291604051613852816122146020820194630b135d3f60e11b998a87526024840152604060448401526064830190611b89565b51915afa9061385f612479565b82613892575b82613875575b50505f8080613814565b61388a91925060208082518301019101611eb3565b145f8061386b565b915060208251101591613865565b6001600160a01b0383811691161493505f61380c565b906030116103275790603090565b906090116103275760300190606090565b9060b0116103275760900190602090565b90939293848311610327578411610327578101920390565b35906020811061390c575090565b5f199060200360031b1b1690565b969594906139579361393b613949926060979560808c5260808c01916122a6565b9089820360208b0152611b89565b9187830360408901526122a6565b930152565b90602061068492818152019061228e565b9160206106849381815201916122a6565b60b091828104915f9081613990614733565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b8784106139d257505050505050505050565b826139e19101809288876138e6565b906139ec82826138b6565b91613a0b613a056139fd86846138c4565b9690936138d5565b906138fe565b90893b15610327575f908d613a38604094855198899485946304512a2360e31b86528a8a6004880161391a565b03816801bc16d674ec8000008d5af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194613a8492613a93575b50519283928361396d565b0390a1600181930192906139c0565b80610b58613aa092610f30565b5f613a79565b8160301161032757613a05917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613ae4614733565b90613afb613af284866138c4565b969094866138d5565b94813b15610327576801bc16d674ec8000005f94613b6197604051988996879586946304512a2360e31b865260806004870152613b52613b3f8d608489019061228e565b60031994858983030160248a0152611b89565b928684030160448701526122a6565b90606483015203925af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192612c1592613baa575b506040519182918261395c565b613bb390610f30565b5f613b9d565b6001600160801b0390818111613bcd571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613c745760028355814710613c5c575f918291829182916001600160a01b03165af1613c3e612479565b5015613c4a5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b03821681158015613cb5575b15613ca85750905090565b6106849260801c9161284b565b508015613c9d565b6098546001600160801b0381169082158015613d0d575b15613cde57505090565b60801c90613ced82828561284b565b9282156123945709613cfc5790565b600181018091111561068457611ef2565b508115613cd4565b61020180546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b613d64613688565b6001600160a01b03168015613dac57606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190613dc8613688565b6001600160a01b038316908115610b64578015613e745780613def6119b660985460801c90565b0193613df96121b4565b8511613e62576109fb94613e2091613e1b613e1385613cbd565b978893613bb9565b613f32565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613e92613688565b6001600160a01b038216918215610b64578115613e745781613eb96119b660985460801c90565b01613ec26121b4565b8111613e62576109fb95613f09613e5d927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613e1b613f0188613cbd565b9a8b93613bb9565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613f3b82613bb9565b60985490613f536001600160801b0391828416612cdf565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609a549068010000000000000000821015610f2b576001820180609a5582101561246757609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614cd283398151915290910155565b919091801561408657613fed614968565b908101809111611406576001600160a01b03808211614066576001600160601b039081851161404657906121669394614041926040519461402d86610f10565b168452166001600160601b03166020830152565b613f7e565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b6140a0614968565b60018101809111611406576001600160a01b03808211614066579061216691604051916140cc83610f10565b1681525f6020820152613f7e565b8015614086576140e8614968565b908101809111611406576001600160a01b03808211614066579061216691604051916140cc83610f10565b9080821015614120575090565b905090565b93929190916141326149aa565b61413a613688565b6001600160a01b0385165f9081526101376020526040902061415b90611ecd565b946001600160801b0361417587516001600160801b031690565b161561434157614184866126a8565b6001600160a01b0381165f908152609c602052604090206141ad906141a890610886565b6149cb565b955f198414614311575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610576575f966142f0575b50859861424961423c61422c84613bb9565b86516001600160801b0316612cdf565b6001600160801b03168552565b61425d6119b685516001600160801b031690565b116142de577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58956142a66142d9946104de8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61430a91965060203d60201161056f576105618183610f79565b945f61421a565b92506143276119b684516001600160801b031690565b80871115614337578603926141b7565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576576143ac9161439c915f916143b1575b50613bb9565b6001600160801b03166020880152565b614184565b6143ca915060203d60201161056f576105618183610f79565b5f614396565b60018060a01b03165f52609c60205260405f20908154818103908111611406576143fa9255613bb9565b609854906001600160801b03908183160316906001600160801b03191617609855565b61442561443e565b61442d61462c565b60d35481036144395750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561446d57565b604051631afcd79f60e31b8152600490fd5b61448761443e565b801561449d57600181016144985750565b609d55565b6040516331278a8760e01b8152600490fd5b6144b761443e565b6801bc16d674ec8000006144c96121b4565b1061449d5761443961462c565b6144de61443e565b6001600160a01b0316806144ef5750565b61016a80546001600160a01b0319169091179055565b61450d61443e565b61451561443e565b61451d61443e565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341061455657611fb03430613dbe565b60405163ea2559bb60e01b8152600490fd5b90816020910312610327575160ff811681036103275790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948161460b575b506145d157604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614d1283398151915284036145f257612166929350614ad5565b604051632a87526960e21b815260048101859052602490fd5b61462591955060203d60201161056f576105618183610f79565b935f6145ab565b6e5661756c7456616c696461746f727360881b602060405161464d81610f10565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610f2b5760405251902090565b8151919060418303614729576147229250602082015190606060408401519301515f1a90614b77565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261068481610f10565b60018060a01b0381165f5261013760205260405f20906040519161477f83610f10565b54906001600160801b03918281169081855260801c602085015215612690576141a86108866147d2926147b0613688565b6147b9866126a8565b6001600160a01b03165f908152609c6020526040902090565b915116116142de57565b9291908015611b04576001600160a01b03828116928315610b6457614802611729614bf9565b6148ef5790611837956148d3612d96857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f95816148a861484d6119b66099546001600160801b031690565b9261221461487a85614875614860614968565b61486f6119b6609e5460801c90565b906123cf565b6123cf565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c602052604090206148cb8382546121d7565b905501613bb9565b6040805188815260208101959095529116929081908101613e5d565b9293946148fb83611f69565b938415613e74577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea8348093614945866149609361493b6109fb612e3184613bb9565b61319b84876143d0565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b609a548061497557505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661125d565b6149b2614bf9565b156149b957565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561057657614a66936001600160401b036108616040614a45946020975f91614ab6575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610576575f91614a9d575090565b610684915060203d60201161056f576105618183610f79565b614acf915060603d606011610b3457610b258183610f79565b5f614a36565b90813b15614b56575f80516020614d1283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614b3b57611fb091614c68565b505034614b4457565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614bee579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610576575f516001600160a01b03811615614be457905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f91614c4f575090565b610684915060203d602011611163576111548183610f79565b5f8061068493602081519101845af4614c7f612479565b9190614c955750805115613c4a57805190602001fd5b81511580614cc8575b614ca6575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614c9e56fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122035548413bcd03e27aac60751ad1e40b89f59d863d7834fa8790a56e9bb12aaf064736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612695565b005b5f3560e01c806301d523b61461031157806301e1d1141461030c578063066055e01461030757806307a2d13a1461030257806314c4184b146102fd57806318f72950146102f85780631a7ff553146102f3578063201b9eb5146102ee5780632999ad3f146102e95780632cdf7401146102e45780633229fa95146102df57806333194c0a146102da57806336fe59d2146102d55780633a98ef39146102d0578063439fab91146102cb57806343e82a79146102c657806346904840146102c15780634ec96b22146102bc5780634f1ef286146102b757806352d1902d146102b257806353156f28146102ad57806354fd4d50146102a85780635c60da1b146102a35780635cfc1a511461029e57806360d60e6e1461029957806372b410a814610294578063754c38881461028f57806376b58b901461028a5780637fd6f15c1461028557806383d430d5146102805780638697d2c21461027b5780638ceab9aa146102765780639267842a14610271578063a49a1e7d1461026c578063ac9650d814610267578063ad3cb1cc14610262578063b1f0e7c71461025d578063b45a1eb514610258578063c6e6f59214610253578063d0a64ddc1461024e578063d83ad00c14610249578063e74b981b14610244578063ee3bd5df1461023f578063f04da65b1461023a578063f45bf3d214610235578063f851a440146102305763f9609f080361000e57611e89565b611e62565b611e21565b611de6565b611dc0565b611d93565b611d6d565b611d40565b611d22565b611cf0565b611ccc565b611c87565b611c11565b611b16565b611922565b6118ee565b611748565b611578565b611554565b611503565b611498565b61140b565b611366565b61134c565b611318565b6112fd565b6112d9565b611270565b610feb565b610e86565b610e5e565b610d51565b610c8b565b610c0a565b610bf6565b610bbc565b610b90565b610b76565b6106d3565b610687565b610628565b6105c2565b610599565b61057b565b6103d7565b6103a6565b610339565b6001600160a01b0381160361032757565b5f80fd5b908160809103126103275790565b60803660031901126103275760043561035181610316565b60443561035d81610316565b606435906001600160401b0382116103275760209261038b61038661039494369060040161032b565b611f8f565b60243590612024565b604051908152f35b5f91031261032757565b34610327575f36600319011261032757602060985460801c604051908152f35b6001600160801b0381160361032757565b34610327576020366003190112610327576004356103f4816103c6565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610576575f91610547575b50335f9081526101376020526040902061047090611ecd565b916001600160801b0361048a84516001600160801b031690565b1615610535576104e3836104a0610531956126a8565b6104ca6104bd846104b884516001600160801b031690565b611f1e565b6001600160801b03168252565b335f90815261013760205260409020611f37565b611f37565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610569915060203d60201161056f575b6105618183610f79565b810190611eb3565b5f610457565b503d610557565b611ec2565b34610327576020366003190112610327576020610394600435611f69565b34610327575f36600319011261032757610201546040516001600160a01b039091168152602090f35b6060366003190112610327576004356105da81610316565b6024356105e681610316565b604435906001600160401b0382116103275760209261060f61038661039494369060040161032b565b61061833612ece565b61062181612ece565b3490613e86565b34610327576020366003190112610327576004356001600160401b0381116103275761038661002091369060040161032b565b60609060031901126103275760043561067381610316565b906024359060443561068481610316565b90565b3461032757602061039461069a3661065b565b916106a433612ece565b33614125565b606090600319011261032757600435906024356106c681610316565b9060443561068481610316565b34610327576106e1366106aa565b906001600160a01b0380831615610b64576106fa613688565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103275760408051631d8557d760e01b815260049491905f81878183875af1801561057657610b4b575b506001600160a01b0383165f9081526101376020526040902061076d90611ecd565b6001600160801b03928361078883516001600160801b031690565b1615610b3b57610797826126a8565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610576575f98610b0a575b50602097888101956001600160401b039182806108108a516001600160401b031690565b1614610afa57908c92918751918c838061083c6303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561057657610868938e5f94610ad5575b5050516001600160801b03165b16906127d7565b9661088c6108868a60018060a01b03165f52609c60205260405f2090565b54611f69565b928389118015610ac5575b610ab557908b6108d593926108b389516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561057657670de0b6b3a764000094610924948e5f95610a88575b505061091661090861091c926123b2565b93516001600160401b031690565b936123b2565b92169061284b565b1015610a7a578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610576577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610a57956109ce93610a5c575b50506109b16104bd6109a18c613bb9565b83516001600160801b0316611f1e565b6001600160a01b0386165f90815261013760205260409020611f37565b6109d782613c86565b90610a166109fb6109e785613bb9565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610a2082866143d0565b610a2a8389613bec565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610a7292903d1061056f576105618183610f79565b505f80610990565b835163185cfc6d60e11b8152fd5b61091c929550610aab610916928261090893903d1061056f576105618183610f79565b959250508e6108f7565b875163efda1a2760e01b81528590fd5b50610ace611fb3565b8911610897565b6108619294509081610af292903d1061056f576105618183610f79565b92908e610854565b8651630709133160e01b81528490fd5b610b2d91985060603d606011610b34575b610b258183610f79565b810190612f03565b965f6107ec565b503d610b1b565b825163673f032f60e11b81528790fd5b80610b58610b5e92610f30565b8061039c565b5f61074b565b60405163d92e233d60e01b8152600490fd5b34610327575f366003190112610327576020610394611fb3565b34610327575f366003190112610327576020610baa611fe9565b6040516001600160a01b039091168152f35b34610327575f3660031901126103275760206040517fa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d208152f35b6020610394610c043661065b565b91612024565b34610327575f3660031901126103275760206001600160801b0360985416604051908152f35b9181601f84011215610327578235916001600160401b038311610327576020838186019501011161032757565b602060031982011261032757600435906001600160401b03821161032757610c8791600401610c30565b9091565b610c9436610c5d565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610d3d575b610d2b5768010000000000000003610cee9368ffffffffffffffffff19161784556120e5565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610cc8565b3461032757610d5f366106aa565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105765782915f91610e2f575b50163303610e1d5781610a57610dea86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396612f43565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610e51915060203d602011610e57575b610e498183610f79565b810190612051565b5f610db2565b503d610e3f565b34610327575f366003190112610327576065546040516001600160a01b039091168152602090f35b3461032757602036600319011261032757600435610ea381610316565b60018060a01b03165f52610137602052602060405f2060405190610ec682610f10565b54906001600160801b03918281169081835260801c84830152610eee575b5116604051908152f35b610ef7816126a8565b610ee4565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b03821117610f2b57604052565b610efc565b6001600160401b038111610f2b57604052565b606081019081106001600160401b03821117610f2b57604052565b608081019081106001600160401b03821117610f2b57604052565b90601f801991011681019081106001600160401b03821117610f2b57604052565b6001600160401b038111610f2b57601f01601f191660200190565b929192610fc182610f9a565b91610fcf6040519384610f79565b829481845281830111610327578281602093845f960137010152565b60408060031936011261032757600490813561100681610316565b6024356001600160401b0381116103275736602382011215610327576110359036906024818701359101610fb5565b9161103e61345c565b8051926110758461106760209363439fab9160e01b858401528460248401526044830190611b89565b03601f198101865285610f79565b61107d61345c565b6110856134b5565b6001600160a01b0383811680159291908790841561123b575b84156111cd575b841561116a575b505082156110d4575b50506110c5576100208383614581565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610576575f9261113d575b5050155f806110b5565b61115c9250803d10611163575b6111548183610f79565b8101906121c2565b5f80611133565b503d61114a565b855163054fd4d560e41b81529294508391839182905afa90811561057657879160ff915f916111a0575b5016141591865f6110ac565b6111c09150843d86116111c6575b6111b88183610f79565b810190614568565b5f611194565b503d6111ae565b935050835163198ca60560e11b815282818981875afa9081156105765788917fa2d618745a84ee1647adb00f6b31dcca3bb90ddc2b1211d1d4d9757016d93d20915f9161121e575b501415936110a5565b6112359150853d871161056f576105618183610f79565b5f611215565b5f80516020614d12833981519152549094508490611269906001600160a01b03165b6001600160a01b031690565b149361109e565b34610327575f366003190112610327577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036112c75760206040515f80516020614d128339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112610327576001600160a01b036112f4611fe9565b163303610e1d57005b34610327575f36600319011261032757602060405160038152f35b34610327575f366003190112610327575f80516020614d12833981519152546040516001600160a01b039091168152602090f35b34610327575f3660031901126103275760206103946121b4565b3461032757602036600319011261032757609a80549081905f6004355b8482106113b4575050508110156113a957610531905b6040519081529081906020820190565b506105315f19611399565b909193808316906001818518811c8301809311611406575f8790525f80516020614cd28339815191528301546001600160a01b03168410156113fb575050935b9190611383565b9095910192506113f4565b611ef2565b34610327575f36600319011261032757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610576576020915f9161147b575b506040519015158152f35b6114929150823d8411611163576111548183610f79565b5f611470565b34610327576020366003190112610327576004356114b581610316565b6114bd6134b5565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103275760803660031901126103275761053161153760043561152681610316565b6064359060443590602435906121e4565b604080519384526020840192909252908201529081906060820190565b34610327575f36600319011261032757602061ffff60655460a01c16604051908152f35b34610327576003196040368201126103275760049081356001600160401b038082116103275760a082850193833603011261032757602435908111610327576115c49036908501610c30565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103275760405163837d444160e01b8152905f9082908183816116178c828f016122c6565b03925af1801561057657611735575b5061162f613688565b6116376125c7565b9081163314159182611706575b505090506116f5576044019160b061165c8484612344565b905004801580156116dd575b6116cd5761167d611677611fb3565b91612399565b116116be575060b061168f8383612344565b9050145f146116ab57610020916116a591612344565b90613aa6565b610020916116b891612344565b9061397e565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506116e88484612344565b905060b082021415611668565b604051634ca8886760e01b81528390fd5b611729925061172361172d9461171b88613713565b923691610fb5565b916137ed565b1590565b805f80611644565b80610b5861174292610f30565b5f611626565b346103275760603660031901126103275760043560243561176d6044358284336121e4565b91926117997f0000000000000000000000000000000000000000000000000000000000000000826123cf565b421080156118e6575b80156118de575b6118cc577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936118046117e96117de86613bb9565b60995460801c611f1e565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916118489190611837608082610f79565b5190205f52609b60205260405f2090565b555f9360018311611881575b505050506118628233613bec565b604080519485526020850191909152830152339180606081015b0390a2005b6118c29293945061189290886123cf565b60408051336020820190815291810193909352606083018290526080958601835290949091906118379082610f79565b555f808080611854565b604051630e3d8e8d60e11b8152600490fd5b5082156117a9565b5081156117a2565b3461032757604036600319011261032757602061191960243561191081610316565b600435336147dc565b6103943361475c565b346103275760203660031901126103275760043561193e613688565b335f9081526101376020526040902061195690611ecd565b6001600160801b038061197083516001600160801b031690565b1615610535578290611981836126a8565b82516001600160801b03161610611b0457335f908152609c6020526040902054826119c26119b684516001600160801b031690565b6001600160801b031690565b14611aee576119e690836119e06119b685516001600160801b031690565b9161284b565b91611a13611a066119f683613bb9565b84516001600160801b03166109ee565b6001600160801b03168352565b335f90815261013760205260409020611a2d908390611f37565b611a756020611a6660018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336147dc565b9301516001600160801b031690565b833b156103275760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105765761053192611adb575b506040519081529081906020820190565b80610b58611ae892610f30565b5f611aca565b335f908152610137602052604081205591611a2d565b604051636edcc52360e01b8152600490fd5b346103275761187c7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611b4836610c5d565b9290611b526134b5565b60405191829160208352339560208401916122a6565b5f5b838110611b795750505f910152565b8181015183820152602001611b6a565b90602091611ba281518092818552858086019101611b68565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611be35750505050505090565b9091929394958480611c01600193603f198682030187528a51611b89565b9801930193019194939290611bd3565b34610327576020366003190112610327576001600160401b036004358181116103275736602382011215610327578060040135918211610327573660248360051b8301011161032757610531916024611c6a920161251a565b60405191829182611bae565b906020610684928181520190611b89565b34610327575f36600319011261032757610531604051611ca681610f10565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611b89565b34610327575f366003190112610327576020610baa6125c7565b8015150361032757565b3461032757604036600319011261032757610020600435611d1081610316565b60243590611d1d82611ce6565b6125fd565b34610327576020366003190112610327576020610394600435613c86565b3461032757602036600319011261032757610020600435611d6081610316565b611d686134b5565b613d15565b34610327575f3660031901126103275760206001600160801b0360995416604051908152f35b3461032757602036600319011261032757610020600435611db381610316565b611dbb6134b5565b613d5c565b34610327575f3660031901126103275760206001600160801b03609e5416604051908152f35b3461032757602036600319011261032757600435611e0381610316565b60018060a01b03165f52609c602052602060405f2054604051908152f35b3461032757602036600319011261032757600435611e3e81610316565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b34610327575f366003190112610327575f546040516001600160a01b039091168152602090f35b6040366003190112610327576020610394600435611ea681610316565b6024359061060f82610316565b90816020910312610327575190565b6040513d5f823e3d90fd5b90604051611eda81610f10565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f19019190821161140657565b6001600160801b03918216908216039190821161140657565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b0381169081611f8157505090565b916106849260801c9061284b565b611f9b611fa2916129b3565b9190612b49565b611fa857565b611fb0612cfa565b50565b476099546001600160801b03611fca818316611f69565b90609e5416019060801c01908181115f14611fe3570390565b50505f90565b61016a546001600160a01b03168015611fff5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b90610684929161203333612ece565b61203c33612ece565b612047833433613e86565b506106a433612ece565b90816020910312610327575161068481610316565b906020828203126103275781356001600160401b0392838211610327570191606083830312610327576040519261209c84610f43565b80358452602081013561ffff81168103610327576020850152604081013591821161032757019080601f83011215610327578160206120dd93359101610fb5565b604082015290565b5f549091906001600160a01b03166121aa5760405163e7f6f22560e01b8152906020908183600481335afa928315610576575f9361218b575b50604051636f4fa30f60e01b8152938285600481335afa9081156105765761216695612161945f93612168575b505061215a9192810190612066565b9083613368565b613450565b565b61215a9350908161218492903d10610e5757610e498183610f79565b915f61214b565b6121a3919350823d8411610e5757610e498183610f79565b915f61211e565b505061216661325c565b609d548061068457505f1990565b90816020910312610327575161068481611ce6565b9190820391821161140657565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061222281608081015b03601f198101835282610f79565b5190205f52609b60205260405f2054918215612252576122439183916134ed565b90918281039081116114065792565b5050505f905f905f90565b9035601e19823603018112156103275701602081359101916001600160401b03821161032757813603831361032757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610684926020815282356020820152602083013560408201526123026122f2604085018561225d565b84606085015260c08401916122a6565b9061233561232a612316606087018761225d565b601f198587038101608087015295916122a6565b94608081019061225d565b939092828603019101526122a6565b903590601e198136030182121561032757018035906001600160401b0382116103275760200191813603831361032757565b634e487b7160e01b5f52601260045260245ffd5b8115612394570490565b612376565b906801bc16d674ec800000918083029283040361140657565b90670de0b6b3a76400009182810292818404149015171561140657565b9190820180921161140657565b6001600160401b038111610f2b5760051b60200190565b906123fd826123dc565b61240a6040519182610f79565b828152809261241b601f19916123dc565b01905f5b82811061242b57505050565b80606060208093850101520161241f565b634e487b7160e01b5f52603260045260245ffd5b9082101561246757610c879160051b810190612344565b61243c565b908092918237015f815290565b3d156124a3573d9061248a82610f9a565b916124986040519384610f79565b82523d5f602084013e565b606090565b602081830312610327578051906001600160401b038211610327570181601f820112156103275780516124da81610f9a565b926124e86040519485610f79565b81845260208284010111610327576106849160208085019101611b68565b80518210156124675760209160051b010190565b919091612526836123f3565b925f5b81811061253557505050565b5f80612542838587612450565b6040939161255485518093819361246c565b0390305af490612562612479565b91156125895750906001916125778288612506565b526125828187612506565b5001612529565b906044815110610327576125c36125ae600492838101516024809183010191016124a8565b925162461bcd60e51b81529283928301611c76565b0390fd5b60d2546001600160a01b03168061068457507f000000000000000000000000000000000000000000000000000000000000000090565b610201546001600160a01b03919082163303610e1d576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612690576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b61269e33612ece565b611fb03433613dbe565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f9161273e575b5060208201916001600160801b03918284511691828214612737578361272a61272561273295858486511661284b565b613bb9565b169052613bb9565b169052565b5050505050565b612757915060203d60201161056f576105618183610f79565b5f6126f5565b90808202905f19818409908280831092039180830392146127cc5761271090828211156127ba577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461283a57670de0b6b3a764000090828211156127ba577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146128be57848311156127ba57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090610684925061238a565b90816060910312610327578051916040602083015192015161068481611ce6565b81835290916001600160fb1b0383116103275760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103610327576040830152604081013561293f81610316565b6001600160a01b031660608381019190915281013536829003601e19018112156103275701602081359101906001600160401b038111610327578060051b360382136103275760a08360808061068496015201916128ec565b9190915f838201938412911290801582169115161761140657565b6040516325f56f1160e01b81526001600160a01b039291606090829081906129de9060048301612910565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610576575f915f905f95612b04575b508415612ab15781612a28611fe9565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612aaa57509060205f92600460405180958193634641257d60e01b83525af190811561057657612a85925f92612a89575b50612998565b9190565b612aa391925060203d60201161056f576105618183610f79565b905f612a7f565b9081612ab7575b50509190565b803b1561032757604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561057657612af1575b80612ab1565b80610b58612afe92610f30565b5f612aeb565b91945050612b2a915060603d606011612b32575b612b228183610f79565b8101906128cb565b93905f612a18565b503d612b18565b600160ff1b8114611406575f0390565b8015611fb057612b5e6119b660985460801c90565b5f8212612c305781612b6f916123cf565b90612b7c6109fb83613bb9565b612b916065549161ffff8360a01c169061275d565b801561269057807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793612bcf6119b66098546001600160801b031690565b80612c1a575050612c1590925b6001600160a01b031691612bf08484613f32565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b612c1592612c2a9203908461284b565b92612bdc565b90612c3a90612b39565b612c4f6119b6609e546001600160801b031690565b80612c6f575b5080612c5f575050565b6127256109fb91612166936121d7565b90612cd67f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91611399612cba612caf612ca888886123cf565b878561284b565b808094039603613bb9565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f612c55565b9190916001600160801b038080941691160191821161140657565b612d1347612d0d6119b660995460801c90565b906121d7565b908115612ec957609e546001600160801b0381169081612e51575b5050612d456119b66099546001600160801b031690565b9182158015612e49575b612e4357612d6690612d6084611f69565b90614113565b8015612e4357612d7581613c86565b928315612e3c57612e3161216692612db2612d96612725886109fb966121d7565b6001600160801b03166001600160801b03196099541617609955565b612dcc6117e9612dc183613bb9565b60995460801c612cdf565b612dd68187613fdc565b60408051878152602081018390525f80516020614cf28339815191529190a1612725612e15612e0488613bb9565b6098546001600160801b0316611f1e565b6001600160801b03166001600160801b03196098541617609855565b60985460801c611f1e565b505f925050565b505f9150565b508015612d4f565b8184929410612e3c57612dc184612e99935f80516020614cf2833981519152826117e99560801c612e828282613fdc565b604080519182526020820192909252a10394613bb9565b612ead6001600160801b03609e5416609e55565b612ec26001600160801b0319609e5416609e55565b5f80612d2e565b5f9150565b6001600160a01b03165f908152610202602052604090205460ff16610e1d57565b51906001600160401b038216820361032757565b90816060910312610327576120dd6040805192612f1f84610f43565b8051612f2a816103c6565b8452612f3860208201612eef565b602085015201612eef565b92906001600160a01b039081811615610b6457612f5e613688565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561032757604094855193631d8557d760e01b85526004945f81878183895af1801561057657613249575b506001600160a01b0388165f90815261013760205260409020612fd190611ecd565b906001600160801b03612feb83516001600160801b031690565b161561323957612ffa826126a8565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156105765761321a575b508651936303d1689d60e11b97888652602091828780613074888c83019190602083019252565b0381845afa968715610576575f976131fb575b5086996130a76108868d60018060a01b03165f52609c60205260405f2090565b881180156131eb575b6131db5790836130ed926130cb87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610576575f859488946131329c6131be575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af1958615610576576109a16131799461315c936104bd936121669a6131a0575b5050613bb9565b6001600160a01b0388165f90815261013760205260409020611f37565b61319b61318583613c86565b80976131966109fb6109e787613bb9565b6143d0565b613bec565b816131b692903d1061056f576105618183610f79565b505f80613155565b6131d490873d891161056f576105618183610f79565b505f613107565b825163efda1a2760e01b81528990fd5b506131f4611fb3565b88116130b0565b613213919750833d851161056f576105618183610f79565b955f613087565b6132329060603d606011610b3457610b258183610f79565b505f61304d565b875163673f032f60e11b81528690fd5b80610b5861325692610f30565b5f612faf565b61326461443e565b6132796119b66099546001600160801b031690565b60018111613356576001146132ed575b609f54613294614968565b908082106132b0575b50506132a85f609f55565b61216661441d565b5f80516020614cf2833981519152916132e391036132cd816140da565b604080519182525f602083015290918291820190565b0390a15f8061329d565b61330a612e156133056098546001600160801b031690565b611f06565b61331f6001600160801b031960995416609955565b613327614098565b5f80516020614cf28339815191526040518061334e81905f60206040840193600181520152565b0390a1613289565b604051630299325160e41b8152600490fd5b61337061443e565b604083015161337d61443e565b6001600160a01b0382168015610b64576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806133d633946020830190611b89565b0390a26020830151926133e761443e565b61271061ffff85161161343e576134369361340461342993613d5c565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555161447f565b6134316144af565b6144d6565b612166614505565b604051638a81d3b360e01b8152600490fd5b61216690611d6861443e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821561349a575b50506112c757565b5f80516020614d128339815191525416141590505f80613492565b5f546001600160a01b03163303610e1d57565b906040516134d581610f10565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613680575b613673578361363d575f5b609a5f526001600160a01b03166135325f80516020614cd283398151915286016134c8565b8051909790613549906001600160a01b031661125d565b9861356e6135626020809b01516001600160601b031690565b6001600160601b031690565b948381108015613633575b6136215791600193979a956135986135a4939488035b838c0390614113565b8092019887039161284b565b01970193808611801590613617575b61360c57609a5f5282906135d55f80516020614cd283398151915287016134c8565b805190890151969992966001600160a01b0390911694600193926135a49290916001600160601b039091169061359890880361358f565b945050509250509190565b50818510156135b3565b60405163e8722f8f60e01b8152600490fd5b50808b1115613579565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031661350d565b505093505050505f905f90565b508415613502565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f916136f4575b506136e257565b60405163e775715160e01b8152600490fd5b61370d915060203d602011611163576111548183610f79565b5f6136db565b604290467f0000000000000000000000000000000000000000000000000000000000000000036137c15760d354905b6137596137526040830183612344565b3691610fb5565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526137a481610f5e565b5190206040519161190160f01b8352600283015260228201522090565b6137c961462c565b90613742565b600411156137d957565b634e487b7160e01b5f52602160045260245ffd5b6137f783836146f9565b50613804819592956137cf565b1593846138a0575b50831561381a575b50505090565b5f929350908291604051613852816122146020820194630b135d3f60e11b998a87526024840152604060448401526064830190611b89565b51915afa9061385f612479565b82613892575b82613875575b50505f8080613814565b61388a91925060208082518301019101611eb3565b145f8061386b565b915060208251101591613865565b6001600160a01b0383811691161493505f61380c565b906030116103275790603090565b906090116103275760300190606090565b9060b0116103275760900190602090565b90939293848311610327578411610327578101920390565b35906020811061390c575090565b5f199060200360031b1b1690565b969594906139579361393b613949926060979560808c5260808c01916122a6565b9089820360208b0152611b89565b9187830360408901526122a6565b930152565b90602061068492818152019061228e565b9160206106849381815201916122a6565b60b091828104915f9081613990614733565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b8784106139d257505050505050505050565b826139e19101809288876138e6565b906139ec82826138b6565b91613a0b613a056139fd86846138c4565b9690936138d5565b906138fe565b90893b15610327575f908d613a38604094855198899485946304512a2360e31b86528a8a6004880161391a565b03816801bc16d674ec8000008d5af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194613a8492613a93575b50519283928361396d565b0390a1600181930192906139c0565b80610b58613aa092610f30565b5f613a79565b8160301161032757613a05917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613ae4614733565b90613afb613af284866138c4565b969094866138d5565b94813b15610327576801bc16d674ec8000005f94613b6197604051988996879586946304512a2360e31b865260806004870152613b52613b3f8d608489019061228e565b60031994858983030160248a0152611b89565b928684030160448701526122a6565b90606483015203925af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192612c1592613baa575b506040519182918261395c565b613bb390610f30565b5f613b9d565b6001600160801b0390818111613bcd571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613c745760028355814710613c5c575f918291829182916001600160a01b03165af1613c3e612479565b5015613c4a5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b03821681158015613cb5575b15613ca85750905090565b6106849260801c9161284b565b508015613c9d565b6098546001600160801b0381169082158015613d0d575b15613cde57505090565b60801c90613ced82828561284b565b9282156123945709613cfc5790565b600181018091111561068457611ef2565b508115613cd4565b61020180546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b613d64613688565b6001600160a01b03168015613dac57606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190613dc8613688565b6001600160a01b038316908115610b64578015613e745780613def6119b660985460801c90565b0193613df96121b4565b8511613e62576109fb94613e2091613e1b613e1385613cbd565b978893613bb9565b613f32565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613e92613688565b6001600160a01b038216918215610b64578115613e745781613eb96119b660985460801c90565b01613ec26121b4565b8111613e62576109fb95613f09613e5d927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613e1b613f0188613cbd565b9a8b93613bb9565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613f3b82613bb9565b60985490613f536001600160801b0391828416612cdf565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609a549068010000000000000000821015610f2b576001820180609a5582101561246757609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614cd283398151915290910155565b919091801561408657613fed614968565b908101809111611406576001600160a01b03808211614066576001600160601b039081851161404657906121669394614041926040519461402d86610f10565b168452166001600160601b03166020830152565b613f7e565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b6140a0614968565b60018101809111611406576001600160a01b03808211614066579061216691604051916140cc83610f10565b1681525f6020820152613f7e565b8015614086576140e8614968565b908101809111611406576001600160a01b03808211614066579061216691604051916140cc83610f10565b9080821015614120575090565b905090565b93929190916141326149aa565b61413a613688565b6001600160a01b0385165f9081526101376020526040902061415b90611ecd565b946001600160801b0361417587516001600160801b031690565b161561434157614184866126a8565b6001600160a01b0381165f908152609c602052604090206141ad906141a890610886565b6149cb565b955f198414614311575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610576575f966142f0575b50859861424961423c61422c84613bb9565b86516001600160801b0316612cdf565b6001600160801b03168552565b61425d6119b685516001600160801b031690565b116142de577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58956142a66142d9946104de8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61430a91965060203d60201161056f576105618183610f79565b945f61421a565b92506143276119b684516001600160801b031690565b80871115614337578603926141b7565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576576143ac9161439c915f916143b1575b50613bb9565b6001600160801b03166020880152565b614184565b6143ca915060203d60201161056f576105618183610f79565b5f614396565b60018060a01b03165f52609c60205260405f20908154818103908111611406576143fa9255613bb9565b609854906001600160801b03908183160316906001600160801b03191617609855565b61442561443e565b61442d61462c565b60d35481036144395750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561446d57565b604051631afcd79f60e31b8152600490fd5b61448761443e565b801561449d57600181016144985750565b609d55565b6040516331278a8760e01b8152600490fd5b6144b761443e565b6801bc16d674ec8000006144c96121b4565b1061449d5761443961462c565b6144de61443e565b6001600160a01b0316806144ef5750565b61016a80546001600160a01b0319169091179055565b61450d61443e565b61451561443e565b61451d61443e565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341061455657611fb03430613dbe565b60405163ea2559bb60e01b8152600490fd5b90816020910312610327575160ff811681036103275790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948161460b575b506145d157604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614d1283398151915284036145f257612166929350614ad5565b604051632a87526960e21b815260048101859052602490fd5b61462591955060203d60201161056f576105618183610f79565b935f6145ab565b6e5661756c7456616c696461746f727360881b602060405161464d81610f10565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610f2b5760405251902090565b8151919060418303614729576147229250602082015190606060408401519301515f1a90614b77565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261068481610f10565b60018060a01b0381165f5261013760205260405f20906040519161477f83610f10565b54906001600160801b03918281169081855260801c602085015215612690576141a86108866147d2926147b0613688565b6147b9866126a8565b6001600160a01b03165f908152609c6020526040902090565b915116116142de57565b9291908015611b04576001600160a01b03828116928315610b6457614802611729614bf9565b6148ef5790611837956148d3612d96857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f95816148a861484d6119b66099546001600160801b031690565b9261221461487a85614875614860614968565b61486f6119b6609e5460801c90565b906123cf565b6123cf565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c602052604090206148cb8382546121d7565b905501613bb9565b6040805188815260208101959095529116929081908101613e5d565b9293946148fb83611f69565b938415613e74577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea8348093614945866149609361493b6109fb612e3184613bb9565b61319b84876143d0565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b609a548061497557505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661125d565b6149b2614bf9565b156149b957565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561057657614a66936001600160401b036108616040614a45946020975f91614ab6575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610576575f91614a9d575090565b610684915060203d60201161056f576105618183610f79565b614acf915060603d606011610b3457610b258183610f79565b5f614a36565b90813b15614b56575f80516020614d1283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614b3b57611fb091614c68565b505034614b4457565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614bee579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610576575f516001600160a01b03811615614be457905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f91614c4f575090565b610684915060203d602011611163576111548183610f79565b5f8061068493602081519101845af4614c7f612479565b9190614c955750805115613c4a57805190602001fd5b81511580614cc8575b614ca6575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614c9e56fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122035548413bcd03e27aac60751ad1e40b89f59d863d7834fa8790a56e9bb12aaf064736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthErc20Vault.json b/test/shared/artifacts/EthErc20Vault.json deleted file mode 100644 index 839554b7..00000000 --- a/test/shared/artifacts/EthErc20Vault.json +++ /dev/null @@ -1,1950 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthErc20Vault", - "sourceName": "contracts/vaults/ethereum/EthErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61020034620001f25762005aa338819003601f8101601f191683016001600160401b03811184821017620001f65783928291604052833961012091829181010312620001f25762000050826200020a565b6200005e602084016200020a565b6200006c604085016200020a565b916200007b606086016200020a565b62000089608087016200020a565b916200009860a088016200020a565b93620000a760c089016200020a565b95620000b660e08a016200020a565b91610100809a01519360805260a05260c0523060e052620000d66200021f565b468852865261014046815261016091825260018060a01b038061018094168452806101a0951685526101c0951685526101e0958652620001156200021f565b604051966157e49889620002bf8a396080518981816117890152818161195d01528181612f8501528181613ea80152615131015260a05189611420015260c05189818161419901526142ba015260e05189818161159f0152613c6a0152518861261501525187612c1f01525186613f1e01525185611b030152518481816104aa01528181610a8f01528181612c6001528181613364015281816134d10152818161365701526147b1015251838181610b4e0152818161111c01528181613716015261473501525182611df60152518181816125f00152612fcd0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620001f257565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620002ac576001600160401b036002600160401b0319828216016200026d57505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe60806040526004361015610022575b3615610018575f80fd5b610020612c41565b005b5f3560e01c806301d523b61461038757806301e1d11414610382578063066055e01461037d57806306fdde031461037857806307a2d13a14610373578063095ea7b31461036e57806318160ddd1461033257806318f72950146103695780631a7ff55314610364578063201b9eb51461035f57806323b872dd1461035a5780632999ad3f146103555780632cdf740114610350578063313ce5671461034b5780633229fa951461034657806333194c0a146103415780633644e5151461033c57806336fe59d2146103375780633a98ef3914610332578063439fab911461032d57806343e82a791461032857806346904840146103235780634ec96b221461031e5780634f1ef2861461031957806352d1902d1461031457806353156f281461030f57806354fd4d501461030a5780635c60da1b146103055780635cfc1a511461030057806360d60e6e146102fb57806370a082311461028d57806372b410a8146102f6578063754c3888146102f157806376b58b90146102ec5780637ecebe00146102e75780637fd6f15c146102e257806383d430d5146102dd5780638697d2c2146102d85780638ceab9aa146102d35780639267842a146102ce57806395d89b41146102c9578063a49a1e7d146102c4578063a9059cbb146102bf578063ac9650d8146102ba578063ad3cb1cc146102b5578063b1f0e7c7146102b0578063c6e6f592146102ab578063d505accf146102a6578063d83ad00c146102a1578063dd62ed3e1461029c578063e74b981b14610297578063ee3bd5df14610292578063f04da65b1461028d578063f851a440146102885763f9609f080361000e57612471565b612449565b611723565b612423565b6123f6565b6123b2565b612367565b612152565b612129565b61210f565b6120ca565b612065565b611fc4565b611f72565b611ece565b611cda565b611c82565b611ad7565b611907565b6118e3565b6118a8565b611857565b6117eb565b61175e565b611683565b611669565b611635565b61161a565b6115f6565b61158d565b611308565b611222565b6111fa565b6110ed565b611027565b610899565b610fab565b610f91565b610f57565b610f2b565b610f10565b610ef6565b610a65565b610989565b61096f565b610913565b6108bf565b6107f7565b6107d9565b610713565b61045a565b610429565b6103af565b6001600160a01b0381160361039d57565b5f80fd5b9081608091031261039d5790565b608036600319011261039d576004356103c78161038c565b6044356103d38161038c565b606435906001600160401b03821161039d576020926104016103fc6104179436906004016103a1565b61255a565b61040c823433614645565b5060243590336132a0565b604051908152f35b5f91031261039d57565b3461039d575f36600319011261039d57602060cf5460801c604051908152f35b6001600160801b0381160361039d57565b3461039d57602036600319011261039d5760043561047781610449565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156105f9575f916105ca575b50335f90815261016e602052604090206104f3906124a1565b916001600160801b0361050d84516001600160801b031690565b16156105b857610566836105236105b495612c4b565b61054d6105408461053b84516001600160801b031690565b6124f2565b6001600160801b03168252565b335f90815261016e6020526040902061250b565b61250b565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b6105ec915060203d6020116105f2575b6105e48183610698565b810190612487565b5f6104da565b503d6105da565b612496565b90600182811c9216801561062c575b602083101461061857565b634e487b7160e01b5f52602260045260245ffd5b91607f169161060d565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761066557604052565b610636565b6001600160401b03811161066557604052565b608081019081106001600160401b0382111761066557604052565b90601f801991011681019081106001600160401b0382111761066557604052565b5f5b8381106106ca5750505f910152565b81810151838201526020016106bb565b906020916106f3815180928185528580860191016106b9565b601f01601f1916010190565b9060206107109281815201906106da565b90565b3461039d575f36600319011261039d576040515f8054610732816105fe565b808452906020906001908181169081156107af575060011461076b575b6105b48561075f81870382610698565b604051918291826106ff565b5f80805293505f8051602061570f8339815191525b83851061079c5750505050810160200161075f826105b461074f565b8054868601840152938201938101610780565b8695506105b49693506020925061075f94915060ff191682840152151560051b820101929361074f565b3461039d57602036600319011261039d576020610417600435612534565b3461039d57604036600319011261039d576004356108148161038c565b6001600160a01b038116906024359082156108875761084f8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b3461039d575f36600319011261039d5760206001600160801b0360cf5416604051908152f35b606036600319011261039d576004356108d78161038c565b6024356108e38161038c565b604435906001600160401b03821161039d5760209261090c6103fc6104179436906004016103a1565b3490614645565b3461039d57602036600319011261039d576004356001600160401b03811161039d576103fc6100209136906004016103a1565b606090600319011261039d5760043561095e8161038c565b90602435906044356107108161038c565b3461039d57602061041761098236610946565b91336132a0565b3461039d57606036600319011261039d576004356109a68161038c565b602435906109b38261038c565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610a03575b6109f7846109f285888361481c565b61354b565b60405160018152602090f35b919093818503948511610a37575f9283526002602090815260408085203386529091529092209390935591806109f76109e3565b6124c6565b606090600319011261039d5760043590602435610a588161038c565b906044356107108161038c565b3461039d57610a7336610a3c565b906001600160a01b038083161561088757610a8c613e8d565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561039d5760408051631d8557d760e01b815260049491905f81878183875af180156105f957610edd575b506001600160a01b0383165f90815261016e60205260409020610aff906124a1565b6001600160801b039283610b1a83516001600160801b031690565b1615610ecd57610b2982612c4b565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa9788156105f9575f98610e9c575b50602097888101956001600160401b03918280610ba28a516001600160401b031690565b1614610e8c57908c92918751918c8380610bce6303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156105f957610bfa938e5f94610e67575b5050516001600160801b03165b1690612d7a565b96610c1e610c188a60018060a01b03165f5260d360205260405f2090565b54612534565b928389118015610e57575b610e4757908b610c679392610c4589516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa9182156105f957670de0b6b3a764000094610cb6948e5f95610e1a575b5050610ca8610c9a610cae926129f5565b93516001600160401b031690565b936129f5565b921690612dee565b1015610e0c578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156105f9577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610de995610d6093610dee575b5050610d43610540610d338c6143bf565b83516001600160801b03166124f2565b6001600160a01b0386165f90815261016e6020526040902061250b565b610d698261448c565b90610da8610d8d610d79856143bf565b60cf5460801c5b036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610db28286615185565b610dbc83896143f2565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610e0492903d106105f2576105e48183610698565b505f80610d22565b835163185cfc6d60e11b8152fd5b610cae929550610e3d610ca89282610c9a93903d106105f2576105e48183610698565b959250508e610c89565b875163efda1a2760e01b81528590fd5b50610e606125a1565b8911610c29565b610bf39294509081610e8492903d106105f2576105e48183610698565b92908e610be6565b8651630709133160e01b81528490fd5b610ebf91985060603d606011610ec6575b610eb78183610698565b8101906135df565b965f610b7e565b503d610ead565b825163673f032f60e11b81528790fd5b80610eea610ef09261066a565b8061041f565b5f610add565b3461039d575f36600319011261039d5760206104176125a1565b3461039d575f36600319011261039d57602060405160128152f35b3461039d575f36600319011261039d576020610f456125d7565b6040516001600160a01b039091168152f35b3461039d575f36600319011261039d5760206040517f9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd8152f35b3461039d575f36600319011261039d576020610417612612565b6020610417610fb936610946565b91610fc5833433614645565b50336132a0565b9181601f8401121561039d578235916001600160401b03831161039d576020838186019501011161039d57565b602060031982011261039d57600435906001600160401b03821161039d5761102391600401610fcc565b9091565b61103036610ff9565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c1680156110d9575b6110c7576801000000000000000361108a9368ffffffffffffffffff1916178455612725565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015611064565b3461039d576110fb36610a3c565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105f95782915f916111cb575b501633036111b95781610de961118686867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613639565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6111ed915060203d6020116111f3575b6111e58183610698565b810190612647565b5f61114e565b503d6111db565b3461039d575f36600319011261039d57609c546040516001600160a01b039091168152602090f35b3461039d57602036600319011261039d5760043561123f8161038c565b60018060a01b03165f5261016e602052602060405f20604051906112628261064a565b54906001600160801b03918281169081835260801c8483015261128a575b5116604051908152f35b61129381612c4b565b611280565b6040519060a082018281106001600160401b0382111761066557604052565b6001600160401b03811161066557601f01601f191660200190565b9291926112de826112b7565b916112ec6040519384610698565b82948184528183011161039d578281602093845f960137010152565b60408060031936011261039d5760049081356113238161038c565b6024356001600160401b03811161039d573660238201121561039d5761135290369060248187013591016112d2565b9161135b613c60565b8051926113928461138460209363439fab9160e01b8584015284602484015260448301906106da565b03601f198101865285610698565b61139a613c60565b6113a2613cb9565b6001600160a01b03838116801592919087908415611558575b84156114ea575b8415611487575b505082156113f1575b50506113e2576100208383614b7d565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156105f9575f9261145a575b5050155f806113d2565b6114799250803d10611480575b6114718183610698565b810190612806565b5f80611450565b503d611467565b855163054fd4d560e41b81529294508391839182905afa9081156105f957879160ff915f916114bd575b5016141591865f6113c9565b6114dd9150843d86116114e3575b6114d58183610698565b810190614b68565b5f6114b1565b503d6114cb565b935050835163198ca60560e11b815282818981875afa9081156105f95788917f9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd915f9161153b575b501415936113c2565b6115529150853d87116105f2576105e48183610698565b5f611532565b5f8051602061574f833981519152549094508490611586906001600160a01b03165b6001600160a01b031690565b14936113bb565b3461039d575f36600319011261039d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036115e45760206040515f8051602061574f8339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f36600319011261039d576001600160a01b036116116125d7565b1633036111b957005b3461039d575f36600319011261039d57602060405160038152f35b3461039d575f36600319011261039d575f8051602061574f833981519152546040516001600160a01b039091168152602090f35b3461039d575f36600319011261039d5760206104176127eb565b3461039d57602036600319011261039d5760d180549081905f6004355b8482106116d1575050508110156116c6576105b4905b6040519081529081906020820190565b506105b45f196116b6565b909193808316906001818518811c8301809311610a37575f8790525f8051602061578f8339815191528301546001600160a01b0316841015611718575050935b91906116a0565b909591019250611711565b3461039d57602036600319011261039d576004356117408161038c565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461039d575f36600319011261039d57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156105f9576020915f916117ce575b506040519015158152f35b6117e59150823d8411611480576114718183610698565b5f6117c3565b3461039d57602036600319011261039d576004356118088161038c565b611810613cb9565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461039d57608036600319011261039d576105b461188b60043561187a8161038c565b606435906044359060243590612827565b604080519384526020840192909252908201529081906060820190565b3461039d57602036600319011261039d576004356118c58161038c565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461039d575f36600319011261039d57602061ffff609c5460a01c16604051908152f35b3461039d5760031960403682011261039d5760049081356001600160401b0380821161039d5760a082850193833603011261039d5760243590811161039d576119539036908501610fcc565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561039d5760405163837d444160e01b8152905f9082908183816119a68c828f01612909565b03925af180156105f957611ac4575b506119be613e8d565b6119c6612c0a565b9081163314159182611a95575b50509050611a84576044019160b06119eb8484612987565b90500480158015611a6c575b611a5c57611a0c611a066125a1565b916129dc565b11611a4d575060b0611a1e8383612987565b9050145f14611a3a5761002091611a3491612987565b906142ac565b61002091611a4791612987565b90614184565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611a778484612987565b905060b0820214156119f7565b604051634ca8886760e01b81528390fd5b611ab89250611ab2611abc94611aaa88613f18565b9236916112d2565b91613ff3565b1590565b805f806119d3565b80610eea611ad19261066a565b5f6119b5565b3461039d57606036600319011261039d57600435602435611afc604435828433612827565b9192611b287f000000000000000000000000000000000000000000000000000000000000000082612a12565b42108015611c7a575b8015611c72575b611c60577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611b93611b78611b6d866143bf565b60d05460801c6124f2565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611bd79190611bc6608082610698565b5190205f5260d260205260405f2090565b555f9360018311611c10575b50505050611bf182336143f2565b604080519485526020850191909152830152339180606081015b0390a2005b611c5692939450611c219088612a12565b60408051336020820190815291810193909352606083018290529094909190611bc69082608081015b03908101835282610698565b555f808080611be3565b604051630e3d8e8d60e11b8152600490fd5b508215611b38565b508115611b31565b3461039d57604036600319011261039d576020600435611cae602435611ca78161038c565b8233614d6a565b90611cb83361354b565b60405190815230905f8051602061576f833981519152843392a3604051908152f35b3461039d57602036600319011261039d57600435611cf6613e8d565b335f90815261016e60205260409020611d0e906124a1565b6001600160801b0380611d2883516001600160801b031690565b16156105b8578290611d3983612c4b565b82516001600160801b03161610611ebc57335f90815260d3602052604090205482611d7a611d6e84516001600160801b031690565b6001600160801b031690565b14611ea657611d9e9083611d98611d6e85516001600160801b031690565b91612dee565b91611dcb611dbe611dae836143bf565b84516001600160801b0316610d80565b6001600160801b03168352565b335f90815261016e60205260409020611de590839061250b565b611e2d6020611e1e60018060a01b037f000000000000000000000000000000000000000000000000000000000000000016809633614d6a565b9301516001600160801b031690565b833b1561039d5760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105f9576105b492611e93575b506040519081529081906020820190565b80610eea611ea09261066a565b5f611e82565b335f90815261016e602052604081205591611de5565b604051636edcc52360e01b8152600490fd5b3461039d575f36600319011261039d576040515f60018054611eef816105fe565b80855291602091600181169081156107af5750600114611f19576105b48561075f81870382610698565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510611f5f5750505050810160200161075f826105b461074f565b8054868601840152938201938101611f43565b3461039d57611c0b7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611fa436610ff9565b9290611fae613cb9565b60405191829160208352339560208401916128e9565b3461039d57604036600319011261039d57611fee600435611fe48161038c565b602435903361481c565b611ff73361354b565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120375750505050505090565b9091929394958480612055600193603f198682030187528a516106da565b9801930193019194939290612027565b3461039d57602036600319011261039d576001600160401b0360043581811161039d573660238201121561039d57806004013591821161039d573660248360051b8301011161039d576105b49160246120be9201612b5d565b60405191829182612002565b3461039d575f36600319011261039d576105b46040516120e98161064a565b60058152640352e302e360dc1b60208201526040519182916020835260208301906106da565b3461039d575f36600319011261039d576020610f45612c0a565b3461039d57602036600319011261039d57602061041760043561448c565b60ff81160361039d57565b3461039d5760e036600319011261039d5760043561216f8161038c565b60243561217b8161038c565b60443590606435926084359061219082612147565b6001600160a01b0383811695909290861561088757428110612355576020915f91611c4a61228389878a6122466121c5612612565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039161225a601f1993848101835282610698565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa156105f9575f51928284168015908115612348575b5061233657612323859161230e7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610de9565b6040516323389ba560e21b8152600490fd5b905083831614155f6122c9565b604051631ab7da6b60e01b8152600490fd5b3461039d575f36600319011261039d5760206001600160801b0360d05416604051908152f35b604090600319011261039d576004356123a58161038c565b906024356107108161038c565b3461039d5760206123ed6123c53661238d565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b3461039d57602036600319011261039d576100206004356124168161038c565b61241e613cb9565b61451b565b3461039d575f36600319011261039d5760206001600160801b0360d55416604051908152f35b3461039d575f36600319011261039d576037546040516001600160a01b039091168152602090f35b602061041761247f3661238d565b903490614645565b9081602091031261039d575190565b6040513d5f823e3d90fd5b906040516124ae8161064a565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f190191908211610a3757565b6001600160801b039182169082160391908211610a3757565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161254c57505090565b916107109260801c90612dee565b61256661256d91612f54565b91906130ea565b61257357565b61257b614f85565b80612584575b50565b5f906040519081525f8051602061576f83398151915260203092a3565b4760d0546001600160801b036125b8818316612534565b9060d55416019060801c01908181115f146125d1570390565b50505f90565b6101a1546001600160a01b031680156125ed5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f00000000000000000000000000000000000000000000000000000000000000000361263f5760045490565b610710613952565b9081602091031261039d57516107108161038c565b359061ffff8216820361039d57565b9080601f8301121561039d57816020610710933591016112d2565b9060208282031261039d5781356001600160401b039283821161039d57019060a08282031261039d576126b7611298565b92823584526126c86020840161265c565b6020850152604083013581811161039d57826126e591850161266b565b6040850152606083013581811161039d578261270291850161266b565b6060850152608083013590811161039d5761271d920161266b565b608082015290565b6037549091906001600160a01b03166127e1576040519063e7f6f22560e01b82526020928383600481335afa9283156105f9575f936127c2575b50604051636f4fa30f60e01b8152908482600481335afa9182156105f95761279d955f9361279f575b50506127979192810190612686565b91613ba0565b565b612797935090816127bb92903d106111f3576111e58183610698565b915f612788565b6127da919350843d86116111f3576111e58183610698565b915f61275f565b505061279d613a78565b60d4548061071057505f1990565b5190811515820361039d57565b9081602091031261039d57610710906127f9565b91908203918211610a3757565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061286581608081015b03601f198101835282610698565b5190205f5260d260205260405f205491821561289557612886918391613cf2565b9091828103908111610a375792565b5050505f905f905f90565b9035601e198236030181121561039d5701602081359101916001600160401b03821161039d57813603831361039d57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06107109260208152823560208201526020830135604082015261294561293560408501856128a0565b84606085015260c08401916128e9565b9061297861296d61295960608701876128a0565b601f198587038101608087015295916128e9565b9460808101906128a0565b939092828603019101526128e9565b903590601e198136030182121561039d57018035906001600160401b03821161039d5760200191813603831361039d57565b634e487b7160e01b5f52601260045260245ffd5b81156129d7570490565b6129b9565b906801bc16d674ec8000009180830292830403610a3757565b90670de0b6b3a764000091828102928184041490151715610a3757565b91908201809211610a3757565b6001600160401b0381116106655760051b60200190565b90612a4082612a1f565b612a4d6040519182610698565b8281528092612a5e601f1991612a1f565b01905f5b828110612a6e57505050565b806060602080938501015201612a62565b634e487b7160e01b5f52603260045260245ffd5b90821015612aaa576110239160051b810190612987565b612a7f565b908092918237015f815290565b3d15612ae6573d90612acd826112b7565b91612adb6040519384610698565b82523d5f602084013e565b606090565b60208183031261039d578051906001600160401b03821161039d570181601f8201121561039d578051612b1d816112b7565b92612b2b6040519485610698565b8184526020828401011161039d5761071091602080850191016106b9565b8051821015612aaa5760209160051b010190565b919091612b6983612a36565b925f5b818110612b7857505050565b5f80612b85838587612a93565b60409391612b97855180938193612aaf565b0390305af490612ba5612abc565b9115612bcc575090600191612bba8288612b49565b52612bc58187612b49565b5001612b6c565b90604481511061039d57612c06612bf160049283810151602480918301019101612aeb565b925162461bcd60e51b815292839283016106ff565b0390fd5b610109546001600160a01b03168061071057507f000000000000000000000000000000000000000000000000000000000000000090565b612581343361457d565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9575f91612ce1575b5060208201916001600160801b03918284511691828214612cda5783612ccd612cc8612cd5958584865116612dee565b6143bf565b1690526143bf565b169052565b5050505050565b612cfa915060203d6020116105f2576105e48183610698565b5f612c98565b90808202905f1981840990828083109203918083039214612d6f576127109082821115612d5d577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612ddd57670de0b6b3a76400009082821115612d5d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f1984820993838086109503948086039514612e615784831115612d5d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509061071092506129cd565b9081606091031261039d578051916107106040602084015193016127f9565b81835290916001600160fb1b03831161039d5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361039d5760408301526040810135612ee08161038c565b6001600160a01b031660608381019190915281013536829003601e190181121561039d5701602081359101906001600160401b03811161039d578060051b3603821361039d5760a0836080806107109601520191612e8d565b9190915f8382019384129112908015821691151617610a3757565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612f7f9060048301612eb1565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156105f9575f915f905f956130a5575b5084156130525781612fc96125d7565b16917f000000000000000000000000000000000000000000000000000000000000000016821461304b57509060205f92600460405180958193634641257d60e01b83525af19081156105f957613026925f9261302a575b50612f39565b9190565b61304491925060203d6020116105f2576105e48183610698565b905f613020565b9081613058575b50509190565b803b1561039d57604051636ee3193160e11b815260048101929092525f908290602490829084905af180156105f957613092575b80613052565b80610eea61309f9261066a565b5f61308c565b919450506130cb915060603d6060116130d3575b6130c38183610698565b810190612e6e565b93905f612fb9565b503d6130b9565b600160ff1b8114610a37575f0390565b8015612581576130ff611d6e60cf5460801c90565b5f82126131d6578161311091612a12565b9061311d610d8d836143bf565b613132609c549161ffff8360a01c1690612d00565b80156131d157807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613170611d6e60cf546001600160801b031690565b806131bb5750506131b690925b6001600160a01b0316916131918484614f1d565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6131b6926131cb92039084612dee565b9261317d565b505050565b906131e0906130da565b6131f5611d6e60d5546001600160801b031690565b80613215575b5080613205575050565b612cc8610d8d9161279d9361281a565b9061327c7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916116b661326061325561324e8888612a12565b8785612dee565b8080940396036143bf565b6001600160801b03166001600160801b031960d554161760d555565b0390a15f6131fb565b9190916001600160801b0380809416911601918211610a3757565b93929190916132ad6146f1565b6132b5613e8d565b6001600160a01b0385165f90815261016e602052604090206132d6906124a1565b946001600160801b036132f087516001600160801b031690565b16156134bc576132ff86612c4b565b6001600160a01b0381165f90815260d3602052604090206133289061332390610c18565b614712565b955f19841461348c575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af19586156105f9575f9661346b575b5085986133c46133b76133a7846143bf565b86516001600160801b0316613285565b6001600160801b03168552565b6133d8611d6e85516001600160801b031690565b11613459577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5895613421613454946105618760018060a01b03165f5261016e60205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61348591965060203d6020116105f2576105e48183610698565b945f613395565b92506134a2611d6e84516001600160801b031690565b808711156134b257860392613332565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f95761352791613517915f9161352c575b506143bf565b6001600160801b03166020880152565b6132ff565b613545915060203d6020116105f2576105e48183610698565b5f613511565b60018060a01b0381165f5261016e60205260405f20906040519161356e8361064a565b54906001600160801b03918281169081855260801c6020850152156131d157613323610c186135c19261359f613e8d565b6135a886612c4b565b6001600160a01b03165f90815260d36020526040902090565b9151161161345957565b51906001600160401b038216820361039d57565b9081606091031261039d5760405190606082018281106001600160401b0382111761066557613631916040918252805161361881610449565b8452613626602082016135cb565b6020850152016135cb565b604082015290565b92906001600160a01b03908181161561088757613654613e8d565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561039d57604094855193631d8557d760e01b85526004945f81878183895af180156105f95761393f575b506001600160a01b0388165f90815261016e602052604090206136c7906124a1565b906001600160801b036136e183516001600160801b031690565b161561392f576136f082612c4b565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156105f957613910575b508651936303d1689d60e11b9788865260209182878061376a888c83019190602083019252565b0381845afa9687156105f9575f976138f1575b50869961379d610c188d60018060a01b03165f5260d360205260405f2090565b881180156138e1575b6138d15790836137e3926137c187516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa9889156105f9575f859488946138289c6138b4575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156105f957610d3361386f94613852936105409361279d9a613896575b50506143bf565b6001600160a01b0388165f90815261016e6020526040902061250b565b61389161387b8361448c565b809761388c610d8d610d79876143bf565b615185565b6143f2565b816138ac92903d106105f2576105e48183610698565b505f8061384b565b6138ca90873d89116105f2576105e48183610698565b505f6137fd565b825163efda1a2760e01b81528990fd5b506138ea6125a1565b88116137a6565b613909919750833d85116105f2576105e48183610698565b955f61377d565b6139289060603d606011610ec657610eb78183610698565b505f613743565b875163673f032f60e11b81528690fd5b80610eea61394c9261066a565b5f6136a5565b6040515f905f5490613963826105fe565b9283825260209384830193600190866001821691825f14613a58575050600114613a15575b5050918161399e613a0f93612857950382610698565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f8051602061570f8339815191525b828410613a43575050508201018161399e613988565b80548685018601528794909301928101613a2d565b60ff1916875292151560051b8501909201925083915061399e9050613988565b613a806148ba565b613a95611d6e60d0546001600160801b031690565b60018111613b8e57600114613b09575b60d654613ab0615385565b90808210613acc575b5050613ac45f60d655565b61279d614898565b5f8051602061572f83398151915291613aff9103613ae9816152b0565b604080519182525f602083015290918291820190565b0390a15f80613ab9565b613b42613b26613b2160cf546001600160801b031690565b6124da565b6001600160801b03166001600160801b031960cf54161760cf55565b613b576001600160801b031960d0541660d055565b613b5f61524e565b5f8051602061572f83398151915260405180613b8681905f60206040840193600181520152565b0390a1613aa5565b604051630299325160e41b8152600490fd5b9190613baa6148ba565b608082015190613bb86148ba565b6001600160a01b038416801561088757613c5894613c4893613c31926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613c1f339460208301906106da565b0390a2602085015161ffff16906148fb565b613c3b835161494c565b613c4361497c565b6149a9565b60606040820151910151906149d8565b61279d614b05565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613c9e575b50506115e457565b5f8051602061574f8339815191525416141590505f80613c96565b6037546001600160a01b031633036111b957565b90604051613cda8161064a565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590613e85575b613e785783613e42575f5b60d15f526001600160a01b0316613d375f8051602061578f8339815191528601613ccd565b8051909790613d4e906001600160a01b031661157a565b98613d73613d676020809b01516001600160601b031690565b6001600160601b031690565b948381108015613e38575b613e265791600193979a95613d9d613da9939488035b838c0390614c28565b80920198870391612dee565b01970193808611801590613e1c575b613e115760d15f528290613dda5f8051602061578f8339815191528701613ccd565b805190890151969992966001600160a01b039091169460019392613da99290916001600160601b0390911690613d9d908803613d94565b945050509250509190565b5081851015613db8565b60405163e8722f8f60e01b8152600490fd5b50808b1115613d7e565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316613d12565b505093505050505f905f90565b508415613d07565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9575f91613ef9575b50613ee757565b60405163e775715160e01b8152600490fd5b613f12915060203d602011611480576114718183610698565b5f613ee0565b604290467f000000000000000000000000000000000000000000000000000000000000000003613fc75761010a54905b613f5f613f586040830183612987565b36916112d2565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613faa8161067d565b5190206040519161190160f01b8352600283015260228201522090565b613fcf614c3a565b90613f48565b60041115613fdf57565b634e487b7160e01b5f52602160045260245ffd5b613ffd8383614d07565b5061400a81959295613fd5565b1593846140a6575b508315614020575b50505090565b5f929350908291604051614058816128576020820194630b135d3f60e11b998a875260248401526040604484015260648301906106da565b51915afa90614065612abc565b82614098575b8261407b575b50505f808061401a565b61409091925060208082518301019101612487565b145f80614071565b91506020825110159161406b565b6001600160a01b0383811691161493505f614012565b9060301161039d5790603090565b9060901161039d5760300190606090565b9060b01161039d5760900190602090565b9093929384831161039d57841161039d578101920390565b359060208110614112575090565b5f199060200360031b1b1690565b9695949061415d9361414161414f926060979560808c5260808c01916128e9565b9089820360208b01526106da565b9187830360408901526128e9565b930152565b9060206107109281815201906128d1565b9160206107109381815201916128e9565b60b091828104915f9081614196614d41565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b8784106141d857505050505050505050565b826141e79101809288876140ec565b906141f282826140bc565b9161421161420b61420386846140ca565b9690936140db565b90614104565b90893b1561039d575f908d61423e604094855198899485946304512a2360e31b86528a8a60048801614120565b03816801bc16d674ec8000008d5af19081156105f9577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19461428a92614299575b505192839283614173565b0390a1600181930192906141c6565b80610eea6142a69261066a565b5f61427f565b8160301161039d5761420b917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166142ea614d41565b906143016142f884866140ca565b969094866140db565b94813b1561039d576801bc16d674ec8000005f9461436797604051988996879586946304512a2360e31b8652608060048701526143586143458d60848901906128d1565b60031994858983030160248a01526106da565b928684030160448701526128e9565b90606483015203925af19081156105f9577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926131b6926143b0575b5060405191829182614162565b6143b99061066a565b5f6143a3565b6001600160801b03908181116143d3571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541461447a5760028355814710614462575f918291829182916001600160a01b03165af1614444612abc565b50156144505760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b038216811580156144bb575b156144ae5750905090565b6107109260801c91612dee565b5080156144a3565b60cf546001600160801b0381169082158015614513575b156144e457505090565b60801c906144f3828285612dee565b9282156129d757096145025790565b6001810180911115610710576124c6565b5081156144da565b614523613e8d565b6001600160a01b0316801561456b57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190614587613e8d565b6001600160a01b03831690811561088757801561463357806145ae611d6e60cf5460801c90565b01936145b86127eb565b851161462157610d8d946145df916145da6145d2856144c3565b9788936143bf565b614f1d565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192614651613e8d565b6001600160a01b0382169182156108875781156146335781614678611d6e60cf5460801c90565b016146816127eb565b811161462157610d8d956146c861461c927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c946145da6146c0886144c3565b9a8b936143bf565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b6146f9615116565b1561470057565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156105f9576147ad936001600160401b03610bf3604061478c946020975f916147fd575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156105f9575f916147e4575090565b610710915060203d6020116105f2576105e48183610698565b614816915060603d606011610ec657610eb78183610698565b5f61477d565b6001600160a01b0390811691908215801561488e575b61088757825f5260d360205260405f2090815492858403938411610a37575f8051602061576f833981519152936020935561487d8160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614832565b6148a06148ba565b6148a8614c3a565b61010a805482036148b7575050565b55565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156148e957565b604051631afcd79f60e31b8152600490fd5b6149036148ba565b61271061ffff83161161493a576149199061451b565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b6149546148ba565b801561496a57600181016149655750565b60d455565b6040516331278a8760e01b8152600490fd5b6149846148ba565b6801bc16d674ec8000006149966127eb565b1061496a576149a3614c3a565b61010a55565b6149b16148ba565b6001600160a01b0316806149c25750565b6101a180546001600160a01b0319169091179055565b6149e06148ba565b601e8151118015614afa575b614ae8576149f86148ba565b8051906001600160401b03821161066557614a1c82614a175f546105fe565b6153c7565b602090816001601f851114614a7457509180614a5292614a5995945f92614a69575b50508160011b915f199060031b1c19161790565b5f55615491565b61279d614a64613952565b600455565b015190505f80614a3e565b5f80529190601f1984165f8051602061570f833981519152935f905b828210614ad0575050916001939185614a5997969410614ab8575b505050811b015f55615491565b01515f1960f88460031b161c191690555f8080614aab565b80600186978294978701518155019601940190614a90565b604051632d3f993760e21b8152600490fd5b50600a8251116149ec565b614b0d6148ba565b614b156148ba565b614b1d6148ba565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614b5657612581343061457d565b60405163ea2559bb60e01b8152600490fd5b9081602091031261039d575161071081612147565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614c07575b50614bcd57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f8051602061574f8339815191528403614bee5761279d92935061556f565b604051632a87526960e21b815260048101859052602490fd5b614c2191955060203d6020116105f2576105e48183610698565b935f614ba7565b9080821015614c35575090565b905090565b6e5661756c7456616c696461746f727360881b6020604051614c5b8161064a565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176106655760405251902090565b8151919060418303614d3757614d309250602082015190606060408401519301515f1a90615611565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c820152602081526107108161064a565b9291908015611ebc576001600160a01b0382811692831561088757614d90611ab8615116565b614e995790611bc695614e7d614e61857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f9581614e36614ddb611d6e60d0546001600160801b031690565b92612857614e0885614e03614dee615385565b614dfd611d6e60d55460801c90565b90612a12565b612a12565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f90815260d360205260409020614e5983825461281a565b9055016143bf565b6001600160801b03166001600160801b031960d054161760d055565b604080518881526020810195909552911692908190810161461c565b929394614ea583612534565b938415614633577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea8348093614efa86614f1593614ef0610d8d614ee5846143bf565b60cf5460801c6124f2565b6138918487615185565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b5f8051602061576f83398151915260205f92614f38856143bf565b60cf5490614f506001600160801b0391828416613285565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b614f9e47614f98611d6e60d05460801c90565b9061281a565b9081156151115760d5546001600160801b0381169081615099575b5050614fd0611d6e60d0546001600160801b031690565b9182158015615091575b61508b57614ff190614feb84612534565b90614c28565b801561508b576150008161448c565b92831561508457614ee561279d92615021614e61612cc888610d8d9661281a565b61503b611b78615030836143bf565b60d05460801c613285565b61504581876152fb565b60408051878152602081018390525f8051602061572f8339815191529190a1612cc8613b26615073886143bf565b60cf546001600160801b03166124f2565b505f925050565b505f9150565b508015614fda565b818492941061508457615030846150e1935f8051602061572f83398151915282611b789560801c6150ca82826152fb565b604080519182526020820192909252a103946143bf565b6150f56001600160801b0360d5541660d555565b61510a6001600160801b031960d5541660d555565b5f80614fb9565b5f9150565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9575f9161516c575090565b610710915060203d602011611480576114718183610698565b6001600160a01b03165f81815260d360205260409020805483810391908211610a37575f935f8051602061576f83398151915292602092556151c6816143bf565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b60d154906801000000000000000082101561066557600182018060d155821015612aaa5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f8051602061578f83398151915290910155565b615256615385565b60018101809111610a37576001600160a01b03808211615290579061279d91604051916152828361064a565b1681525f60208201526151f0565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b80156152e9576152be615385565b908101809111610a37576001600160a01b03808211615290579061279d91604051916152828361064a565b604051632ec8835b60e21b8152600490fd5b91909180156152e95761530c615385565b908101809111610a37576001600160a01b03808211615290576001600160601b0390818511615365579061279d9394615360926040519461534c8661064a565b168452166001600160601b03166020830152565b6151f0565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60d1548061539257505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b031661157a565b601f81116153d3575050565b5f80525f8051602061570f833981519152906020601f840160051c83019310615416575b601f0160051c01905b81811061540b575050565b5f8155600101615400565b90915081906153f7565b90601f821161542d575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c83019310615487575b601f0160051c01905b81811061547d57505050565b5f81558201615471565b9091508190615468565b9081516001600160401b038111610665576001906154b8816154b384546105fe565b615420565b602080601f83116001146154ed575081906154e99394955f92614a695750508160011b915f199060031b1c19161790565b9055565b90601f1983169561551f60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b8882106155585750508385969710615540575b505050811b019055565b01515f1960f88460031b161c191690555f8080615536565b808785968294968601518155019501930190615523565b90813b156155f0575f8051602061574f83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156155d557612581916156a5565b5050346155de57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161569a579061566a6020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156105f9575f516001600160a01b0381161561569057905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061071093602081519101845af46156bc612abc565b91906156d2575080511561445057805190602001fd5b81511580615705575b6156e3575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156156db56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a2646970667358221220f7de8f37e59c06617071431d53b35ed8f081bb59d4820f5cd0ae3e7f09be091864736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612c41565b005b5f3560e01c806301d523b61461038757806301e1d11414610382578063066055e01461037d57806306fdde031461037857806307a2d13a14610373578063095ea7b31461036e57806318160ddd1461033257806318f72950146103695780631a7ff55314610364578063201b9eb51461035f57806323b872dd1461035a5780632999ad3f146103555780632cdf740114610350578063313ce5671461034b5780633229fa951461034657806333194c0a146103415780633644e5151461033c57806336fe59d2146103375780633a98ef3914610332578063439fab911461032d57806343e82a791461032857806346904840146103235780634ec96b221461031e5780634f1ef2861461031957806352d1902d1461031457806353156f281461030f57806354fd4d501461030a5780635c60da1b146103055780635cfc1a511461030057806360d60e6e146102fb57806370a082311461028d57806372b410a8146102f6578063754c3888146102f157806376b58b90146102ec5780637ecebe00146102e75780637fd6f15c146102e257806383d430d5146102dd5780638697d2c2146102d85780638ceab9aa146102d35780639267842a146102ce57806395d89b41146102c9578063a49a1e7d146102c4578063a9059cbb146102bf578063ac9650d8146102ba578063ad3cb1cc146102b5578063b1f0e7c7146102b0578063c6e6f592146102ab578063d505accf146102a6578063d83ad00c146102a1578063dd62ed3e1461029c578063e74b981b14610297578063ee3bd5df14610292578063f04da65b1461028d578063f851a440146102885763f9609f080361000e57612471565b612449565b611723565b612423565b6123f6565b6123b2565b612367565b612152565b612129565b61210f565b6120ca565b612065565b611fc4565b611f72565b611ece565b611cda565b611c82565b611ad7565b611907565b6118e3565b6118a8565b611857565b6117eb565b61175e565b611683565b611669565b611635565b61161a565b6115f6565b61158d565b611308565b611222565b6111fa565b6110ed565b611027565b610899565b610fab565b610f91565b610f57565b610f2b565b610f10565b610ef6565b610a65565b610989565b61096f565b610913565b6108bf565b6107f7565b6107d9565b610713565b61045a565b610429565b6103af565b6001600160a01b0381160361039d57565b5f80fd5b9081608091031261039d5790565b608036600319011261039d576004356103c78161038c565b6044356103d38161038c565b606435906001600160401b03821161039d576020926104016103fc6104179436906004016103a1565b61255a565b61040c823433614645565b5060243590336132a0565b604051908152f35b5f91031261039d57565b3461039d575f36600319011261039d57602060cf5460801c604051908152f35b6001600160801b0381160361039d57565b3461039d57602036600319011261039d5760043561047781610449565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156105f9575f916105ca575b50335f90815261016e602052604090206104f3906124a1565b916001600160801b0361050d84516001600160801b031690565b16156105b857610566836105236105b495612c4b565b61054d6105408461053b84516001600160801b031690565b6124f2565b6001600160801b03168252565b335f90815261016e6020526040902061250b565b61250b565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b6105ec915060203d6020116105f2575b6105e48183610698565b810190612487565b5f6104da565b503d6105da565b612496565b90600182811c9216801561062c575b602083101461061857565b634e487b7160e01b5f52602260045260245ffd5b91607f169161060d565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761066557604052565b610636565b6001600160401b03811161066557604052565b608081019081106001600160401b0382111761066557604052565b90601f801991011681019081106001600160401b0382111761066557604052565b5f5b8381106106ca5750505f910152565b81810151838201526020016106bb565b906020916106f3815180928185528580860191016106b9565b601f01601f1916010190565b9060206107109281815201906106da565b90565b3461039d575f36600319011261039d576040515f8054610732816105fe565b808452906020906001908181169081156107af575060011461076b575b6105b48561075f81870382610698565b604051918291826106ff565b5f80805293505f8051602061570f8339815191525b83851061079c5750505050810160200161075f826105b461074f565b8054868601840152938201938101610780565b8695506105b49693506020925061075f94915060ff191682840152151560051b820101929361074f565b3461039d57602036600319011261039d576020610417600435612534565b3461039d57604036600319011261039d576004356108148161038c565b6001600160a01b038116906024359082156108875761084f8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b3461039d575f36600319011261039d5760206001600160801b0360cf5416604051908152f35b606036600319011261039d576004356108d78161038c565b6024356108e38161038c565b604435906001600160401b03821161039d5760209261090c6103fc6104179436906004016103a1565b3490614645565b3461039d57602036600319011261039d576004356001600160401b03811161039d576103fc6100209136906004016103a1565b606090600319011261039d5760043561095e8161038c565b90602435906044356107108161038c565b3461039d57602061041761098236610946565b91336132a0565b3461039d57606036600319011261039d576004356109a68161038c565b602435906109b38261038c565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610a03575b6109f7846109f285888361481c565b61354b565b60405160018152602090f35b919093818503948511610a37575f9283526002602090815260408085203386529091529092209390935591806109f76109e3565b6124c6565b606090600319011261039d5760043590602435610a588161038c565b906044356107108161038c565b3461039d57610a7336610a3c565b906001600160a01b038083161561088757610a8c613e8d565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561039d5760408051631d8557d760e01b815260049491905f81878183875af180156105f957610edd575b506001600160a01b0383165f90815261016e60205260409020610aff906124a1565b6001600160801b039283610b1a83516001600160801b031690565b1615610ecd57610b2982612c4b565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa9788156105f9575f98610e9c575b50602097888101956001600160401b03918280610ba28a516001600160401b031690565b1614610e8c57908c92918751918c8380610bce6303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156105f957610bfa938e5f94610e67575b5050516001600160801b03165b1690612d7a565b96610c1e610c188a60018060a01b03165f5260d360205260405f2090565b54612534565b928389118015610e57575b610e4757908b610c679392610c4589516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa9182156105f957670de0b6b3a764000094610cb6948e5f95610e1a575b5050610ca8610c9a610cae926129f5565b93516001600160401b031690565b936129f5565b921690612dee565b1015610e0c578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156105f9577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610de995610d6093610dee575b5050610d43610540610d338c6143bf565b83516001600160801b03166124f2565b6001600160a01b0386165f90815261016e6020526040902061250b565b610d698261448c565b90610da8610d8d610d79856143bf565b60cf5460801c5b036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610db28286615185565b610dbc83896143f2565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610e0492903d106105f2576105e48183610698565b505f80610d22565b835163185cfc6d60e11b8152fd5b610cae929550610e3d610ca89282610c9a93903d106105f2576105e48183610698565b959250508e610c89565b875163efda1a2760e01b81528590fd5b50610e606125a1565b8911610c29565b610bf39294509081610e8492903d106105f2576105e48183610698565b92908e610be6565b8651630709133160e01b81528490fd5b610ebf91985060603d606011610ec6575b610eb78183610698565b8101906135df565b965f610b7e565b503d610ead565b825163673f032f60e11b81528790fd5b80610eea610ef09261066a565b8061041f565b5f610add565b3461039d575f36600319011261039d5760206104176125a1565b3461039d575f36600319011261039d57602060405160128152f35b3461039d575f36600319011261039d576020610f456125d7565b6040516001600160a01b039091168152f35b3461039d575f36600319011261039d5760206040517f9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd8152f35b3461039d575f36600319011261039d576020610417612612565b6020610417610fb936610946565b91610fc5833433614645565b50336132a0565b9181601f8401121561039d578235916001600160401b03831161039d576020838186019501011161039d57565b602060031982011261039d57600435906001600160401b03821161039d5761102391600401610fcc565b9091565b61103036610ff9565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c1680156110d9575b6110c7576801000000000000000361108a9368ffffffffffffffffff1916178455612725565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015611064565b3461039d576110fb36610a3c565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105f95782915f916111cb575b501633036111b95781610de961118686867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613639565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6111ed915060203d6020116111f3575b6111e58183610698565b810190612647565b5f61114e565b503d6111db565b3461039d575f36600319011261039d57609c546040516001600160a01b039091168152602090f35b3461039d57602036600319011261039d5760043561123f8161038c565b60018060a01b03165f5261016e602052602060405f20604051906112628261064a565b54906001600160801b03918281169081835260801c8483015261128a575b5116604051908152f35b61129381612c4b565b611280565b6040519060a082018281106001600160401b0382111761066557604052565b6001600160401b03811161066557601f01601f191660200190565b9291926112de826112b7565b916112ec6040519384610698565b82948184528183011161039d578281602093845f960137010152565b60408060031936011261039d5760049081356113238161038c565b6024356001600160401b03811161039d573660238201121561039d5761135290369060248187013591016112d2565b9161135b613c60565b8051926113928461138460209363439fab9160e01b8584015284602484015260448301906106da565b03601f198101865285610698565b61139a613c60565b6113a2613cb9565b6001600160a01b03838116801592919087908415611558575b84156114ea575b8415611487575b505082156113f1575b50506113e2576100208383614b7d565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156105f9575f9261145a575b5050155f806113d2565b6114799250803d10611480575b6114718183610698565b810190612806565b5f80611450565b503d611467565b855163054fd4d560e41b81529294508391839182905afa9081156105f957879160ff915f916114bd575b5016141591865f6113c9565b6114dd9150843d86116114e3575b6114d58183610698565b810190614b68565b5f6114b1565b503d6114cb565b935050835163198ca60560e11b815282818981875afa9081156105f95788917f9480c4a5d7e604111fbc986cd90c895a458ca155fe13c10879b93c4592ce29fd915f9161153b575b501415936113c2565b6115529150853d87116105f2576105e48183610698565b5f611532565b5f8051602061574f833981519152549094508490611586906001600160a01b03165b6001600160a01b031690565b14936113bb565b3461039d575f36600319011261039d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036115e45760206040515f8051602061574f8339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f36600319011261039d576001600160a01b036116116125d7565b1633036111b957005b3461039d575f36600319011261039d57602060405160038152f35b3461039d575f36600319011261039d575f8051602061574f833981519152546040516001600160a01b039091168152602090f35b3461039d575f36600319011261039d5760206104176127eb565b3461039d57602036600319011261039d5760d180549081905f6004355b8482106116d1575050508110156116c6576105b4905b6040519081529081906020820190565b506105b45f196116b6565b909193808316906001818518811c8301809311610a37575f8790525f8051602061578f8339815191528301546001600160a01b0316841015611718575050935b91906116a0565b909591019250611711565b3461039d57602036600319011261039d576004356117408161038c565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461039d575f36600319011261039d57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156105f9576020915f916117ce575b506040519015158152f35b6117e59150823d8411611480576114718183610698565b5f6117c3565b3461039d57602036600319011261039d576004356118088161038c565b611810613cb9565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461039d57608036600319011261039d576105b461188b60043561187a8161038c565b606435906044359060243590612827565b604080519384526020840192909252908201529081906060820190565b3461039d57602036600319011261039d576004356118c58161038c565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461039d575f36600319011261039d57602061ffff609c5460a01c16604051908152f35b3461039d5760031960403682011261039d5760049081356001600160401b0380821161039d5760a082850193833603011261039d5760243590811161039d576119539036908501610fcc565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561039d5760405163837d444160e01b8152905f9082908183816119a68c828f01612909565b03925af180156105f957611ac4575b506119be613e8d565b6119c6612c0a565b9081163314159182611a95575b50509050611a84576044019160b06119eb8484612987565b90500480158015611a6c575b611a5c57611a0c611a066125a1565b916129dc565b11611a4d575060b0611a1e8383612987565b9050145f14611a3a5761002091611a3491612987565b906142ac565b61002091611a4791612987565b90614184565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611a778484612987565b905060b0820214156119f7565b604051634ca8886760e01b81528390fd5b611ab89250611ab2611abc94611aaa88613f18565b9236916112d2565b91613ff3565b1590565b805f806119d3565b80610eea611ad19261066a565b5f6119b5565b3461039d57606036600319011261039d57600435602435611afc604435828433612827565b9192611b287f000000000000000000000000000000000000000000000000000000000000000082612a12565b42108015611c7a575b8015611c72575b611c60577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611b93611b78611b6d866143bf565b60d05460801c6124f2565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611bd79190611bc6608082610698565b5190205f5260d260205260405f2090565b555f9360018311611c10575b50505050611bf182336143f2565b604080519485526020850191909152830152339180606081015b0390a2005b611c5692939450611c219088612a12565b60408051336020820190815291810193909352606083018290529094909190611bc69082608081015b03908101835282610698565b555f808080611be3565b604051630e3d8e8d60e11b8152600490fd5b508215611b38565b508115611b31565b3461039d57604036600319011261039d576020600435611cae602435611ca78161038c565b8233614d6a565b90611cb83361354b565b60405190815230905f8051602061576f833981519152843392a3604051908152f35b3461039d57602036600319011261039d57600435611cf6613e8d565b335f90815261016e60205260409020611d0e906124a1565b6001600160801b0380611d2883516001600160801b031690565b16156105b8578290611d3983612c4b565b82516001600160801b03161610611ebc57335f90815260d3602052604090205482611d7a611d6e84516001600160801b031690565b6001600160801b031690565b14611ea657611d9e9083611d98611d6e85516001600160801b031690565b91612dee565b91611dcb611dbe611dae836143bf565b84516001600160801b0316610d80565b6001600160801b03168352565b335f90815261016e60205260409020611de590839061250b565b611e2d6020611e1e60018060a01b037f000000000000000000000000000000000000000000000000000000000000000016809633614d6a565b9301516001600160801b031690565b833b1561039d5760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105f9576105b492611e93575b506040519081529081906020820190565b80610eea611ea09261066a565b5f611e82565b335f90815261016e602052604081205591611de5565b604051636edcc52360e01b8152600490fd5b3461039d575f36600319011261039d576040515f60018054611eef816105fe565b80855291602091600181169081156107af5750600114611f19576105b48561075f81870382610698565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510611f5f5750505050810160200161075f826105b461074f565b8054868601840152938201938101611f43565b3461039d57611c0b7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611fa436610ff9565b9290611fae613cb9565b60405191829160208352339560208401916128e9565b3461039d57604036600319011261039d57611fee600435611fe48161038c565b602435903361481c565b611ff73361354b565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120375750505050505090565b9091929394958480612055600193603f198682030187528a516106da565b9801930193019194939290612027565b3461039d57602036600319011261039d576001600160401b0360043581811161039d573660238201121561039d57806004013591821161039d573660248360051b8301011161039d576105b49160246120be9201612b5d565b60405191829182612002565b3461039d575f36600319011261039d576105b46040516120e98161064a565b60058152640352e302e360dc1b60208201526040519182916020835260208301906106da565b3461039d575f36600319011261039d576020610f45612c0a565b3461039d57602036600319011261039d57602061041760043561448c565b60ff81160361039d57565b3461039d5760e036600319011261039d5760043561216f8161038c565b60243561217b8161038c565b60443590606435926084359061219082612147565b6001600160a01b0383811695909290861561088757428110612355576020915f91611c4a61228389878a6122466121c5612612565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039161225a601f1993848101835282610698565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa156105f9575f51928284168015908115612348575b5061233657612323859161230e7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610de9565b6040516323389ba560e21b8152600490fd5b905083831614155f6122c9565b604051631ab7da6b60e01b8152600490fd5b3461039d575f36600319011261039d5760206001600160801b0360d05416604051908152f35b604090600319011261039d576004356123a58161038c565b906024356107108161038c565b3461039d5760206123ed6123c53661238d565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b3461039d57602036600319011261039d576100206004356124168161038c565b61241e613cb9565b61451b565b3461039d575f36600319011261039d5760206001600160801b0360d55416604051908152f35b3461039d575f36600319011261039d576037546040516001600160a01b039091168152602090f35b602061041761247f3661238d565b903490614645565b9081602091031261039d575190565b6040513d5f823e3d90fd5b906040516124ae8161064a565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f190191908211610a3757565b6001600160801b039182169082160391908211610a3757565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161254c57505090565b916107109260801c90612dee565b61256661256d91612f54565b91906130ea565b61257357565b61257b614f85565b80612584575b50565b5f906040519081525f8051602061576f83398151915260203092a3565b4760d0546001600160801b036125b8818316612534565b9060d55416019060801c01908181115f146125d1570390565b50505f90565b6101a1546001600160a01b031680156125ed5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f00000000000000000000000000000000000000000000000000000000000000000361263f5760045490565b610710613952565b9081602091031261039d57516107108161038c565b359061ffff8216820361039d57565b9080601f8301121561039d57816020610710933591016112d2565b9060208282031261039d5781356001600160401b039283821161039d57019060a08282031261039d576126b7611298565b92823584526126c86020840161265c565b6020850152604083013581811161039d57826126e591850161266b565b6040850152606083013581811161039d578261270291850161266b565b6060850152608083013590811161039d5761271d920161266b565b608082015290565b6037549091906001600160a01b03166127e1576040519063e7f6f22560e01b82526020928383600481335afa9283156105f9575f936127c2575b50604051636f4fa30f60e01b8152908482600481335afa9182156105f95761279d955f9361279f575b50506127979192810190612686565b91613ba0565b565b612797935090816127bb92903d106111f3576111e58183610698565b915f612788565b6127da919350843d86116111f3576111e58183610698565b915f61275f565b505061279d613a78565b60d4548061071057505f1990565b5190811515820361039d57565b9081602091031261039d57610710906127f9565b91908203918211610a3757565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061286581608081015b03601f198101835282610698565b5190205f5260d260205260405f205491821561289557612886918391613cf2565b9091828103908111610a375792565b5050505f905f905f90565b9035601e198236030181121561039d5701602081359101916001600160401b03821161039d57813603831361039d57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06107109260208152823560208201526020830135604082015261294561293560408501856128a0565b84606085015260c08401916128e9565b9061297861296d61295960608701876128a0565b601f198587038101608087015295916128e9565b9460808101906128a0565b939092828603019101526128e9565b903590601e198136030182121561039d57018035906001600160401b03821161039d5760200191813603831361039d57565b634e487b7160e01b5f52601260045260245ffd5b81156129d7570490565b6129b9565b906801bc16d674ec8000009180830292830403610a3757565b90670de0b6b3a764000091828102928184041490151715610a3757565b91908201809211610a3757565b6001600160401b0381116106655760051b60200190565b90612a4082612a1f565b612a4d6040519182610698565b8281528092612a5e601f1991612a1f565b01905f5b828110612a6e57505050565b806060602080938501015201612a62565b634e487b7160e01b5f52603260045260245ffd5b90821015612aaa576110239160051b810190612987565b612a7f565b908092918237015f815290565b3d15612ae6573d90612acd826112b7565b91612adb6040519384610698565b82523d5f602084013e565b606090565b60208183031261039d578051906001600160401b03821161039d570181601f8201121561039d578051612b1d816112b7565b92612b2b6040519485610698565b8184526020828401011161039d5761071091602080850191016106b9565b8051821015612aaa5760209160051b010190565b919091612b6983612a36565b925f5b818110612b7857505050565b5f80612b85838587612a93565b60409391612b97855180938193612aaf565b0390305af490612ba5612abc565b9115612bcc575090600191612bba8288612b49565b52612bc58187612b49565b5001612b6c565b90604481511061039d57612c06612bf160049283810151602480918301019101612aeb565b925162461bcd60e51b815292839283016106ff565b0390fd5b610109546001600160a01b03168061071057507f000000000000000000000000000000000000000000000000000000000000000090565b612581343361457d565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9575f91612ce1575b5060208201916001600160801b03918284511691828214612cda5783612ccd612cc8612cd5958584865116612dee565b6143bf565b1690526143bf565b169052565b5050505050565b612cfa915060203d6020116105f2576105e48183610698565b5f612c98565b90808202905f1981840990828083109203918083039214612d6f576127109082821115612d5d577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612ddd57670de0b6b3a76400009082821115612d5d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f1984820993838086109503948086039514612e615784831115612d5d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509061071092506129cd565b9081606091031261039d578051916107106040602084015193016127f9565b81835290916001600160fb1b03831161039d5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361039d5760408301526040810135612ee08161038c565b6001600160a01b031660608381019190915281013536829003601e190181121561039d5701602081359101906001600160401b03811161039d578060051b3603821361039d5760a0836080806107109601520191612e8d565b9190915f8382019384129112908015821691151617610a3757565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612f7f9060048301612eb1565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156105f9575f915f905f956130a5575b5084156130525781612fc96125d7565b16917f000000000000000000000000000000000000000000000000000000000000000016821461304b57509060205f92600460405180958193634641257d60e01b83525af19081156105f957613026925f9261302a575b50612f39565b9190565b61304491925060203d6020116105f2576105e48183610698565b905f613020565b9081613058575b50509190565b803b1561039d57604051636ee3193160e11b815260048101929092525f908290602490829084905af180156105f957613092575b80613052565b80610eea61309f9261066a565b5f61308c565b919450506130cb915060603d6060116130d3575b6130c38183610698565b810190612e6e565b93905f612fb9565b503d6130b9565b600160ff1b8114610a37575f0390565b8015612581576130ff611d6e60cf5460801c90565b5f82126131d6578161311091612a12565b9061311d610d8d836143bf565b613132609c549161ffff8360a01c1690612d00565b80156131d157807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613170611d6e60cf546001600160801b031690565b806131bb5750506131b690925b6001600160a01b0316916131918484614f1d565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b6131b6926131cb92039084612dee565b9261317d565b505050565b906131e0906130da565b6131f5611d6e60d5546001600160801b031690565b80613215575b5080613205575050565b612cc8610d8d9161279d9361281a565b9061327c7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916116b661326061325561324e8888612a12565b8785612dee565b8080940396036143bf565b6001600160801b03166001600160801b031960d554161760d555565b0390a15f6131fb565b9190916001600160801b0380809416911601918211610a3757565b93929190916132ad6146f1565b6132b5613e8d565b6001600160a01b0385165f90815261016e602052604090206132d6906124a1565b946001600160801b036132f087516001600160801b031690565b16156134bc576132ff86612c4b565b6001600160a01b0381165f90815260d3602052604090206133289061332390610c18565b614712565b955f19841461348c575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af19586156105f9575f9661346b575b5085986133c46133b76133a7846143bf565b86516001600160801b0316613285565b6001600160801b03168552565b6133d8611d6e85516001600160801b031690565b11613459577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5895613421613454946105618760018060a01b03165f5261016e60205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61348591965060203d6020116105f2576105e48183610698565b945f613395565b92506134a2611d6e84516001600160801b031690565b808711156134b257860392613332565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f95761352791613517915f9161352c575b506143bf565b6001600160801b03166020880152565b6132ff565b613545915060203d6020116105f2576105e48183610698565b5f613511565b60018060a01b0381165f5261016e60205260405f20906040519161356e8361064a565b54906001600160801b03918281169081855260801c6020850152156131d157613323610c186135c19261359f613e8d565b6135a886612c4b565b6001600160a01b03165f90815260d36020526040902090565b9151161161345957565b51906001600160401b038216820361039d57565b9081606091031261039d5760405190606082018281106001600160401b0382111761066557613631916040918252805161361881610449565b8452613626602082016135cb565b6020850152016135cb565b604082015290565b92906001600160a01b03908181161561088757613654613e8d565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561039d57604094855193631d8557d760e01b85526004945f81878183895af180156105f95761393f575b506001600160a01b0388165f90815261016e602052604090206136c7906124a1565b906001600160801b036136e183516001600160801b031690565b161561392f576136f082612c4b565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156105f957613910575b508651936303d1689d60e11b9788865260209182878061376a888c83019190602083019252565b0381845afa9687156105f9575f976138f1575b50869961379d610c188d60018060a01b03165f5260d360205260405f2090565b881180156138e1575b6138d15790836137e3926137c187516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa9889156105f9575f859488946138289c6138b4575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156105f957610d3361386f94613852936105409361279d9a613896575b50506143bf565b6001600160a01b0388165f90815261016e6020526040902061250b565b61389161387b8361448c565b809761388c610d8d610d79876143bf565b615185565b6143f2565b816138ac92903d106105f2576105e48183610698565b505f8061384b565b6138ca90873d89116105f2576105e48183610698565b505f6137fd565b825163efda1a2760e01b81528990fd5b506138ea6125a1565b88116137a6565b613909919750833d85116105f2576105e48183610698565b955f61377d565b6139289060603d606011610ec657610eb78183610698565b505f613743565b875163673f032f60e11b81528690fd5b80610eea61394c9261066a565b5f6136a5565b6040515f905f5490613963826105fe565b9283825260209384830193600190866001821691825f14613a58575050600114613a15575b5050918161399e613a0f93612857950382610698565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f8051602061570f8339815191525b828410613a43575050508201018161399e613988565b80548685018601528794909301928101613a2d565b60ff1916875292151560051b8501909201925083915061399e9050613988565b613a806148ba565b613a95611d6e60d0546001600160801b031690565b60018111613b8e57600114613b09575b60d654613ab0615385565b90808210613acc575b5050613ac45f60d655565b61279d614898565b5f8051602061572f83398151915291613aff9103613ae9816152b0565b604080519182525f602083015290918291820190565b0390a15f80613ab9565b613b42613b26613b2160cf546001600160801b031690565b6124da565b6001600160801b03166001600160801b031960cf54161760cf55565b613b576001600160801b031960d0541660d055565b613b5f61524e565b5f8051602061572f83398151915260405180613b8681905f60206040840193600181520152565b0390a1613aa5565b604051630299325160e41b8152600490fd5b9190613baa6148ba565b608082015190613bb86148ba565b6001600160a01b038416801561088757613c5894613c4893613c31926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613c1f339460208301906106da565b0390a2602085015161ffff16906148fb565b613c3b835161494c565b613c4361497c565b6149a9565b60606040820151910151906149d8565b61279d614b05565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613c9e575b50506115e457565b5f8051602061574f8339815191525416141590505f80613c96565b6037546001600160a01b031633036111b957565b90604051613cda8161064a565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590613e85575b613e785783613e42575f5b60d15f526001600160a01b0316613d375f8051602061578f8339815191528601613ccd565b8051909790613d4e906001600160a01b031661157a565b98613d73613d676020809b01516001600160601b031690565b6001600160601b031690565b948381108015613e38575b613e265791600193979a95613d9d613da9939488035b838c0390614c28565b80920198870391612dee565b01970193808611801590613e1c575b613e115760d15f528290613dda5f8051602061578f8339815191528701613ccd565b805190890151969992966001600160a01b039091169460019392613da99290916001600160601b0390911690613d9d908803613d94565b945050509250509190565b5081851015613db8565b60405163e8722f8f60e01b8152600490fd5b50808b1115613d7e565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316613d12565b505093505050505f905f90565b508415613d07565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9575f91613ef9575b50613ee757565b60405163e775715160e01b8152600490fd5b613f12915060203d602011611480576114718183610698565b5f613ee0565b604290467f000000000000000000000000000000000000000000000000000000000000000003613fc75761010a54905b613f5f613f586040830183612987565b36916112d2565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613faa8161067d565b5190206040519161190160f01b8352600283015260228201522090565b613fcf614c3a565b90613f48565b60041115613fdf57565b634e487b7160e01b5f52602160045260245ffd5b613ffd8383614d07565b5061400a81959295613fd5565b1593846140a6575b508315614020575b50505090565b5f929350908291604051614058816128576020820194630b135d3f60e11b998a875260248401526040604484015260648301906106da565b51915afa90614065612abc565b82614098575b8261407b575b50505f808061401a565b61409091925060208082518301019101612487565b145f80614071565b91506020825110159161406b565b6001600160a01b0383811691161493505f614012565b9060301161039d5790603090565b9060901161039d5760300190606090565b9060b01161039d5760900190602090565b9093929384831161039d57841161039d578101920390565b359060208110614112575090565b5f199060200360031b1b1690565b9695949061415d9361414161414f926060979560808c5260808c01916128e9565b9089820360208b01526106da565b9187830360408901526128e9565b930152565b9060206107109281815201906128d1565b9160206107109381815201916128e9565b60b091828104915f9081614196614d41565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b8784106141d857505050505050505050565b826141e79101809288876140ec565b906141f282826140bc565b9161421161420b61420386846140ca565b9690936140db565b90614104565b90893b1561039d575f908d61423e604094855198899485946304512a2360e31b86528a8a60048801614120565b03816801bc16d674ec8000008d5af19081156105f9577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19461428a92614299575b505192839283614173565b0390a1600181930192906141c6565b80610eea6142a69261066a565b5f61427f565b8160301161039d5761420b917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166142ea614d41565b906143016142f884866140ca565b969094866140db565b94813b1561039d576801bc16d674ec8000005f9461436797604051988996879586946304512a2360e31b8652608060048701526143586143458d60848901906128d1565b60031994858983030160248a01526106da565b928684030160448701526128e9565b90606483015203925af19081156105f9577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926131b6926143b0575b5060405191829182614162565b6143b99061066a565b5f6143a3565b6001600160801b03908181116143d3571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0091600283541461447a5760028355814710614462575f918291829182916001600160a01b03165af1614444612abc565b50156144505760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b038216811580156144bb575b156144ae5750905090565b6107109260801c91612dee565b5080156144a3565b60cf546001600160801b0381169082158015614513575b156144e457505090565b60801c906144f3828285612dee565b9282156129d757096145025790565b6001810180911115610710576124c6565b5081156144da565b614523613e8d565b6001600160a01b0316801561456b57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190614587613e8d565b6001600160a01b03831690811561088757801561463357806145ae611d6e60cf5460801c90565b01936145b86127eb565b851161462157610d8d946145df916145da6145d2856144c3565b9788936143bf565b614f1d565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192614651613e8d565b6001600160a01b0382169182156108875781156146335781614678611d6e60cf5460801c90565b016146816127eb565b811161462157610d8d956146c861461c927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c946145da6146c0886144c3565b9a8b936143bf565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b6146f9615116565b1561470057565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156105f9576147ad936001600160401b03610bf3604061478c946020975f916147fd575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156105f9575f916147e4575090565b610710915060203d6020116105f2576105e48183610698565b614816915060603d606011610ec657610eb78183610698565b5f61477d565b6001600160a01b0390811691908215801561488e575b61088757825f5260d360205260405f2090815492858403938411610a37575f8051602061576f833981519152936020935561487d8160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614832565b6148a06148ba565b6148a8614c3a565b61010a805482036148b7575050565b55565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156148e957565b604051631afcd79f60e31b8152600490fd5b6149036148ba565b61271061ffff83161161493a576149199061451b565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b6149546148ba565b801561496a57600181016149655750565b60d455565b6040516331278a8760e01b8152600490fd5b6149846148ba565b6801bc16d674ec8000006149966127eb565b1061496a576149a3614c3a565b61010a55565b6149b16148ba565b6001600160a01b0316806149c25750565b6101a180546001600160a01b0319169091179055565b6149e06148ba565b601e8151118015614afa575b614ae8576149f86148ba565b8051906001600160401b03821161066557614a1c82614a175f546105fe565b6153c7565b602090816001601f851114614a7457509180614a5292614a5995945f92614a69575b50508160011b915f199060031b1c19161790565b5f55615491565b61279d614a64613952565b600455565b015190505f80614a3e565b5f80529190601f1984165f8051602061570f833981519152935f905b828210614ad0575050916001939185614a5997969410614ab8575b505050811b015f55615491565b01515f1960f88460031b161c191690555f8080614aab565b80600186978294978701518155019601940190614a90565b604051632d3f993760e21b8152600490fd5b50600a8251116149ec565b614b0d6148ba565b614b156148ba565b614b1d6148ba565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614b5657612581343061457d565b60405163ea2559bb60e01b8152600490fd5b9081602091031261039d575161071081612147565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614c07575b50614bcd57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f8051602061574f8339815191528403614bee5761279d92935061556f565b604051632a87526960e21b815260048101859052602490fd5b614c2191955060203d6020116105f2576105e48183610698565b935f614ba7565b9080821015614c35575090565b905090565b6e5661756c7456616c696461746f727360881b6020604051614c5b8161064a565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176106655760405251902090565b8151919060418303614d3757614d309250602082015190606060408401519301515f1a90615611565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c820152602081526107108161064a565b9291908015611ebc576001600160a01b0382811692831561088757614d90611ab8615116565b614e995790611bc695614e7d614e61857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f9581614e36614ddb611d6e60d0546001600160801b031690565b92612857614e0885614e03614dee615385565b614dfd611d6e60d55460801c90565b90612a12565b612a12565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f90815260d360205260409020614e5983825461281a565b9055016143bf565b6001600160801b03166001600160801b031960d054161760d055565b604080518881526020810195909552911692908190810161461c565b929394614ea583612534565b938415614633577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea8348093614efa86614f1593614ef0610d8d614ee5846143bf565b60cf5460801c6124f2565b6138918487615185565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b5f8051602061576f83398151915260205f92614f38856143bf565b60cf5490614f506001600160801b0391828416613285565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b614f9e47614f98611d6e60d05460801c90565b9061281a565b9081156151115760d5546001600160801b0381169081615099575b5050614fd0611d6e60d0546001600160801b031690565b9182158015615091575b61508b57614ff190614feb84612534565b90614c28565b801561508b576150008161448c565b92831561508457614ee561279d92615021614e61612cc888610d8d9661281a565b61503b611b78615030836143bf565b60d05460801c613285565b61504581876152fb565b60408051878152602081018390525f8051602061572f8339815191529190a1612cc8613b26615073886143bf565b60cf546001600160801b03166124f2565b505f925050565b505f9150565b508015614fda565b818492941061508457615030846150e1935f8051602061572f83398151915282611b789560801c6150ca82826152fb565b604080519182526020820192909252a103946143bf565b6150f56001600160801b0360d5541660d555565b61510a6001600160801b031960d5541660d555565b5f80614fb9565b5f9150565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9575f9161516c575090565b610710915060203d602011611480576114718183610698565b6001600160a01b03165f81815260d360205260409020805483810391908211610a37575f935f8051602061576f83398151915292602092556151c6816143bf565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b60d154906801000000000000000082101561066557600182018060d155821015612aaa5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f8051602061578f83398151915290910155565b615256615385565b60018101809111610a37576001600160a01b03808211615290579061279d91604051916152828361064a565b1681525f60208201526151f0565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b80156152e9576152be615385565b908101809111610a37576001600160a01b03808211615290579061279d91604051916152828361064a565b604051632ec8835b60e21b8152600490fd5b91909180156152e95761530c615385565b908101809111610a37576001600160a01b03808211615290576001600160601b0390818511615365579061279d9394615360926040519461534c8661064a565b168452166001600160601b03166020830152565b6151f0565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60d1548061539257505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b031661157a565b601f81116153d3575050565b5f80525f8051602061570f833981519152906020601f840160051c83019310615416575b601f0160051c01905b81811061540b575050565b5f8155600101615400565b90915081906153f7565b90601f821161542d575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c83019310615487575b601f0160051c01905b81811061547d57505050565b5f81558201615471565b9091508190615468565b9081516001600160401b038111610665576001906154b8816154b384546105fe565b615420565b602080601f83116001146154ed575081906154e99394955f92614a695750508160011b915f199060031b1c19161790565b9055565b90601f1983169561551f60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b8882106155585750508385969710615540575b505050811b019055565b01515f1960f88460031b161c191690555f8080615536565b808785968294968601518155019501930190615523565b90813b156155f0575f8051602061574f83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156155d557612581916156a5565b5050346155de57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161569a579061566a6020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156105f9575f516001600160a01b0381161561569057905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061071093602081519101845af46156bc612abc565b91906156d2575080511561445057805190602001fd5b81511580615705575b6156e3575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156156db56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a2646970667358221220f7de8f37e59c06617071431d53b35ed8f081bb59d4820f5cd0ae3e7f09be091864736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthGenesisVault.json b/test/shared/artifacts/EthGenesisVault.json deleted file mode 100644 index 25f2f904..00000000 --- a/test/shared/artifacts/EthGenesisVault.json +++ /dev/null @@ -1,1751 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthGenesisVault", - "sourceName": "contracts/vaults/ethereum/EthGenesisVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "poolEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "rewardEthToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialHarvest", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "capacity", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "GenesisVaultCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Migrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "acceptPoolEscrowOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "migrate", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61022034620002f657601f6200585238819003918201601f19168301926001600160401b039290919083851183861017620002fa578083926040968752833961016092839181010312620002f657620000d793620000e59362000062836200030e565b9162000071602085016200030e565b946200007f8286016200030e565b946200008e606082016200030e565b926200009d608083016200030e565b93620000ac60a084016200030e565b95620000bb60c085016200030e565b97620000ca60e086016200030e565b6101009d8e87016200030e565b9a6101209d8e88016200030e565b9c610140809801519360805260a05260c0523060e0528d52468c52845260018060a01b0380921685528161018096168652816101a0971687526101c09788527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82861c16620002e5578080831603620002a0575b505050806101e09816885261020098168852519761552e998a620003248b396080518a8181611428015281816115c00152818161213401528181612dfc01528181613eec015261524c015260a0518a6110f5015260c0518a818161411e0152614247015260e0518a81816112740152613cc201525189612a6401525188613f62015251876117660152518681816104140152818161072001528181612ad70152818161340001528181613568015281816136a1015281816137f7015281816138d601526145aa0152518581816107df01528181610db001528181613995015261452e01525184611a3001525183818161235e0152612e4401525182818161066e01528181611e3601528181612210015281816122e501528181612a88015281816131670152614eed015251818181611cea015281816121ad0152612f9e0152f35b6001600160401b0319909116811790915582519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200015f565b845163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002f65756fe60806040526004361015610022575b3615610018575f80fd5b610020612a86565b005b5f3560e01c806301d523b6146102f157806301e1d114146102ec578063066055e0146102e757806307a2d13a146102e257806318f72950146102dd5780631a7ff553146102d8578063201b9eb5146102d357806323d18ed8146102ce5780632999ad3f146102c95780632cdf7401146102c45780633229fa95146102bf57806333194c0a146102ba57806336fe59d2146102b55780633a98ef39146102b0578063439fab91146102ab57806343e82a79146102a657806346904840146102a15780634ec96b221461029c5780634f1ef2861461029757806352d1902d1461029257806353156f281461028d57806354fd4d50146102885780635c60da1b146102835780635cfc1a511461027e57806360d60e6e1461027957806372b410a814610274578063754c38881461026f57806376b58b901461026a5780637fd6f15c1461026557806383d430d5146102605780638697d2c21461025b5780638ceab9aa146102565780639267842a14610251578063a49a1e7d1461024c578063ac9650d814610247578063ad3cb1cc14610242578063ad68ebf71461023d578063b1f0e7c714610238578063c6e6f59214610233578063d83ad00c1461022e578063e74b981b14610229578063ee3bd5df14610224578063f04da65b1461021f578063f851a4401461021a5763f9609f080361000e57611fa4565b611f7d565b611f42565b611f1c565b611eef565b611ec9565b611eab565b611e91565b611cbe565b611c79565b611c03565b611b08565b611914565b6118e0565b61173a565b61156a565b611546565b6114f5565b61148a565b6113fd565b611358565b61133e565b61130a565b6112ef565b6112cb565b611262565b610fdd565b610eb6565b610e8e565b610d81565b610cbb565b610c3a565b610c19565b610bdf565b610bb3565b610b99565b6106f6565b610653565b610639565b6105da565b610586565b610568565b6103c4565b610393565b610319565b6001600160a01b0381160361030757565b5f80fd5b908160809103126103075790565b608036600319011261030757600435610331816102f6565b60443561033d816102f6565b606435906001600160401b0382116103075760209261036b61036661038194369060040161030b565b61210d565b6103768234336147e0565b5060243590336135e2565b604051908152f35b5f91031261030757565b34610307575f36600319011261030757602060985460801c604051908152f35b6001600160801b0381160361030757565b34610307576020366003190112610307576004356103e1816103b3565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610563575f91610534575b50335f9081526101376020526040902061045d90611fe8565b916001600160801b0361047784516001600160801b031690565b1615610522576104d08361048d61051e95612ac2565b6104b76104aa846104a584516001600160801b031690565b612039565b6001600160801b03168252565b335f90815261013760205260409020612052565b612052565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610556915060203d60201161055c575b61054e8183610f6b565b810190611fce565b5f610444565b503d610544565b611fdd565b34610307576020366003190112610307576020610381600435612084565b60603660031901126103075760043561059e816102f6565b6024356105aa816102f6565b604435906001600160401b038211610307576020926105d361036661038194369060040161030b565b34906147e0565b34610307576020366003190112610307576004356001600160401b0381116103075761036661002091369060040161030b565b606090600319011261030757600435610625816102f6565b9060243590604435610636816102f6565b90565b3461030757602061038161064c3661060d565b91336135e2565b34610307575f806003193601126103075761066c613851565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610307575f809160046040518094819363b4b6d74f60e01b83525af18015610563576106c3575080f35b6100209150610f02565b606090600319011261030757600435906024356106e9816102f6565b90604435610636816102f6565b3461030757610704366106cd565b906001600160a01b0380831615610b875761071d613ed1565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103075760408051631d8557d760e01b815260049491905f81878183875af1801561056357610b6e575b506001600160a01b0383165f9081526101376020526040902061079090611fe8565b6001600160801b0392836107ab83516001600160801b031690565b1615610b5e576107ba82612ac2565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610563575f98610b2d575b50602097888101956001600160401b039182806108338a516001600160401b031690565b1614610b1d57908c92918751918c838061085f6303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156105635761088b938e5f94610af8575b5050516001600160801b03165b1690612b77565b966108af6108a98a60018060a01b03165f52609c60205260405f2090565b54612084565b928389118015610ae8575b610ad857908b6108f893926108d689516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561056357670de0b6b3a764000094610947948e5f95610aab575b505061093961092b61093f92612820565b93516001600160401b031690565b93612820565b921690612c65565b1015610a9d578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610563577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610a7a956109f193610a7f575b50506109d46104aa6109c48c61434c565b83516001600160801b0316612039565b6001600160a01b0386165f90815261013760205260409020612052565b6109fa82614627565b90610a39610a1e610a0a8561434c565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610a438286614bb7565b610a4d838961437f565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610a9592903d1061055c5761054e8183610f6b565b505f806109b3565b835163185cfc6d60e11b8152fd5b61093f929550610ace610939928261092b93903d1061055c5761054e8183610f6b565b959250508e61091a565b875163efda1a2760e01b81528590fd5b50610af16122e3565b89116108ba565b6108849294509081610b1592903d1061055c5761054e8183610f6b565b92908e610877565b8651630709133160e01b81528490fd5b610b5091985060603d606011610b57575b610b488183610f6b565b810190613878565b965f61080f565b503d610b3e565b825163673f032f60e11b81528790fd5b80610b7b610b8192610f02565b80610389565b5f61076e565b60405163d92e233d60e01b8152600490fd5b34610307575f3660031901126103075760206103816122e3565b34610307575f366003190112610307576020610bcd612345565b6040516001600160a01b039091168152f35b34610307575f3660031901126103075760206040517f11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c5058152f35b6020610381610c273661060d565b91610c338334336147e0565b50336135e2565b34610307575f3660031901126103075760206001600160801b0360985416604051908152f35b9181601f84011215610307578235916001600160401b038311610307576020838186019501011161030757565b602060031982011261030757600435906001600160401b03821161030757610cb791600401610c60565b9091565b610cc436610c8d565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610d6d575b610d5b5768010000000000000003610d1e9368ffffffffffffffffff191617845561243f565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610cf8565b3461030757610d8f366106cd565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105635782915f91610e5f575b50163303610e4d5781610a7a610e1a86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966138b8565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610e81915060203d602011610e87575b610e798183610f6b565b8101906120f8565b5f610de2565b503d610e6f565b34610307575f366003190112610307576065546040516001600160a01b039091168152602090f35b34610307576020366003190112610307576020610edd600435610ed8816102f6565b6125e5565b6001600160801b0360405191168152f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111610f1557604052565b610eee565b604081019081106001600160401b03821117610f1557604052565b606081019081106001600160401b03821117610f1557604052565b608081019081106001600160401b03821117610f1557604052565b90601f801991011681019081106001600160401b03821117610f1557604052565b6001600160401b038111610f1557601f01601f191660200190565b929192610fb382610f8c565b91610fc16040519384610f6b565b829481845281830111610307578281602093845f960137010152565b604080600319360112610307576004908135610ff8816102f6565b6024356001600160401b0381116103075736602382011215610307576110279036906024818701359101610fa7565b91611030613cb8565b8051926110678461105960209363439fab9160e01b858401528460248401526044830190611b7b565b03601f198101865285610f6b565b61106f613cb8565b611077613851565b6001600160a01b0383811680159291908790841561122d575b84156111bf575b841561115c575b505082156110c6575b50506110b7576100208383614d39565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610563575f9261112f575b5050155f806110a7565b61114e9250803d10611155575b6111468183610f6b565b8101906120b7565b5f80611125565b503d61113c565b855163054fd4d560e41b81529294508391839182905afa90811561056357879160ff915f91611192575b5016141591865f61109e565b6111b29150843d86116111b8575b6111aa8183610f6b565b810190614d20565b5f611186565b503d6111a0565b935050835163198ca60560e11b815282818981875afa9081156105635788917f11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505915f91611210575b50141593611097565b6112279150853d871161055c5761054e8183610f6b565b5f611207565b5f805160206154d983398151915254909450849061125b906001600160a01b03165b6001600160a01b031690565b1493611090565b34610307575f366003190112610307577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036112b95760206040515f805160206154d98339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112610307576001600160a01b036112e6612345565b163303610e4d57005b34610307575f36600319011261030757602060405160038152f35b34610307575f366003190112610307575f805160206154d9833981519152546040516001600160a01b039091168152602090f35b34610307575f366003190112610307576020610381612637565b3461030757602036600319011261030757609a80549081905f6004355b8482106113a65750505081101561139b5761051e905b6040519081529081906020820190565b5061051e5f1961138b565b909193808316906001818518811c83018093116113f8575f8790525f805160206154998339815191528301546001600160a01b03168410156113ed575050935b9190611375565b9095910192506113e6565b61200d565b34610307575f36600319011261030757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610563576020915f9161146d575b506040519015158152f35b6114849150823d8411611155576111468183610f6b565b5f611462565b34610307576020366003190112610307576004356114a7816102f6565b6114af613851565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103075760803660031901126103075761051e611529600435611518816102f6565b606435906044359060243590612652565b604080519384526020840192909252908201529081906060820190565b34610307575f36600319011261030757602061ffff60655460a01c16604051908152f35b34610307576003196040368201126103075760049081356001600160401b038082116103075760a082850193833603011261030757602435908111610307576115b69036908501610c60565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103075760405163837d444160e01b8152905f9082908183816116098c828f01612734565b03925af1801561056357611727575b50611621613ed1565b611629612a50565b90811633141591826116f8575b505090506116e7576044019160b061164e84846127b2565b905004801580156116cf575b6116bf5761166f6116696122e3565b91612807565b116116b0575060b061168183836127b2565b9050145f1461169d5761002091611697916127b2565b90614231565b610020916116aa916127b2565b906140ff565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506116da84846127b2565b905060b08202141561165a565b604051634ca8886760e01b81528390fd5b61171b925061171561171f9461170d88613f5c565b923691610fa7565b91614036565b1590565b805f80611636565b80610b7b61173492610f02565b5f611618565b346103075760603660031901126103075760043560243561175f604435828433612652565b919261178b7f00000000000000000000000000000000000000000000000000000000000000008261283d565b421080156118d8575b80156118d0575b6118be577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936117f66117db6117d08661434c565b60995460801c612039565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f9161183a9190611829608082610f6b565b5190205f52609b60205260405f2090565b555f9360018311611873575b50505050611854823361437f565b604080519485526020850191909152830152339180606081015b0390a2005b6118b492939450611884908861283d565b60408051336020820190815291810193909352606083018290526080958601835290949091906118299082610f6b565b555f808080611846565b604051630e3d8e8d60e11b8152600490fd5b50821561179b565b508115611794565b3461030757604036600319011261030757602061190b602435611902816102f6565b600435336150aa565b6103813361502a565b3461030757602036600319011261030757600435611930613ed1565b335f9081526101376020526040902061194890611fe8565b6001600160801b038061196283516001600160801b031690565b161561052257829061197383612ac2565b82516001600160801b03161610611af657335f908152609c6020526040902054826119b46119a884516001600160801b031690565b6001600160801b031690565b14611ae0576119d890836119d26119a885516001600160801b031690565b91612c65565b91611a056119f86119e88361434c565b84516001600160801b0316610a11565b6001600160801b03168352565b335f90815261013760205260409020611a1f908390612052565b611a676020611a5860018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336150aa565b9301516001600160801b031690565b833b156103075760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105635761051e92611acd575b506040519081529081906020820190565b80610b7b611ada92610f02565b5f611abc565b335f908152610137602052604081205591611a1f565b604051636edcc52360e01b8152600490fd5b346103075761186e7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611b3a36610c8d565b9290611b44613851565b6040519182916020835233956020840191612714565b5f5b838110611b6b5750505f910152565b8181015183820152602001611b5c565b90602091611b9481518092818552858086019101611b5a565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611bd55750505050505090565b9091929394958480611bf3600193603f198682030187528a51611b7b565b9801930193019194939290611bc5565b34610307576020366003190112610307576001600160401b036004358181116103075736602382011215610307578060040135918211610307573660248360051b830101116103075761051e916024611c5c9201612988565b60405191829182611ba0565b906020610636928181520190611b7b565b34610307575f3660031901126103075761051e604051611c9881610f1a565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611b7b565b346103075760408060031936011261030757600435611cdc816102f6565b6024356001600160a01b03337f0000000000000000000000000000000000000000000000000000000000000000821614801590611e21575b611e1057611d2061444f565b611d28613ed1565b821615611dff578015611dee57917fd083678824038160bef3975359ab29f19c3f0e9bcf9d7ead540a492d4d678b6383611d6461051e95614627565b93611d7f610a1e611d748461434c565b60985460801c612a35565b611d898582614470565b611da4611d95826144bc565b611d9e8461450b565b90614615565b80611ddc575b5083516001600160a01b03919091168152602081019190915260408101849052606090a1519081529081906020820190565b611de7908280613340565b505f611daa565b82516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8351634ca8886760e01b8152600490fd5b508351638da5cb5b60e01b81526020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610563575f91611e72575b508116301415611d14565b611e8b915060203d602011610e8757610e798183610f6b565b5f611e67565b34610307575f366003190112610307576020610bcd612a50565b34610307576020366003190112610307576020610381600435614627565b34610307575f3660031901126103075760206001600160801b0360995416604051908152f35b3461030757602036600319011261030757610020600435611f0f816102f6565b611f17613851565b6146b6565b34610307575f3660031901126103075760206001600160801b03609e5416604051908152f35b3461030757602036600319011261030757600435611f5f816102f6565b60018060a01b03165f52609c602052602060405f2054604051908152f35b34610307575f366003190112610307575f546040516001600160a01b039091168152602090f35b6040366003190112610307576020610381600435611fc1816102f6565b602435906105d3826102f6565b90816020910312610307575190565b6040513d5f823e3d90fd5b90604051611ff581610f1a565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f1901919082116113f857565b6001600160801b0391821690821603919082116113f857565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b038116908161209c57505090565b916106369260801c90612c65565b5190811515820361030757565b9081602091031261030757610636906120aa565b908160209103126103075751610636816103b3565b81810392915f1380158285131691841216176113f857565b908160209103126103075751610636816102f6565b604051630156a69560e11b81523060048201526020916001600160a01b03919083826024817f000000000000000000000000000000000000000000000000000000000000000087165afa918215610563575f926122c0575b5061216f90612dcb565b9390809215612196575b50506121859150612f8a565b61218b57565b612193613162565b50565b60405163070aab0d60e11b815291925082826004817f000000000000000000000000000000000000000000000000000000000000000088165afa8015610563576001600160801b036121f4916121fa945f91612293575b5016612f51565b906120e0565b91604051638da5cb5b60e01b81528281600481857f0000000000000000000000000000000000000000000000000000000000000000165afa928315610563575f93612274575b505016301480159061226b575b61225957805f80612179565b60405163c284f82560e01b8152600490fd5b505f811261224d565b61228b929350803d10610e8757610e798183610f6b565b905f80612240565b6122b39150863d88116122b9575b6122ab8183610f6b565b8101906120cb565b5f6121ed565b503d6122a1565b61216f9192506122dc90853d8711611155576111468183610f6b565b9190612165565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163147016099546001600160801b03612326818316612084565b90609e5416019060801c01908181115f1461233f570390565b50505f90565b61016a546001600160a01b0316801561235b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b919091604081840312610307578035612398816102f6565b9260208201356001600160401b039283821161030757019160608383031261030757604051926123c784610f35565b80358452602081013561ffff81168103610307576020850152604081013591821161030757019080601f830112156103075781602061240893359101610fa7565b604082015290565b90610636949360809361ffff9260018060a01b0316845260208401521660408201528160608201520190611b7b565b5f5490916001600160a01b039182166124b85782612480917f6efc3c5ea2064c46840711aa5ff8d7f70826faa0cc04fcf0557a3863533aafad940190612380565b911661248c8282613bd1565b6124b382519260406124a3602083015161ffff1690565b9101519060405194859485612410565b0390a1565b5050506124c3614c25565b6124d86119a86099546001600160801b031690565b600181116125d35760011461254e575b609f546124f36152a0565b90808210612511575b50506125075f609f55565b61250f614c04565b565b5f805160206154b983398151915291612544910361252e81614ae2565b604080519182525f602083015290918291820190565b0390a15f806124fc565b61258761256b6125666098546001600160801b031690565b612021565b6001600160801b03166001600160801b03196098541617609855565b61259c6001600160801b031960995416609955565b6125a4614a80565b5f805160206154b9833981519152604051806125cb81905f60206040840193600181520152565b0390a16124e8565b604051630299325160e41b8152600490fd5b60018060a01b03165f5261013760205260405f206040519061260682610f1a565b54906001600160801b03918281169081835260801c602083015261262957511690565b61263281612ac2565b511690565b609d548061063657505f1990565b919082039182116113f857565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061269081608081015b03601f198101835282610f6b565b5190205f52609b60205260405f20549182156126c0576126b1918391613d36565b90918281039081116113f85792565b5050505f905f905f90565b9035601e19823603018112156103075701602081359101916001600160401b03821161030757813603831361030757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06106369260208152823560208201526020830135604082015261277061276060408501856126cb565b84606085015260c0840191612714565b906127a361279861278460608701876126cb565b601f19858703810160808701529591612714565b9460808101906126cb565b93909282860301910152612714565b903590601e198136030182121561030757018035906001600160401b0382116103075760200191813603831361030757565b634e487b7160e01b5f52601260045260245ffd5b8115612802570490565b6127e4565b906801bc16d674ec80000091808302928304036113f857565b90670de0b6b3a7640000918281029281840414901517156113f857565b919082018092116113f857565b6001600160401b038111610f155760051b60200190565b9061286b8261284a565b6128786040519182610f6b565b8281528092612889601f199161284a565b01905f5b82811061289957505050565b80606060208093850101520161288d565b634e487b7160e01b5f52603260045260245ffd5b908210156128d557610cb79160051b8101906127b2565b6128aa565b908092918237015f815290565b3d15612911573d906128f882610f8c565b916129066040519384610f6b565b82523d5f602084013e565b606090565b602081830312610307578051906001600160401b038211610307570181601f8201121561030757805161294881610f8c565b926129566040519485610f6b565b81845260208284010111610307576106369160208085019101611b5a565b80518210156128d55760209160051b010190565b91909161299483612861565b925f5b8181106129a357505050565b5f806129b08385876128be565b604093916129c28551809381936128da565b0390305af4906129d06128e7565b91156129f75750906001916129e58288612974565b526129f08187612974565b5001612997565b90604481511061030757612a31612a1c60049283810151602480918301019101612916565b925162461bcd60e51b81529283928301611c68565b0390fd5b9190916001600160801b03808094169116019182116113f857565b60d2546001600160a01b03168061063657507f000000000000000000000000000000000000000000000000000000000000000090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612ab857565b6121933433614718565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563575f91612b58575b5060208201916001600160801b03918284511691828214612b515783612b44612b3f612b4c958584865116612c65565b61434c565b16905261434c565b169052565b5050505050565b612b71915060203d60201161055c5761054e8183610f6b565b5f612b0f565b90808202905f1981840990828083109203918083039214612bec57670de0b6b3a76400009082821115612bda577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a764000091500490565b90808202905f1981840990828083109203918083039214612c5a576127109082821115612bda577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b505061271091500490565b9091828202915f1984820993838086109503948086039514612cd85784831115612bda57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509061063692506127f8565b90816060910312610307578051916106366040602084015193016120aa565b81835290916001600160fb1b0383116103075760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036103075760408301526040810135612d57816102f6565b6001600160a01b031660608381019190915281013536829003601e19018112156103075701602081359101906001600160401b038111610307578060051b360382136103075760a0836080806106369601520191612d04565b9190915f83820193841291129080158216911516176113f857565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612df69060048301612d28565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610563575f915f905f95612f1c575b508415612ec95781612e40612345565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612ec257509060205f92600460405180958193634641257d60e01b83525af190811561056357612e9d925f92612ea1575b50612db0565b9190565b612ebb91925060203d60201161055c5761054e8183610f6b565b905f612e97565b9081612ecf575b50509190565b803b1561030757604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561056357612f09575b80612ec9565b80610b7b612f1692610f02565b5f612f03565b91945050612f42915060603d606011612f4a575b612f3a8183610f6b565b810190612ce5565b93905f612e30565b503d612f30565b6001600160ff1b038111612f625790565b6024906040519063123baf0360e11b82526004820152fd5b600160ff1b81146113f8575f0390565b8015612193576040516278744560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691906020908181600481875afa908115610563575f91613145575b50604051631cd5ec3960e31b8152908282600481885afa91821561056357613011935f93613126575b5050612645565b801561311b5761302f8161302a6119a860985460801c90565b61283d565b905f8312156130b7576130539161304e9161304985612f7a565b612c65565b612f51565b61305c81612f7a565b92803b156103075760405163304f0a6b60e21b815260048101949094525f908490602490829084905af19182156105635761250f9361309f936130a45750612db0565b61488c565b80610b7b6130b192610f02565b5f612e97565b6130c59161304e9184612c65565b823b156103075760405163304f0a6b60e21b815260048101829052925f908490602490829084905af19182156105635761250f9361309f93613108575b506120e0565b80610b7b61311592610f02565b5f613102565b5061250f915061488c565b61313d929350803d1061055c5761054e8183610f6b565b905f8061300a565b61315c9150823d841161055c5761054e8183610f6b565b5f612fe1565b6131a77f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163147016131a16119a860995460801c90565b90612645565b90811561333b57609e546001600160801b03811690816132c3575b50506131d96119a86099546001600160801b031690565b91821580156132bb575b6132b5576131f490611d9e84612084565b80156132b55761320381614627565b9283156132ae576132a361250f92613240613224612b3f88610a1e96612645565b6001600160801b03166001600160801b03196099541617609955565b61325a6117db61324f8361434c565b60995460801c612a35565b6132648187614b2d565b60408051878152602081018390525f805160206154b98339815191529190a1612b3f61256b6132928861434c565b6098546001600160801b0316612039565b60985460801c612039565b505f925050565b505f9150565b5080156131e3565b81849294106132ae5761324f8461330b935f805160206154b9833981519152826117db9560801c6132f48282614b2d565b604080519182526020820192909252a1039461434c565b61331f6001600160801b03609e5416609e55565b6133346001600160801b0319609e5416609e55565b5f806131c2565b5f9150565b929161334a61444f565b613352613ed1565b6001600160a01b0384165f9081526101376020526040902061337390611fe8565b6001600160801b0361338c82516001600160801b031690565b16156135535761339b81612ac2565b6001600160a01b0385165f908152609c602052604090206133c4906133bf906108a9565b61450b565b945f198314613524575b6040516329460cc560e11b81526001600160a01b0385811660048301526024820185905290939092906020856044815f7f000000000000000000000000000000000000000000000000000000000000000089165af1948515610563575f95613503575b5084976134606134536134438461434c565b85516001600160801b0316612a35565b6001600160801b03168452565b6134746119a884516001600160801b031690565b116134f1577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58946134bd6134ec936104cb8660018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03909816885260208801919091528601525f60608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61351d91955060203d60201161055c5761054e8183610f6b565b935f613431565b915061353a6119a882516001600160801b031690565b8086111561354a578503916133ce565b505f9450505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563576135be916135ae915f916135c3575b5061434c565b6001600160801b03166020830152565b61339b565b6135dc915060203d60201161055c5761054e8183610f6b565b5f6135a8565b93929190916135ef61444f565b6135f7613ed1565b6001600160a01b0385165f9081526101376020526040902061361890611fe8565b946001600160801b0361363287516001600160801b031690565b16156137e25761364186612ac2565b6001600160a01b0381165f908152609c60205260409020613665906133bf906108a9565b955f1984146137b2575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610563575f96613791575b5085986137016136f46136e48461434c565b86516001600160801b0316612a35565b6001600160801b03168552565b6137156119a885516001600160801b031690565b116134f1577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e589561375e6134ec946104cb8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b6137ab91965060203d60201161055c5761054e8183610f6b565b945f6136d2565b92506137c86119a884516001600160801b031690565b808711156137d85786039261366f565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105635761384c9161383c915f916135c3575061434c565b6001600160801b03166020880152565b613641565b5f546001600160a01b03163303610e4d57565b51906001600160401b038216820361030757565b9081606091031261030757612408604080519261389484610f35565b805161389f816103b3565b84526138ad60208201613864565b602085015201613864565b92906001600160a01b039081811615610b87576138d3613ed1565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561030757604094855193631d8557d760e01b85526004945f81878183895af1801561056357613bbe575b506001600160a01b0388165f9081526101376020526040902061394690611fe8565b906001600160801b0361396083516001600160801b031690565b1615613bae5761396f82612ac2565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561056357613b8f575b508651936303d1689d60e11b978886526020918287806139e9888c83019190602083019252565b0381845afa968715610563575f97613b70575b508699613a1c6108a98d60018060a01b03165f52609c60205260405f2090565b88118015613b60575b613b50579083613a6292613a4087516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610563575f85948894613aa79c613b33575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af1958615610563576109c4613aee94613ad1936104aa9361250f9a613b15575b505061434c565b6001600160a01b0388165f90815261013760205260409020612052565b613b10613afa83614627565b8097613b0b610a1e610a0a8761434c565b614bb7565b61437f565b81613b2b92903d1061055c5761054e8183610f6b565b505f80613aca565b613b4990873d891161055c5761054e8183610f6b565b505f613a7c565b825163efda1a2760e01b81528990fd5b50613b696122e3565b8811613a25565b613b88919750833d851161055c5761054e8183610f6b565b955f6139fc565b613ba79060603d606011610b5757610b488183610f6b565b505f6139c2565b875163673f032f60e11b81528690fd5b80610b7b613bcb92610f02565b5f613924565b90613bda614c25565b6040810151613be7614c25565b6001600160a01b0383168015610b87576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613c4033946020830190611b7b565b0390a26020810151613c50614c25565b61271061ffff821611613ca657613c69613c8e936146b6565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614c66565b613c96614c96565b613c9e614c25565b61250f614cbd565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613cf6575b50506112b957565b5f805160206154d98339815191525416141590505f80613cee565b90604051613d1e81610f1a565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613ec9575b613ebc5783613e86575f5b609a5f526001600160a01b0316613d7b5f805160206154998339815191528601613d11565b8051909790613d92906001600160a01b031661124f565b98613db7613dab6020809b01516001600160601b031690565b6001600160601b031690565b948381108015613e7c575b613e6a5791600193979a95613de1613ded939488035b838c0390614615565b80920198870391612c65565b01970193808611801590613e60575b613e5557609a5f528290613e1e5f805160206154998339815191528701613d11565b805190890151969992966001600160a01b039091169460019392613ded9290916001600160601b0390911690613de1908803613dd8565b945050509250509190565b5081851015613dfc565b60405163e8722f8f60e01b8152600490fd5b50808b1115613dc2565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613d56565b505093505050505f905f90565b508415613d4b565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563575f91613f3d575b50613f2b57565b60405163e775715160e01b8152600490fd5b613f56915060203d602011611155576111468183610f6b565b5f613f24565b604290467f00000000000000000000000000000000000000000000000000000000000000000361400a5760d354905b613fa2613f9b60408301836127b2565b3691610fa7565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613fed81610f50565b5190206040519161190160f01b8352600283015260228201522090565b614012614de4565b90613f8b565b6004111561402257565b634e487b7160e01b5f52602160045260245ffd5b6140408383614eb1565b5061404d81959295614018565b1593846140e9575b508315614063575b50505090565b5f92935090829160405161409b816126826020820194630b135d3f60e11b998a87526024840152604060448401526064830190611b7b565b51915afa906140a86128e7565b826140db575b826140be575b50505f808061405d565b6140d391925060208082518301019101611fce565b145f806140b4565b9150602082511015916140ae565b6001600160a01b0383811691161493505f614055565b90614108614eeb565b5f905f60b09360b083049361411b615406565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b87841061415d57505050505050505050565b8261416c910180928887614f92565b906141778282614f62565b916141966141906141888684614f70565b969093614f81565b90614faa565b90893b15610307575f908d6141c3604094855198899485946304512a2360e31b86528a8a60048801614fc6565b03816801bc16d674ec8000008d5af1908115610563577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19461420f9261421e575b505192839283615019565b0390a16001819301929061414b565b80610b7b61422b92610f02565b5f614204565b614239614eeb565b8160301161030757614190917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614277615406565b9061428e6142858486614f70565b96909486614f81565b94813b15610307576801bc16d674ec8000005f946142f497604051988996879586946304512a2360e31b8652608060048701526142e56142d28d60848901906126fc565b60031994858983030160248a0152611b7b565b92868403016044870152612714565b90606483015203925af1908115610563577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926124b39261433d575b5060405191829182615008565b61434690610f02565b5f614330565b6001600160801b0390818111614360571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b478211614442575b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0060028154146144305760029055814710614418575f918291829182916001600160a01b03165af16143d76128e7565b50156144065761250f60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b61444a614eeb565b614387565b614457615231565b1561445e57565b604051630a62fbdb60e11b8152600490fd5b6144798261434c565b609854906144916001600160801b0391828416612a35565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b6001600160a01b0381165f908152609c60205260409020546144dd90612084565b90811561233f576001600160801b036144f86144ff926125e5565b169161450b565b8082101561233f570390565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa8015610563576145a6936001600160401b036108846040614585946020975f916145f6575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610563575f916145dd575090565b610636915060203d60201161055c5761054e8183610f6b565b61460f915060603d606011610b5757610b488183610f6b565b5f614576565b9080821015614622575090565b905090565b609854906001600160801b03821681158015614656575b156146495750905090565b6106369260801c91612c65565b50801561463e565b6098546001600160801b03811690821580156146ae575b1561467f57505090565b60801c9061468e828285612c65565b928215612802570961469d5790565b60018101809111156106365761200d565b508115614675565b6146be613ed1565b6001600160a01b0316801561470657606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190614722613ed1565b6001600160a01b038316908115610b875780156147ce57806147496119a860985460801c90565b0193614753612637565b85116147bc57610a1e9461477a9161477561476d8561465e565b97889361434c565b614470565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926147ec613ed1565b6001600160a01b038216918215610b875781156147ce57816148136119a860985460801c90565b0161481c612637565b81116147bc57610a1e956148636147b7927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461477561485b8861465e565b9a8b9361434c565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b8015612193576148a16119a860985460801c90565b5f821261497357816148b29161283d565b906148bf610a1e8361434c565b6148d46065549161ffff8360a01c1690612bfd565b801561496e57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936149126119a86098546001600160801b031690565b806149585750506124b390925b6001600160a01b0316916149338484614470565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b6124b39261496892039084612c65565b9261491f565b505050565b9061497d90612f7a565b6149926119a8609e546001600160801b031690565b806149b2575b50806149a2575050565b612b3f610a1e9161250f93612645565b90614a197f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161138b6149fd6149f26149eb888861283d565b8785612c65565b80809403960361434c565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f614998565b609a549068010000000000000000821015610f15576001820180609a558210156128d557609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f8051602061549983398151915290910155565b614a886152a0565b600181018091116113f8576001600160a01b03808211614ac2579061250f9160405191614ab483610f1a565b1681525f6020820152614a22565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b8015614b1b57614af06152a0565b9081018091116113f8576001600160a01b03808211614ac2579061250f9160405191614ab483610f1a565b604051632ec8835b60e21b8152600490fd5b9190918015614b1b57614b3e6152a0565b9081018091116113f8576001600160a01b03808211614ac2576001600160601b0390818511614b97579061250f9394614b929260405194614b7e86610f1a565b168452166001600160601b03166020830152565b614a22565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60018060a01b03165f52609c60205260405f209081548181039081116113f857614be1925561434c565b609854906001600160801b03908183160316906001600160801b03191617609855565b614c0c614c25565b614c14614de4565b60d3548103614c205750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614c5457565b604051631afcd79f60e31b8152600490fd5b614c6e614c25565b8015614c845760018101614c7f5750565b609d55565b6040516331278a8760e01b8152600490fd5b614c9e614c25565b6801bc16d674ec800000614cb0612637565b10614c8457614c20614de4565b614cc5614c25565b614ccd614c25565b614cd5614c25565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614d0e576121933430614718565b60405163ea2559bb60e01b8152600490fd5b90816020910312610307575160ff811681036103075790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614dc3575b50614d8957604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206154d98339815191528403614daa5761250f9293506152e2565b604051632a87526960e21b815260048101859052602490fd5b614ddd91955060203d60201161055c5761054e8183610f6b565b935f614d63565b6e5661756c7456616c696461746f727360881b6020604051614e0581610f1a565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610f155760405251902090565b8151919060418303614ee157614eda9250602082015190606060408401519301515f1a90615384565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803180614f20575050565b813b15610307575f9160448392604051948593849263f3fef3a360e01b845230600485015260248401525af1801561056357614f595750565b61250f90610f02565b906030116103075790603090565b906090116103075760300190606090565b9060b0116103075760900190602090565b90939293848311610307578411610307578101920390565b359060208110614fb8575090565b5f199060200360031b1b1690565b9695949061500393614fe7614ff5926060979560808c5260808c0191612714565b9089820360208b0152611b7b565b918783036040890152612714565b930152565b9060206106369281815201906126fc565b916020610636938181520191612714565b60018060a01b0381165f5261013760205260405f20906040519161504d83610f1a565b54906001600160801b03918281169081855260801c60208501521561496e576133bf6108a96150a09261507e613ed1565b61508786612ac2565b6001600160a01b03165f908152609c6020526040902090565b915116116134f157565b9291908015611af6576001600160a01b03828116928315610b87576150d061171b615231565b6151b857906118299561519c613224857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161517161511b6119a86099546001600160801b031690565b926126826151438561302a61512e6152a0565b61513d6119a8609e5460801c90565b9061283d565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c60205260409020615194838254612645565b90550161434c565b60408051888152602081019590955291169290819081016147b7565b9293946151c483612084565b9384156147ce577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361520e8661522993615204610a1e6132a38461434c565b613b108487614bb7565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563575f91615287575090565b610636915060203d602011611155576111468183610f6b565b609a54806152ad57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661124f565b90813b15615363575f805160206154d983398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115615348576121939161542f565b50503461535157565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116153fb579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610563575f516001600160a01b038116156153f157905f905f90565b505f906001905f90565b5050505f9160039190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261063681610f1a565b5f8061063693602081519101845af46154466128e7565b919061545c575080511561440657805190602001fd5b8151158061548f575b61546d575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561546556fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122059150ede3015bf2d6cd55d31f6a9c9f02cfd4250f4ec391b1296422786a6730f64736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612a86565b005b5f3560e01c806301d523b6146102f157806301e1d114146102ec578063066055e0146102e757806307a2d13a146102e257806318f72950146102dd5780631a7ff553146102d8578063201b9eb5146102d357806323d18ed8146102ce5780632999ad3f146102c95780632cdf7401146102c45780633229fa95146102bf57806333194c0a146102ba57806336fe59d2146102b55780633a98ef39146102b0578063439fab91146102ab57806343e82a79146102a657806346904840146102a15780634ec96b221461029c5780634f1ef2861461029757806352d1902d1461029257806353156f281461028d57806354fd4d50146102885780635c60da1b146102835780635cfc1a511461027e57806360d60e6e1461027957806372b410a814610274578063754c38881461026f57806376b58b901461026a5780637fd6f15c1461026557806383d430d5146102605780638697d2c21461025b5780638ceab9aa146102565780639267842a14610251578063a49a1e7d1461024c578063ac9650d814610247578063ad3cb1cc14610242578063ad68ebf71461023d578063b1f0e7c714610238578063c6e6f59214610233578063d83ad00c1461022e578063e74b981b14610229578063ee3bd5df14610224578063f04da65b1461021f578063f851a4401461021a5763f9609f080361000e57611fa4565b611f7d565b611f42565b611f1c565b611eef565b611ec9565b611eab565b611e91565b611cbe565b611c79565b611c03565b611b08565b611914565b6118e0565b61173a565b61156a565b611546565b6114f5565b61148a565b6113fd565b611358565b61133e565b61130a565b6112ef565b6112cb565b611262565b610fdd565b610eb6565b610e8e565b610d81565b610cbb565b610c3a565b610c19565b610bdf565b610bb3565b610b99565b6106f6565b610653565b610639565b6105da565b610586565b610568565b6103c4565b610393565b610319565b6001600160a01b0381160361030757565b5f80fd5b908160809103126103075790565b608036600319011261030757600435610331816102f6565b60443561033d816102f6565b606435906001600160401b0382116103075760209261036b61036661038194369060040161030b565b61210d565b6103768234336147e0565b5060243590336135e2565b604051908152f35b5f91031261030757565b34610307575f36600319011261030757602060985460801c604051908152f35b6001600160801b0381160361030757565b34610307576020366003190112610307576004356103e1816103b3565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610563575f91610534575b50335f9081526101376020526040902061045d90611fe8565b916001600160801b0361047784516001600160801b031690565b1615610522576104d08361048d61051e95612ac2565b6104b76104aa846104a584516001600160801b031690565b612039565b6001600160801b03168252565b335f90815261013760205260409020612052565b612052565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610556915060203d60201161055c575b61054e8183610f6b565b810190611fce565b5f610444565b503d610544565b611fdd565b34610307576020366003190112610307576020610381600435612084565b60603660031901126103075760043561059e816102f6565b6024356105aa816102f6565b604435906001600160401b038211610307576020926105d361036661038194369060040161030b565b34906147e0565b34610307576020366003190112610307576004356001600160401b0381116103075761036661002091369060040161030b565b606090600319011261030757600435610625816102f6565b9060243590604435610636816102f6565b90565b3461030757602061038161064c3661060d565b91336135e2565b34610307575f806003193601126103075761066c613851565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610307575f809160046040518094819363b4b6d74f60e01b83525af18015610563576106c3575080f35b6100209150610f02565b606090600319011261030757600435906024356106e9816102f6565b90604435610636816102f6565b3461030757610704366106cd565b906001600160a01b0380831615610b875761071d613ed1565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103075760408051631d8557d760e01b815260049491905f81878183875af1801561056357610b6e575b506001600160a01b0383165f9081526101376020526040902061079090611fe8565b6001600160801b0392836107ab83516001600160801b031690565b1615610b5e576107ba82612ac2565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610563575f98610b2d575b50602097888101956001600160401b039182806108338a516001600160401b031690565b1614610b1d57908c92918751918c838061085f6303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156105635761088b938e5f94610af8575b5050516001600160801b03165b1690612b77565b966108af6108a98a60018060a01b03165f52609c60205260405f2090565b54612084565b928389118015610ae8575b610ad857908b6108f893926108d689516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561056357670de0b6b3a764000094610947948e5f95610aab575b505061093961092b61093f92612820565b93516001600160401b031690565b93612820565b921690612c65565b1015610a9d578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610563577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610a7a956109f193610a7f575b50506109d46104aa6109c48c61434c565b83516001600160801b0316612039565b6001600160a01b0386165f90815261013760205260409020612052565b6109fa82614627565b90610a39610a1e610a0a8561434c565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610a438286614bb7565b610a4d838961437f565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610a9592903d1061055c5761054e8183610f6b565b505f806109b3565b835163185cfc6d60e11b8152fd5b61093f929550610ace610939928261092b93903d1061055c5761054e8183610f6b565b959250508e61091a565b875163efda1a2760e01b81528590fd5b50610af16122e3565b89116108ba565b6108849294509081610b1592903d1061055c5761054e8183610f6b565b92908e610877565b8651630709133160e01b81528490fd5b610b5091985060603d606011610b57575b610b488183610f6b565b810190613878565b965f61080f565b503d610b3e565b825163673f032f60e11b81528790fd5b80610b7b610b8192610f02565b80610389565b5f61076e565b60405163d92e233d60e01b8152600490fd5b34610307575f3660031901126103075760206103816122e3565b34610307575f366003190112610307576020610bcd612345565b6040516001600160a01b039091168152f35b34610307575f3660031901126103075760206040517f11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c5058152f35b6020610381610c273661060d565b91610c338334336147e0565b50336135e2565b34610307575f3660031901126103075760206001600160801b0360985416604051908152f35b9181601f84011215610307578235916001600160401b038311610307576020838186019501011161030757565b602060031982011261030757600435906001600160401b03821161030757610cb791600401610c60565b9091565b610cc436610c8d565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610d6d575b610d5b5768010000000000000003610d1e9368ffffffffffffffffff191617845561243f565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610cf8565b3461030757610d8f366106cd565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105635782915f91610e5f575b50163303610e4d5781610a7a610e1a86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966138b8565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610e81915060203d602011610e87575b610e798183610f6b565b8101906120f8565b5f610de2565b503d610e6f565b34610307575f366003190112610307576065546040516001600160a01b039091168152602090f35b34610307576020366003190112610307576020610edd600435610ed8816102f6565b6125e5565b6001600160801b0360405191168152f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b038111610f1557604052565b610eee565b604081019081106001600160401b03821117610f1557604052565b606081019081106001600160401b03821117610f1557604052565b608081019081106001600160401b03821117610f1557604052565b90601f801991011681019081106001600160401b03821117610f1557604052565b6001600160401b038111610f1557601f01601f191660200190565b929192610fb382610f8c565b91610fc16040519384610f6b565b829481845281830111610307578281602093845f960137010152565b604080600319360112610307576004908135610ff8816102f6565b6024356001600160401b0381116103075736602382011215610307576110279036906024818701359101610fa7565b91611030613cb8565b8051926110678461105960209363439fab9160e01b858401528460248401526044830190611b7b565b03601f198101865285610f6b565b61106f613cb8565b611077613851565b6001600160a01b0383811680159291908790841561122d575b84156111bf575b841561115c575b505082156110c6575b50506110b7576100208383614d39565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610563575f9261112f575b5050155f806110a7565b61114e9250803d10611155575b6111468183610f6b565b8101906120b7565b5f80611125565b503d61113c565b855163054fd4d560e41b81529294508391839182905afa90811561056357879160ff915f91611192575b5016141591865f61109e565b6111b29150843d86116111b8575b6111aa8183610f6b565b810190614d20565b5f611186565b503d6111a0565b935050835163198ca60560e11b815282818981875afa9081156105635788917f11a6b7bef0f97d298d56e5af2aa94330353808e861cbac86172faad21b10c505915f91611210575b50141593611097565b6112279150853d871161055c5761054e8183610f6b565b5f611207565b5f805160206154d983398151915254909450849061125b906001600160a01b03165b6001600160a01b031690565b1493611090565b34610307575f366003190112610307577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036112b95760206040515f805160206154d98339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112610307576001600160a01b036112e6612345565b163303610e4d57005b34610307575f36600319011261030757602060405160038152f35b34610307575f366003190112610307575f805160206154d9833981519152546040516001600160a01b039091168152602090f35b34610307575f366003190112610307576020610381612637565b3461030757602036600319011261030757609a80549081905f6004355b8482106113a65750505081101561139b5761051e905b6040519081529081906020820190565b5061051e5f1961138b565b909193808316906001818518811c83018093116113f8575f8790525f805160206154998339815191528301546001600160a01b03168410156113ed575050935b9190611375565b9095910192506113e6565b61200d565b34610307575f36600319011261030757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610563576020915f9161146d575b506040519015158152f35b6114849150823d8411611155576111468183610f6b565b5f611462565b34610307576020366003190112610307576004356114a7816102f6565b6114af613851565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103075760803660031901126103075761051e611529600435611518816102f6565b606435906044359060243590612652565b604080519384526020840192909252908201529081906060820190565b34610307575f36600319011261030757602061ffff60655460a01c16604051908152f35b34610307576003196040368201126103075760049081356001600160401b038082116103075760a082850193833603011261030757602435908111610307576115b69036908501610c60565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103075760405163837d444160e01b8152905f9082908183816116098c828f01612734565b03925af1801561056357611727575b50611621613ed1565b611629612a50565b90811633141591826116f8575b505090506116e7576044019160b061164e84846127b2565b905004801580156116cf575b6116bf5761166f6116696122e3565b91612807565b116116b0575060b061168183836127b2565b9050145f1461169d5761002091611697916127b2565b90614231565b610020916116aa916127b2565b906140ff565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506116da84846127b2565b905060b08202141561165a565b604051634ca8886760e01b81528390fd5b61171b925061171561171f9461170d88613f5c565b923691610fa7565b91614036565b1590565b805f80611636565b80610b7b61173492610f02565b5f611618565b346103075760603660031901126103075760043560243561175f604435828433612652565b919261178b7f00000000000000000000000000000000000000000000000000000000000000008261283d565b421080156118d8575b80156118d0575b6118be577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb56936117f66117db6117d08661434c565b60995460801c612039565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f9161183a9190611829608082610f6b565b5190205f52609b60205260405f2090565b555f9360018311611873575b50505050611854823361437f565b604080519485526020850191909152830152339180606081015b0390a2005b6118b492939450611884908861283d565b60408051336020820190815291810193909352606083018290526080958601835290949091906118299082610f6b565b555f808080611846565b604051630e3d8e8d60e11b8152600490fd5b50821561179b565b508115611794565b3461030757604036600319011261030757602061190b602435611902816102f6565b600435336150aa565b6103813361502a565b3461030757602036600319011261030757600435611930613ed1565b335f9081526101376020526040902061194890611fe8565b6001600160801b038061196283516001600160801b031690565b161561052257829061197383612ac2565b82516001600160801b03161610611af657335f908152609c6020526040902054826119b46119a884516001600160801b031690565b6001600160801b031690565b14611ae0576119d890836119d26119a885516001600160801b031690565b91612c65565b91611a056119f86119e88361434c565b84516001600160801b0316610a11565b6001600160801b03168352565b335f90815261013760205260409020611a1f908390612052565b611a676020611a5860018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336150aa565b9301516001600160801b031690565b833b156103075760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105635761051e92611acd575b506040519081529081906020820190565b80610b7b611ada92610f02565b5f611abc565b335f908152610137602052604081205591611a1f565b604051636edcc52360e01b8152600490fd5b346103075761186e7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611b3a36610c8d565b9290611b44613851565b6040519182916020835233956020840191612714565b5f5b838110611b6b5750505f910152565b8181015183820152602001611b5c565b90602091611b9481518092818552858086019101611b5a565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611bd55750505050505090565b9091929394958480611bf3600193603f198682030187528a51611b7b565b9801930193019194939290611bc5565b34610307576020366003190112610307576001600160401b036004358181116103075736602382011215610307578060040135918211610307573660248360051b830101116103075761051e916024611c5c9201612988565b60405191829182611ba0565b906020610636928181520190611b7b565b34610307575f3660031901126103075761051e604051611c9881610f1a565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611b7b565b346103075760408060031936011261030757600435611cdc816102f6565b6024356001600160a01b03337f0000000000000000000000000000000000000000000000000000000000000000821614801590611e21575b611e1057611d2061444f565b611d28613ed1565b821615611dff578015611dee57917fd083678824038160bef3975359ab29f19c3f0e9bcf9d7ead540a492d4d678b6383611d6461051e95614627565b93611d7f610a1e611d748461434c565b60985460801c612a35565b611d898582614470565b611da4611d95826144bc565b611d9e8461450b565b90614615565b80611ddc575b5083516001600160a01b03919091168152602081019190915260408101849052606090a1519081529081906020820190565b611de7908280613340565b505f611daa565b82516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8351634ca8886760e01b8152600490fd5b508351638da5cb5b60e01b81526020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610563575f91611e72575b508116301415611d14565b611e8b915060203d602011610e8757610e798183610f6b565b5f611e67565b34610307575f366003190112610307576020610bcd612a50565b34610307576020366003190112610307576020610381600435614627565b34610307575f3660031901126103075760206001600160801b0360995416604051908152f35b3461030757602036600319011261030757610020600435611f0f816102f6565b611f17613851565b6146b6565b34610307575f3660031901126103075760206001600160801b03609e5416604051908152f35b3461030757602036600319011261030757600435611f5f816102f6565b60018060a01b03165f52609c602052602060405f2054604051908152f35b34610307575f366003190112610307575f546040516001600160a01b039091168152602090f35b6040366003190112610307576020610381600435611fc1816102f6565b602435906105d3826102f6565b90816020910312610307575190565b6040513d5f823e3d90fd5b90604051611ff581610f1a565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f1901919082116113f857565b6001600160801b0391821690821603919082116113f857565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b038116908161209c57505090565b916106369260801c90612c65565b5190811515820361030757565b9081602091031261030757610636906120aa565b908160209103126103075751610636816103b3565b81810392915f1380158285131691841216176113f857565b908160209103126103075751610636816102f6565b604051630156a69560e11b81523060048201526020916001600160a01b03919083826024817f000000000000000000000000000000000000000000000000000000000000000087165afa918215610563575f926122c0575b5061216f90612dcb565b9390809215612196575b50506121859150612f8a565b61218b57565b612193613162565b50565b60405163070aab0d60e11b815291925082826004817f000000000000000000000000000000000000000000000000000000000000000088165afa8015610563576001600160801b036121f4916121fa945f91612293575b5016612f51565b906120e0565b91604051638da5cb5b60e01b81528281600481857f0000000000000000000000000000000000000000000000000000000000000000165afa928315610563575f93612274575b505016301480159061226b575b61225957805f80612179565b60405163c284f82560e01b8152600490fd5b505f811261224d565b61228b929350803d10610e8757610e798183610f6b565b905f80612240565b6122b39150863d88116122b9575b6122ab8183610f6b565b8101906120cb565b5f6121ed565b503d6122a1565b61216f9192506122dc90853d8711611155576111468183610f6b565b9190612165565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163147016099546001600160801b03612326818316612084565b90609e5416019060801c01908181115f1461233f570390565b50505f90565b61016a546001600160a01b0316801561235b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b919091604081840312610307578035612398816102f6565b9260208201356001600160401b039283821161030757019160608383031261030757604051926123c784610f35565b80358452602081013561ffff81168103610307576020850152604081013591821161030757019080601f830112156103075781602061240893359101610fa7565b604082015290565b90610636949360809361ffff9260018060a01b0316845260208401521660408201528160608201520190611b7b565b5f5490916001600160a01b039182166124b85782612480917f6efc3c5ea2064c46840711aa5ff8d7f70826faa0cc04fcf0557a3863533aafad940190612380565b911661248c8282613bd1565b6124b382519260406124a3602083015161ffff1690565b9101519060405194859485612410565b0390a1565b5050506124c3614c25565b6124d86119a86099546001600160801b031690565b600181116125d35760011461254e575b609f546124f36152a0565b90808210612511575b50506125075f609f55565b61250f614c04565b565b5f805160206154b983398151915291612544910361252e81614ae2565b604080519182525f602083015290918291820190565b0390a15f806124fc565b61258761256b6125666098546001600160801b031690565b612021565b6001600160801b03166001600160801b03196098541617609855565b61259c6001600160801b031960995416609955565b6125a4614a80565b5f805160206154b9833981519152604051806125cb81905f60206040840193600181520152565b0390a16124e8565b604051630299325160e41b8152600490fd5b60018060a01b03165f5261013760205260405f206040519061260682610f1a565b54906001600160801b03918281169081835260801c602083015261262957511690565b61263281612ac2565b511690565b609d548061063657505f1990565b919082039182116113f857565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061269081608081015b03601f198101835282610f6b565b5190205f52609b60205260405f20549182156126c0576126b1918391613d36565b90918281039081116113f85792565b5050505f905f905f90565b9035601e19823603018112156103075701602081359101916001600160401b03821161030757813603831361030757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06106369260208152823560208201526020830135604082015261277061276060408501856126cb565b84606085015260c0840191612714565b906127a361279861278460608701876126cb565b601f19858703810160808701529591612714565b9460808101906126cb565b93909282860301910152612714565b903590601e198136030182121561030757018035906001600160401b0382116103075760200191813603831361030757565b634e487b7160e01b5f52601260045260245ffd5b8115612802570490565b6127e4565b906801bc16d674ec80000091808302928304036113f857565b90670de0b6b3a7640000918281029281840414901517156113f857565b919082018092116113f857565b6001600160401b038111610f155760051b60200190565b9061286b8261284a565b6128786040519182610f6b565b8281528092612889601f199161284a565b01905f5b82811061289957505050565b80606060208093850101520161288d565b634e487b7160e01b5f52603260045260245ffd5b908210156128d557610cb79160051b8101906127b2565b6128aa565b908092918237015f815290565b3d15612911573d906128f882610f8c565b916129066040519384610f6b565b82523d5f602084013e565b606090565b602081830312610307578051906001600160401b038211610307570181601f8201121561030757805161294881610f8c565b926129566040519485610f6b565b81845260208284010111610307576106369160208085019101611b5a565b80518210156128d55760209160051b010190565b91909161299483612861565b925f5b8181106129a357505050565b5f806129b08385876128be565b604093916129c28551809381936128da565b0390305af4906129d06128e7565b91156129f75750906001916129e58288612974565b526129f08187612974565b5001612997565b90604481511061030757612a31612a1c60049283810151602480918301019101612916565b925162461bcd60e51b81529283928301611c68565b0390fd5b9190916001600160801b03808094169116019182116113f857565b60d2546001600160a01b03168061063657507f000000000000000000000000000000000000000000000000000000000000000090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303612ab857565b6121933433614718565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563575f91612b58575b5060208201916001600160801b03918284511691828214612b515783612b44612b3f612b4c958584865116612c65565b61434c565b16905261434c565b169052565b5050505050565b612b71915060203d60201161055c5761054e8183610f6b565b5f612b0f565b90808202905f1981840990828083109203918083039214612bec57670de0b6b3a76400009082821115612bda577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a764000091500490565b90808202905f1981840990828083109203918083039214612c5a576127109082821115612bda577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b505061271091500490565b9091828202915f1984820993838086109503948086039514612cd85784831115612bda57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509061063692506127f8565b90816060910312610307578051916106366040602084015193016120aa565b81835290916001600160fb1b0383116103075760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036103075760408301526040810135612d57816102f6565b6001600160a01b031660608381019190915281013536829003601e19018112156103075701602081359101906001600160401b038111610307578060051b360382136103075760a0836080806106369601520191612d04565b9190915f83820193841291129080158216911516176113f857565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612df69060048301612d28565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610563575f915f905f95612f1c575b508415612ec95781612e40612345565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612ec257509060205f92600460405180958193634641257d60e01b83525af190811561056357612e9d925f92612ea1575b50612db0565b9190565b612ebb91925060203d60201161055c5761054e8183610f6b565b905f612e97565b9081612ecf575b50509190565b803b1561030757604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561056357612f09575b80612ec9565b80610b7b612f1692610f02565b5f612f03565b91945050612f42915060603d606011612f4a575b612f3a8183610f6b565b810190612ce5565b93905f612e30565b503d612f30565b6001600160ff1b038111612f625790565b6024906040519063123baf0360e11b82526004820152fd5b600160ff1b81146113f8575f0390565b8015612193576040516278744560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691906020908181600481875afa908115610563575f91613145575b50604051631cd5ec3960e31b8152908282600481885afa91821561056357613011935f93613126575b5050612645565b801561311b5761302f8161302a6119a860985460801c90565b61283d565b905f8312156130b7576130539161304e9161304985612f7a565b612c65565b612f51565b61305c81612f7a565b92803b156103075760405163304f0a6b60e21b815260048101949094525f908490602490829084905af19182156105635761250f9361309f936130a45750612db0565b61488c565b80610b7b6130b192610f02565b5f612e97565b6130c59161304e9184612c65565b823b156103075760405163304f0a6b60e21b815260048101829052925f908490602490829084905af19182156105635761250f9361309f93613108575b506120e0565b80610b7b61311592610f02565b5f613102565b5061250f915061488c565b61313d929350803d1061055c5761054e8183610f6b565b905f8061300a565b61315c9150823d841161055c5761054e8183610f6b565b5f612fe1565b6131a77f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163147016131a16119a860995460801c90565b90612645565b90811561333b57609e546001600160801b03811690816132c3575b50506131d96119a86099546001600160801b031690565b91821580156132bb575b6132b5576131f490611d9e84612084565b80156132b55761320381614627565b9283156132ae576132a361250f92613240613224612b3f88610a1e96612645565b6001600160801b03166001600160801b03196099541617609955565b61325a6117db61324f8361434c565b60995460801c612a35565b6132648187614b2d565b60408051878152602081018390525f805160206154b98339815191529190a1612b3f61256b6132928861434c565b6098546001600160801b0316612039565b60985460801c612039565b505f925050565b505f9150565b5080156131e3565b81849294106132ae5761324f8461330b935f805160206154b9833981519152826117db9560801c6132f48282614b2d565b604080519182526020820192909252a1039461434c565b61331f6001600160801b03609e5416609e55565b6133346001600160801b0319609e5416609e55565b5f806131c2565b5f9150565b929161334a61444f565b613352613ed1565b6001600160a01b0384165f9081526101376020526040902061337390611fe8565b6001600160801b0361338c82516001600160801b031690565b16156135535761339b81612ac2565b6001600160a01b0385165f908152609c602052604090206133c4906133bf906108a9565b61450b565b945f198314613524575b6040516329460cc560e11b81526001600160a01b0385811660048301526024820185905290939092906020856044815f7f000000000000000000000000000000000000000000000000000000000000000089165af1948515610563575f95613503575b5084976134606134536134438461434c565b85516001600160801b0316612a35565b6001600160801b03168452565b6134746119a884516001600160801b031690565b116134f1577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58946134bd6134ec936104cb8660018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03909816885260208801919091528601525f60608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61351d91955060203d60201161055c5761054e8183610f6b565b935f613431565b915061353a6119a882516001600160801b031690565b8086111561354a578503916133ce565b505f9450505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563576135be916135ae915f916135c3575b5061434c565b6001600160801b03166020830152565b61339b565b6135dc915060203d60201161055c5761054e8183610f6b565b5f6135a8565b93929190916135ef61444f565b6135f7613ed1565b6001600160a01b0385165f9081526101376020526040902061361890611fe8565b946001600160801b0361363287516001600160801b031690565b16156137e25761364186612ac2565b6001600160a01b0381165f908152609c60205260409020613665906133bf906108a9565b955f1984146137b2575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610563575f96613791575b5085986137016136f46136e48461434c565b86516001600160801b0316612a35565b6001600160801b03168552565b6137156119a885516001600160801b031690565b116134f1577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e589561375e6134ec946104cb8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b6137ab91965060203d60201161055c5761054e8183610f6b565b945f6136d2565b92506137c86119a884516001600160801b031690565b808711156137d85786039261366f565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105635761384c9161383c915f916135c3575061434c565b6001600160801b03166020880152565b613641565b5f546001600160a01b03163303610e4d57565b51906001600160401b038216820361030757565b9081606091031261030757612408604080519261389484610f35565b805161389f816103b3565b84526138ad60208201613864565b602085015201613864565b92906001600160a01b039081811615610b87576138d3613ed1565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561030757604094855193631d8557d760e01b85526004945f81878183895af1801561056357613bbe575b506001600160a01b0388165f9081526101376020526040902061394690611fe8565b906001600160801b0361396083516001600160801b031690565b1615613bae5761396f82612ac2565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561056357613b8f575b508651936303d1689d60e11b978886526020918287806139e9888c83019190602083019252565b0381845afa968715610563575f97613b70575b508699613a1c6108a98d60018060a01b03165f52609c60205260405f2090565b88118015613b60575b613b50579083613a6292613a4087516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610563575f85948894613aa79c613b33575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af1958615610563576109c4613aee94613ad1936104aa9361250f9a613b15575b505061434c565b6001600160a01b0388165f90815261013760205260409020612052565b613b10613afa83614627565b8097613b0b610a1e610a0a8761434c565b614bb7565b61437f565b81613b2b92903d1061055c5761054e8183610f6b565b505f80613aca565b613b4990873d891161055c5761054e8183610f6b565b505f613a7c565b825163efda1a2760e01b81528990fd5b50613b696122e3565b8811613a25565b613b88919750833d851161055c5761054e8183610f6b565b955f6139fc565b613ba79060603d606011610b5757610b488183610f6b565b505f6139c2565b875163673f032f60e11b81528690fd5b80610b7b613bcb92610f02565b5f613924565b90613bda614c25565b6040810151613be7614c25565b6001600160a01b0383168015610b87576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613c4033946020830190611b7b565b0390a26020810151613c50614c25565b61271061ffff821611613ca657613c69613c8e936146b6565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614c66565b613c96614c96565b613c9e614c25565b61250f614cbd565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613cf6575b50506112b957565b5f805160206154d98339815191525416141590505f80613cee565b90604051613d1e81610f1a565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613ec9575b613ebc5783613e86575f5b609a5f526001600160a01b0316613d7b5f805160206154998339815191528601613d11565b8051909790613d92906001600160a01b031661124f565b98613db7613dab6020809b01516001600160601b031690565b6001600160601b031690565b948381108015613e7c575b613e6a5791600193979a95613de1613ded939488035b838c0390614615565b80920198870391612c65565b01970193808611801590613e60575b613e5557609a5f528290613e1e5f805160206154998339815191528701613d11565b805190890151969992966001600160a01b039091169460019392613ded9290916001600160601b0390911690613de1908803613dd8565b945050509250509190565b5081851015613dfc565b60405163e8722f8f60e01b8152600490fd5b50808b1115613dc2565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613d56565b505093505050505f905f90565b508415613d4b565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563575f91613f3d575b50613f2b57565b60405163e775715160e01b8152600490fd5b613f56915060203d602011611155576111468183610f6b565b5f613f24565b604290467f00000000000000000000000000000000000000000000000000000000000000000361400a5760d354905b613fa2613f9b60408301836127b2565b3691610fa7565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613fed81610f50565b5190206040519161190160f01b8352600283015260228201522090565b614012614de4565b90613f8b565b6004111561402257565b634e487b7160e01b5f52602160045260245ffd5b6140408383614eb1565b5061404d81959295614018565b1593846140e9575b508315614063575b50505090565b5f92935090829160405161409b816126826020820194630b135d3f60e11b998a87526024840152604060448401526064830190611b7b565b51915afa906140a86128e7565b826140db575b826140be575b50505f808061405d565b6140d391925060208082518301019101611fce565b145f806140b4565b9150602082511015916140ae565b6001600160a01b0383811691161493505f614055565b90614108614eeb565b5f905f60b09360b083049361411b615406565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b87841061415d57505050505050505050565b8261416c910180928887614f92565b906141778282614f62565b916141966141906141888684614f70565b969093614f81565b90614faa565b90893b15610307575f908d6141c3604094855198899485946304512a2360e31b86528a8a60048801614fc6565b03816801bc16d674ec8000008d5af1908115610563577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19461420f9261421e575b505192839283615019565b0390a16001819301929061414b565b80610b7b61422b92610f02565b5f614204565b614239614eeb565b8160301161030757614190917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614277615406565b9061428e6142858486614f70565b96909486614f81565b94813b15610307576801bc16d674ec8000005f946142f497604051988996879586946304512a2360e31b8652608060048701526142e56142d28d60848901906126fc565b60031994858983030160248a0152611b7b565b92868403016044870152612714565b90606483015203925af1908115610563577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1926124b39261433d575b5060405191829182615008565b61434690610f02565b5f614330565b6001600160801b0390818111614360571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b478211614442575b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0060028154146144305760029055814710614418575f918291829182916001600160a01b03165af16143d76128e7565b50156144065761250f60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b61444a614eeb565b614387565b614457615231565b1561445e57565b604051630a62fbdb60e11b8152600490fd5b6144798261434c565b609854906144916001600160801b0391828416612a35565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b6001600160a01b0381165f908152609c60205260409020546144dd90612084565b90811561233f576001600160801b036144f86144ff926125e5565b169161450b565b8082101561233f570390565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa8015610563576145a6936001600160401b036108846040614585946020975f916145f6575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610563575f916145dd575090565b610636915060203d60201161055c5761054e8183610f6b565b61460f915060603d606011610b5757610b488183610f6b565b5f614576565b9080821015614622575090565b905090565b609854906001600160801b03821681158015614656575b156146495750905090565b6106369260801c91612c65565b50801561463e565b6098546001600160801b03811690821580156146ae575b1561467f57505090565b60801c9061468e828285612c65565b928215612802570961469d5790565b60018101809111156106365761200d565b508115614675565b6146be613ed1565b6001600160a01b0316801561470657606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190614722613ed1565b6001600160a01b038316908115610b875780156147ce57806147496119a860985460801c90565b0193614753612637565b85116147bc57610a1e9461477a9161477561476d8561465e565b97889361434c565b614470565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926147ec613ed1565b6001600160a01b038216918215610b875781156147ce57816148136119a860985460801c90565b0161481c612637565b81116147bc57610a1e956148636147b7927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461477561485b8861465e565b9a8b9361434c565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b8015612193576148a16119a860985460801c90565b5f821261497357816148b29161283d565b906148bf610a1e8361434c565b6148d46065549161ffff8360a01c1690612bfd565b801561496e57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936149126119a86098546001600160801b031690565b806149585750506124b390925b6001600160a01b0316916149338484614470565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b6124b39261496892039084612c65565b9261491f565b505050565b9061497d90612f7a565b6149926119a8609e546001600160801b031690565b806149b2575b50806149a2575050565b612b3f610a1e9161250f93612645565b90614a197f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161138b6149fd6149f26149eb888861283d565b8785612c65565b80809403960361434c565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f614998565b609a549068010000000000000000821015610f15576001820180609a558210156128d557609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f8051602061549983398151915290910155565b614a886152a0565b600181018091116113f8576001600160a01b03808211614ac2579061250f9160405191614ab483610f1a565b1681525f6020820152614a22565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b8015614b1b57614af06152a0565b9081018091116113f8576001600160a01b03808211614ac2579061250f9160405191614ab483610f1a565b604051632ec8835b60e21b8152600490fd5b9190918015614b1b57614b3e6152a0565b9081018091116113f8576001600160a01b03808211614ac2576001600160601b0390818511614b97579061250f9394614b929260405194614b7e86610f1a565b168452166001600160601b03166020830152565b614a22565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60018060a01b03165f52609c60205260405f209081548181039081116113f857614be1925561434c565b609854906001600160801b03908183160316906001600160801b03191617609855565b614c0c614c25565b614c14614de4565b60d3548103614c205750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614c5457565b604051631afcd79f60e31b8152600490fd5b614c6e614c25565b8015614c845760018101614c7f5750565b609d55565b6040516331278a8760e01b8152600490fd5b614c9e614c25565b6801bc16d674ec800000614cb0612637565b10614c8457614c20614de4565b614cc5614c25565b614ccd614c25565b614cd5614c25565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614d0e576121933430614718565b60405163ea2559bb60e01b8152600490fd5b90816020910312610307575160ff811681036103075790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614dc3575b50614d8957604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206154d98339815191528403614daa5761250f9293506152e2565b604051632a87526960e21b815260048101859052602490fd5b614ddd91955060203d60201161055c5761054e8183610f6b565b935f614d63565b6e5661756c7456616c696461746f727360881b6020604051614e0581610f1a565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610f155760405251902090565b8151919060418303614ee157614eda9250602082015190606060408401519301515f1a90615384565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803180614f20575050565b813b15610307575f9160448392604051948593849263f3fef3a360e01b845230600485015260248401525af1801561056357614f595750565b61250f90610f02565b906030116103075790603090565b906090116103075760300190606090565b9060b0116103075760900190602090565b90939293848311610307578411610307578101920390565b359060208110614fb8575090565b5f199060200360031b1b1690565b9695949061500393614fe7614ff5926060979560808c5260808c0191612714565b9089820360208b0152611b7b565b918783036040890152612714565b930152565b9060206106369281815201906126fc565b916020610636938181520191612714565b60018060a01b0381165f5261013760205260405f20906040519161504d83610f1a565b54906001600160801b03918281169081855260801c60208501521561496e576133bf6108a96150a09261507e613ed1565b61508786612ac2565b6001600160a01b03165f908152609c6020526040902090565b915116116134f157565b9291908015611af6576001600160a01b03828116928315610b87576150d061171b615231565b6151b857906118299561519c613224857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161517161511b6119a86099546001600160801b031690565b926126826151438561302a61512e6152a0565b61513d6119a8609e5460801c90565b9061283d565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c60205260409020615194838254612645565b90550161434c565b60408051888152602081019590955291169290819081016147b7565b9293946151c483612084565b9384156147ce577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361520e8661522993615204610a1e6132a38461434c565b613b108487614bb7565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610563575f91615287575090565b610636915060203d602011611155576111468183610f6b565b609a54806152ad57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661124f565b90813b15615363575f805160206154d983398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115615348576121939161542f565b50503461535157565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116153fb579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610563575f516001600160a01b038116156153f157905f905f90565b505f906001905f90565b5050505f9160039190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261063681610f1a565b5f8061063693602081519101845af46154466128e7565b919061545c575080511561440657805190602001fd5b8151158061548f575b61546d575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561546556fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122059150ede3015bf2d6cd55d31f6a9c9f02cfd4250f4ec391b1296422786a6730f64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthPrivErc20Vault.json b/test/shared/artifacts/EthPrivErc20Vault.json deleted file mode 100644 index 597e0779..00000000 --- a/test/shared/artifacts/EthPrivErc20Vault.json +++ /dev/null @@ -1,2057 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthPrivErc20Vault", - "sourceName": "contracts/vaults/ethereum/EthPrivErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61020034620001f25762005d0938819003601f8101601f191683016001600160401b03811184821017620001f65783928291604052833961012091829181010312620001f25762000050826200020a565b6200005e602084016200020a565b6200006c604085016200020a565b916200007b606086016200020a565b62000089608087016200020a565b916200009860a088016200020a565b93620000a760c089016200020a565b95620000b660e08a016200020a565b91610100809a01519360805260a05260c0523060e052620000d66200021f565b468852865261014046815261016091825260018060a01b038061018094168452806101a0951685526101c0951685526101e0958652620001156200021f565b60405196615a4a9889620002bf8a3960805189818161182f01528181611a030152818161316901528181613e0601526158b7015260a051896114c6015260c0518981816140f70152614218015260e0518981816116450152613bc8015251886127c301525187612df801525186613e7c01525185611ba90152518481816104dd01528181610b4201528181612e42015281816135a901528181614770015281816148cb0152614a72015251838181610c01015281816111c20152818161366801526149f601525182611e9c01525181818161279e01526131b10152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620001f257565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620002ac576001600160401b036002600160401b0319828216016200026d57505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe60806040526004361015610022575b3615610018575f80fd5b610020612e1a565b005b5f3560e01c806301d523b6146103c757806301e1d114146103c2578063066055e0146103bd57806306fdde03146103b857806307a2d13a146103b3578063095ea7b3146103ae5780630d392cd9146103a957806318160ddd1461036857806318f72950146103a45780631a7ff5531461039f578063201b9eb51461039a57806322758a4a1461039557806323b872dd146103905780632999ad3f1461038b5780632cdf740114610386578063313ce567146103815780633229fa951461037c57806333194c0a146103775780633644e5151461037257806336fe59d21461036d5780633a98ef3914610368578063439fab911461036357806343e82a791461035e57806346904840146103595780634ec96b22146103545780634f1ef2861461034f57806352d1902d1461034a57806353156f281461034557806354fd4d50146103405780635c60da1b1461033b5780635cfc1a511461033657806360d60e6e1461033157806370a08231146102c357806372b410a81461032c578063754c38881461032757806376b58b90146103225780637ecebe001461031d5780637fd6f15c1461031857806383d430d5146103135780638697d2c21461030e5780638ceab9aa146103095780639267842a1461030457806395d89b41146102ff578063a49a1e7d146102fa578063a9059cbb146102f5578063ac9650d8146102f0578063ad3cb1cc146102eb578063b1f0e7c7146102e6578063c6e6f592146102e1578063d505accf146102dc578063d83ad00c146102d7578063dd62ed3e146102d2578063e74b981b146102cd578063ee3bd5df146102c8578063f04da65b146102c3578063f6a6830f146102be578063f851a440146102b9578063f9609f08146102b45763f98f5b920361000e57612570565b612558565b612530565b6124ef565b6117c9565b6124c9565b61249c565b612458565b61240d565b6121f8565b6121cf565b6121b5565b612170565b61210b565b61206a565b612018565b611f74565b611d80565b611d28565b611b7d565b6119ad565b611989565b61194e565b6118fd565b611891565b611804565b611729565b61170f565b6116db565b6116c0565b61169c565b611633565b6113ae565b6112c8565b6112a0565b611193565b6110cd565b610908565b61105e565b611044565b61100a565b610fde565b610fc3565b610fa9565b610b18565b610a3c565b610a13565b6109f0565b610994565b61092e565b6108d6565b61082a565b61080c565b610746565b61048d565b61045c565b6103ef565b6001600160a01b038116036103dd57565b5f80fd5b908160809103126103dd5790565b60803660031901126103dd57600435610407816103cc565b604435610413816103cc565b606435906001600160401b0382116103dd5760209261044161043c61044a9436906004016103e1565b612708565b602435906127f5565b604051908152f35b5f9103126103dd57565b346103dd575f3660031901126103dd57602060cf5460801c604051908152f35b6001600160801b038116036103dd57565b346103dd5760203660031901126103dd576004356104aa8161047c565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561062c575f916105fd575b50335f90815261016e60205260409020610526906125b7565b916001600160801b0361054084516001600160801b031690565b16156105eb57610599836105566105e795612e2d565b6105806105738461056e84516001600160801b031690565b612608565b6001600160801b03168252565b335f90815261016e60205260409020612621565b612621565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61061f915060203d602011610625575b61061781836106cb565b81019061259d565b5f61050d565b503d61060d565b6125ac565b90600182811c9216801561065f575b602083101461064b57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610640565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761069857604052565b610669565b6001600160401b03811161069857604052565b608081019081106001600160401b0382111761069857604052565b90601f801991011681019081106001600160401b0382111761069857604052565b5f5b8381106106fd5750505f910152565b81810151838201526020016106ee565b90602091610726815180928185528580860191016106ec565b601f01601f1916010190565b90602061074392818152019061070d565b90565b346103dd575f3660031901126103dd576040515f805461076581610631565b808452906020906001908181169081156107e2575060011461079e575b6105e785610792818703826106cb565b60405191829182610732565b5f80805293505f805160206159758339815191525b8385106107cf57505050508101602001610792826105e7610782565b80548686018401529382019381016107b3565b8695506105e79693506020925061079294915060ff191682840152151560051b8201019293610782565b346103dd5760203660031901126103dd57602061044a60043561264a565b346103dd5760403660031901126103dd57600435610847816103cc565b6001600160a01b038116906024359082156108ba576108828291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b801515036103dd57565b346103dd5760403660031901126103dd576100206004356108f6816103cc565b60243590610903826108cc565b612670565b346103dd575f3660031901126103dd5760206001600160801b0360cf5416604051908152f35b60603660031901126103dd57600435610946816103cc565b602435610952816103cc565b604435906001600160401b0382116103dd5760209261097b61043c61044a9436906004016103e1565b61098433613464565b61098d81613464565b34906145ea565b346103dd5760203660031901126103dd576004356001600160401b0381116103dd5761043c6100209136906004016103e1565b60609060031901126103dd576004356109df816103cc565b9060243590604435610743816103cc565b346103dd57602061044a610a03366109c7565b91610a0d33613464565b336146b1565b346103dd575f3660031901126103dd5761026a546040516001600160a01b039091168152602090f35b346103dd5760603660031901126103dd57600435610a59816103cc565b60243590610a66826103cc565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610ab6575b610aaa84610aa5858883614945565b613486565b60405160018152602090f35b919093818503948511610aea575f928352600260209081526040808520338652909152909220939093559180610aaa610a96565b6125dc565b60609060031901126103dd5760043590602435610b0b816103cc565b90604435610743816103cc565b346103dd57610b2636610aef565b906001600160a01b03808316156108ba57610b3f613deb565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103dd5760408051631d8557d760e01b815260049491905f81878183875af1801561062c57610f90575b506001600160a01b0383165f90815261016e60205260409020610bb2906125b7565b6001600160801b039283610bcd83516001600160801b031690565b1615610f8057610bdc82612e2d565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561062c575f98610f4f575b50602097888101956001600160401b03918280610c558a516001600160401b031690565b1614610f3f57908c92918751918c8380610c816303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561062c57610cad938e5f94610f1a575b5050516001600160801b03165b1690612f5c565b96610cd1610ccb8a60018060a01b03165f5260d360205260405f2090565b5461264a565b928389118015610f0a575b610efa57908b610d1a9392610cf889516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561062c57670de0b6b3a764000094610d69948e5f95610ecd575b5050610d5b610d4d610d6192612bce565b93516001600160401b031690565b93612bce565b921690612fd0565b1015610ebf578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561062c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610e9c95610e1393610ea1575b5050610df6610573610de68c61431d565b83516001600160801b0316612608565b6001600160a01b0386165f90815261016e60205260409020612621565b610e1c826143ea565b90610e5b610e40610e2c8561431d565b60cf5460801c5b036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610e65828661537c565b610e6f8389614350565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610eb792903d106106255761061781836106cb565b505f80610dd5565b835163185cfc6d60e11b8152fd5b610d61929550610ef0610d5b9282610d4d93903d106106255761061781836106cb565b959250508e610d3c565b875163efda1a2760e01b81528590fd5b50610f1361274f565b8911610cdc565b610ca69294509081610f3792903d106106255761061781836106cb565b92908e610c99565b8651630709133160e01b81528490fd5b610f7291985060603d606011610f79575b610f6a81836106cb565b810190613531565b965f610c31565b503d610f60565b825163673f032f60e11b81528790fd5b80610f9d610fa39261069d565b80610452565b5f610b90565b346103dd575f3660031901126103dd57602061044a61274f565b346103dd575f3660031901126103dd57602060405160128152f35b346103dd575f3660031901126103dd576020610ff8612785565b6040516001600160a01b039091168152f35b346103dd575f3660031901126103dd5760206040517f3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d8152f35b346103dd575f3660031901126103dd57602061044a6127c0565b602061044a61106c366109c7565b916127f5565b9181601f840112156103dd578235916001600160401b0383116103dd57602083818601950101116103dd57565b60206003198201126103dd57600435906001600160401b0382116103dd576110c991600401611072565b9091565b6110d63661109f565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c16801561117f575b61116d57680100000000000000036111309368ffffffffffffffffff1916178455612900565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b038416101561110a565b346103dd576111a136610aef565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561062c5782915f91611271575b5016330361125f5781610e9c61122c86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd39661358b565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611293915060203d602011611299575b61128b81836106cb565b810190612822565b5f6111f4565b503d611281565b346103dd575f3660031901126103dd57609c546040516001600160a01b039091168152602090f35b346103dd5760203660031901126103dd576004356112e5816103cc565b60018060a01b03165f5261016e602052602060405f20604051906113088261067d565b54906001600160801b03918281169081835260801c84830152611330575b5116604051908152f35b61133981612e2d565b611326565b6040519060a082018281106001600160401b0382111761069857604052565b6001600160401b03811161069857601f01601f191660200190565b9291926113848261135d565b9161139260405193846106cb565b8294818452818301116103dd578281602093845f960137010152565b6040806003193601126103dd5760049081356113c9816103cc565b6024356001600160401b0381116103dd57366023820112156103dd576113f89036906024818701359101611378565b91611401613bbe565b8051926114388461142a60209363439fab9160e01b85840152846024840152604483019061070d565b03601f1981018652856106cb565b611440613bbe565b611448613c17565b6001600160a01b038381168015929190879084156115fe575b8415611590575b841561152d575b50508215611497575b5050611488576100208383614dc2565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561062c575f92611500575b5050155f80611478565b61151f9250803d10611526575b61151781836106cb565b8101906129de565b5f806114f6565b503d61150d565b855163054fd4d560e41b81529294508391839182905afa90811561062c57879160ff915f91611563575b5016141591865f61146f565b6115839150843d8611611589575b61157b81836106cb565b810190614dad565b5f611557565b503d611571565b935050835163198ca60560e11b815282818981875afa90811561062c5788917f3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d915f916115e1575b50141593611468565b6115f89150853d87116106255761061781836106cb565b5f6115d8565b5f805160206159b583398151915254909450849061162c906001600160a01b03165b6001600160a01b031690565b1493611461565b346103dd575f3660031901126103dd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361168a5760206040515f805160206159b58339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126103dd576001600160a01b036116b7612785565b16330361125f57005b346103dd575f3660031901126103dd57602060405160038152f35b346103dd575f3660031901126103dd575f805160206159b5833981519152546040516001600160a01b039091168152602090f35b346103dd575f3660031901126103dd57602061044a6129d0565b346103dd5760203660031901126103dd5760d180549081905f6004355b8482106117775750505081101561176c576105e7905b6040519081529081906020820190565b506105e75f1961175c565b909193808316906001818518811c8301809311610aea575f8790525f805160206159f58339815191528301546001600160a01b03168410156117be575050935b9190611746565b9095910192506117b7565b346103dd5760203660031901126103dd576004356117e6816103cc565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561062c576020915f91611874575b506040519015158152f35b61188b9150823d84116115265761151781836106cb565b5f611869565b346103dd5760203660031901126103dd576004356118ae816103cc565b6118b6613c17565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103dd5760803660031901126103dd576105e7611931600435611920816103cc565b606435906044359060243590612a00565b604080519384526020840192909252908201529081906060820190565b346103dd5760203660031901126103dd5760043561196b816103cc565b60018060a01b03165f526003602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57602061ffff609c5460a01c16604051908152f35b346103dd576003196040368201126103dd5760049081356001600160401b038082116103dd5760a08285019383360301126103dd576024359081116103dd576119f99036908501611072565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103dd5760405163837d444160e01b8152905f908290818381611a4c8c828f01612ae2565b03925af1801561062c57611b6a575b50611a64613deb565b611a6c612de3565b9081163314159182611b3b575b50509050611b2a576044019160b0611a918484612b60565b90500480158015611b12575b611b0257611ab2611aac61274f565b91612bb5565b11611af3575060b0611ac48383612b60565b9050145f14611ae05761002091611ada91612b60565b9061420a565b61002091611aed91612b60565b906140e2565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611b1d8484612b60565b905060b082021415611a9d565b604051634ca8886760e01b81528390fd5b611b5e9250611b58611b6294611b5088613e76565b923691611378565b91613f51565b1590565b805f80611a79565b80610f9d611b779261069d565b5f611a5b565b346103dd5760603660031901126103dd57600435602435611ba2604435828433612a00565b9192611bce7f000000000000000000000000000000000000000000000000000000000000000082612beb565b42108015611d20575b8015611d18575b611d06577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611c39611c1e611c138661431d565b60d05460801c612608565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611c7d9190611c6c6080826106cb565b5190205f5260d260205260405f2090565b555f9360018311611cb6575b50505050611c978233614350565b604080519485526020850191909152830152339180606081015b0390a2005b611cfc92939450611cc79088612beb565b60408051336020820190815291810193909352606083018290529094909190611c6c9082608081015b039081018352826106cb565b555f808080611c89565b604051630e3d8e8d60e11b8152600490fd5b508215611bde565b508115611bd7565b346103dd5760403660031901126103dd576020600435611d54602435611d4d816103cc565b8233614faf565b90611d5e33613486565b60405190815230905f805160206159d5833981519152843392a3604051908152f35b346103dd5760203660031901126103dd57600435611d9c613deb565b335f90815261016e60205260409020611db4906125b7565b6001600160801b0380611dce83516001600160801b031690565b16156105eb578290611ddf83612e2d565b82516001600160801b03161610611f6257335f90815260d3602052604090205482611e20611e1484516001600160801b031690565b6001600160801b031690565b14611f4c57611e449083611e3e611e1485516001600160801b031690565b91612fd0565b91611e71611e64611e548361431d565b84516001600160801b0316610e33565b6001600160801b03168352565b335f90815261016e60205260409020611e8b908390612621565b611ed36020611ec460018060a01b037f000000000000000000000000000000000000000000000000000000000000000016809633614faf565b9301516001600160801b031690565b833b156103dd5760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af191821561062c576105e792611f39575b506040519081529081906020820190565b80610f9d611f469261069d565b5f611f28565b335f90815261016e602052604081205591611e8b565b604051636edcc52360e01b8152600490fd5b346103dd575f3660031901126103dd576040515f60018054611f9581610631565b80855291602091600181169081156107e25750600114611fbf576105e785610792818703826106cb565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851061200557505050508101602001610792826105e7610782565b8054868601840152938201938101611fe9565b346103dd57611cb17f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61204a3661109f565b9290612054613c17565b6040519182916020835233956020840191612ac2565b346103dd5760403660031901126103dd5761209460043561208a816103cc565b6024359033614945565b61209d33613486565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120dd5750505050505090565b90919293949584806120fb600193603f198682030187528a5161070d565b98019301930191949392906120cd565b346103dd5760203660031901126103dd576001600160401b036004358181116103dd57366023820112156103dd5780600401359182116103dd573660248360051b830101116103dd576105e79160246121649201612d36565b604051918291826120a8565b346103dd575f3660031901126103dd576105e760405161218f8161067d565b60058152640352e302e360dc1b602082015260405191829160208352602083019061070d565b346103dd575f3660031901126103dd576020610ff8612de3565b346103dd5760203660031901126103dd57602061044a6004356143ea565b60ff8116036103dd57565b346103dd5760e03660031901126103dd57600435612215816103cc565b602435612221816103cc565b604435906064359260843590612236826121ed565b6001600160a01b038381169590929086156108ba574281106123fb576020915f91611cf061232989878a6122ec61226b6127c0565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b0391612300601f19938481018352826106cb565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa1561062c575f519282841680159081156123ee575b506123dc576123c985916123b47f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610e9c565b6040516323389ba560e21b8152600490fd5b905083831614155f61236f565b604051631ab7da6b60e01b8152600490fd5b346103dd575f3660031901126103dd5760206001600160801b0360d05416604051908152f35b60409060031901126103dd5760043561244b816103cc565b90602435610743816103cc565b346103dd57602061249361246b36612433565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346103dd5760203660031901126103dd576100206004356124bc816103cc565b6124c4613c17565b614479565b346103dd575f3660031901126103dd5760206001600160801b0360d55416604051908152f35b346103dd5760203660031901126103dd5760043561250c816103cc565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b346103dd575f3660031901126103dd576037546040516001600160a01b039091168152602090f35b602061044a61256636612433565b9061098433613464565b346103dd5760203660031901126103dd57610020600435612590816103cc565b612598613c17565b6144db565b908160209103126103dd575190565b6040513d5f823e3d90fd5b906040516125c48161067d565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f190191908211610aea57565b6001600160801b039182169082160391908211610aea57565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161266257505090565b916107439260801c90612fd0565b61026a546001600160a01b0391908216330361125f576001600160a01b0381165f90815261026b60205260409020549215159260ff1615158314612703576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b61271461271b91613138565b91906132ce565b61272157565b6127296151ca565b80612732575b50565b5f906040519081525f805160206159d583398151915260203092a3565b4760d0546001600160801b0361276681831661264a565b9060d55416019060801c01908181115f1461277f570390565b50505f90565b6101a1546001600160a01b0316801561279b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036127ed5760045490565b6107436138a4565b90610743929161280433613464565b61280d33613464565b6128188334336145ea565b50610a0d33613464565b908160209103126103dd5751610743816103cc565b359061ffff821682036103dd57565b9080601f830112156103dd5781602061074393359101611378565b906020828203126103dd5781356001600160401b03928382116103dd57019060a0828203126103dd5761289261133e565b92823584526128a360208401612837565b602085015260408301358181116103dd57826128c0918501612846565b604085015260608301358181116103dd57826128dd918501612846565b606085015260808301359081116103dd576128f89201612846565b608082015290565b6037549091906001600160a01b03166129c65760405163e7f6f22560e01b8152906020908183600481335afa92831561062c575f936129a7575b50604051636f4fa30f60e01b8152938285600481335afa90811561062c576129829561297d945f93612984575b50506129769192810190612861565b9083613af2565b613bb2565b565b612976935090816129a092903d106112995761128b81836106cb565b915f612967565b6129bf919350823d84116112995761128b81836106cb565b915f61293a565b50506129826139ca565b60d4548061074357505f1990565b908160209103126103dd5751610743816108cc565b91908203918211610aea57565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612a3e81608081015b03601f1981018352826106cb565b5190205f5260d260205260405f2054918215612a6e57612a5f918391613c50565b9091828103908111610aea5792565b5050505f905f905f90565b9035601e19823603018112156103dd5701602081359101916001600160401b0382116103dd5781360383136103dd57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061074392602081528235602082015260208301356040820152612b1e612b0e6040850185612a79565b84606085015260c0840191612ac2565b90612b51612b46612b326060870187612a79565b601f19858703810160808701529591612ac2565b946080810190612a79565b93909282860301910152612ac2565b903590601e19813603018212156103dd57018035906001600160401b0382116103dd576020019181360383136103dd57565b634e487b7160e01b5f52601260045260245ffd5b8115612bb0570490565b612b92565b906801bc16d674ec8000009180830292830403610aea57565b90670de0b6b3a764000091828102928184041490151715610aea57565b91908201809211610aea57565b6001600160401b0381116106985760051b60200190565b90612c1982612bf8565b612c2660405191826106cb565b8281528092612c37601f1991612bf8565b01905f5b828110612c4757505050565b806060602080938501015201612c3b565b634e487b7160e01b5f52603260045260245ffd5b90821015612c83576110c99160051b810190612b60565b612c58565b908092918237015f815290565b3d15612cbf573d90612ca68261135d565b91612cb460405193846106cb565b82523d5f602084013e565b606090565b6020818303126103dd578051906001600160401b0382116103dd570181601f820112156103dd578051612cf68161135d565b92612d0460405194856106cb565b818452602082840101116103dd5761074391602080850191016106ec565b8051821015612c835760209160051b010190565b919091612d4283612c0f565b925f5b818110612d5157505050565b5f80612d5e838587612c6c565b60409391612d70855180938193612c88565b0390305af490612d7e612c95565b9115612da5575090600191612d938288612d22565b52612d9e8187612d22565b5001612d45565b9060448151106103dd57612ddf612dca60049283810151602480918301019101612cc4565b925162461bcd60e51b81529283928301610732565b0390fd5b610109546001600160a01b03168061074357507f000000000000000000000000000000000000000000000000000000000000000090565b612e2333613464565b61272f3433614522565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91612ec3575b5060208201916001600160801b03918284511691828214612ebc5783612eaf612eaa612eb7958584865116612fd0565b61431d565b16905261431d565b169052565b5050505050565b612edc915060203d6020116106255761061781836106cb565b5f612e7a565b90808202905f1981840990828083109203918083039214612f51576127109082821115612f3f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612fbf57670de0b6b3a76400009082821115612f3f577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146130435784831115612f3f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107439250612ba6565b908160609103126103dd5780519160406020830151920151610743816108cc565b81835290916001600160fb1b0383116103dd5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036103dd57604083015260408101356130c4816103cc565b6001600160a01b031660608381019190915281013536829003601e19018112156103dd5701602081359101906001600160401b0381116103dd578060051b360382136103dd5760a0836080806107439601520191613071565b9190915f8382019384129112908015821691151617610aea57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906131639060048301613095565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561062c575f915f905f95613289575b50841561323657816131ad612785565b16917f000000000000000000000000000000000000000000000000000000000000000016821461322f57509060205f92600460405180958193634641257d60e01b83525af190811561062c5761320a925f9261320e575b5061311d565b9190565b61322891925060203d6020116106255761061781836106cb565b905f613204565b908161323c575b50509190565b803b156103dd57604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561062c57613276575b80613236565b80610f9d6132839261069d565b5f613270565b919450506132af915060603d6060116132b7575b6132a781836106cb565b810190613050565b93905f61319d565b503d61329d565b600160ff1b8114610aea575f0390565b801561272f576132e3611e1460cf5460801c90565b5f82126133b557816132f491612beb565b90613301610e408361431d565b613316609c549161ffff8360a01c1690612ee2565b801561270357807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613354611e1460cf546001600160801b031690565b8061339f57505061339a90925b6001600160a01b0316916133758484615162565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b61339a926133af92039084612fd0565b92613361565b906133bf906132be565b6133d4611e1460d5546001600160801b031690565b806133f4575b50806133e4575050565b612eaa610e4091612982936129f3565b9061345b7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161175c61343f61343461342d8888612beb565b8785612fd0565b80809403960361431d565b6001600160801b03166001600160801b031960d554161760d555565b0390a15f6133da565b6001600160a01b03165f90815261026b602052604090205460ff161561125f57565b60018060a01b0381165f5261016e60205260405f2090604051916134a98361067d565b54906001600160801b03918281169081855260801c602085015215612703576134fc610ccb613501926134da613deb565b6134e386612e2d565b6001600160a01b03165f90815260d36020526040902090565b6149d3565b9151161161350b57565b604051633684c65960e01b8152600490fd5b51906001600160401b03821682036103dd57565b908160609103126103dd5760405190606082018281106001600160401b0382111761069857613583916040918252805161356a8161047c565b84526135786020820161351d565b60208501520161351d565b604082015290565b92906001600160a01b0390818116156108ba576135a6613deb565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156103dd57604094855193631d8557d760e01b85526004945f81878183895af1801561062c57613891575b506001600160a01b0388165f90815261016e60205260409020613619906125b7565b906001600160801b0361363383516001600160801b031690565b16156138815761364282612e2d565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561062c57613862575b508651936303d1689d60e11b978886526020918287806136bc888c83019190602083019252565b0381845afa96871561062c575f97613843575b5086996136ef610ccb8d60018060a01b03165f5260d360205260405f2090565b88118015613833575b6138235790836137359261371387516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561062c575f8594889461377a9c613806575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561062c57610de66137c1946137a493610573936129829a6137e8575b505061431d565b6001600160a01b0388165f90815261016e60205260409020612621565b6137e36137cd836143ea565b80976137de610e40610e2c8761431d565b61537c565b614350565b816137fe92903d106106255761061781836106cb565b505f8061379d565b61381c90873d89116106255761061781836106cb565b505f61374f565b825163efda1a2760e01b81528990fd5b5061383c61274f565b88116136f8565b61385b919750833d85116106255761061781836106cb565b955f6136cf565b61387a9060603d606011610f7957610f6a81836106cb565b505f613695565b875163673f032f60e11b81528690fd5b80610f9d61389e9261069d565b5f6135f7565b6040515f905f54906138b582610631565b9283825260209384830193600190866001821691825f146139aa575050600114613967575b505091816138f061396193612a309503826106cb565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f805160206159758339815191525b82841061399557505050820101816138f06138da565b8054868501860152879490930192810161397f565b60ff1916875292151560051b850190920192508391506138f090506138da565b6139d2614aff565b6139e7611e1460d0546001600160801b031690565b60018111613ae057600114613a5b575b60d654613a0261557c565b90808210613a1e575b5050613a165f60d655565b612982614add565b5f8051602061599583398151915291613a519103613a3b816154a7565b604080519182525f602083015290918291820190565b0390a15f80613a0b565b613a94613a78613a7360cf546001600160801b031690565b6125f0565b6001600160801b03166001600160801b031960cf54161760cf55565b613aa96001600160801b031960d0541660d055565b613ab1615445565b5f8051602061599583398151915260405180613ad881905f60206040840193600181520152565b0390a16139f7565b604051630299325160e41b8152600490fd5b9190613afc614aff565b608082015190613b0a614aff565b6001600160a01b03841680156108ba57613baa94613b9a93613b83926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613b713394602083019061070d565b0390a2602085015161ffff1690614b40565b613b8d8351614b91565b613b95614bc1565b614bee565b6060604082015191015190614c1d565b612982614d4a565b61298290612598614aff565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613bfc575b505061168a57565b5f805160206159b58339815191525416141590505f80613bf4565b6037546001600160a01b0316330361125f57565b90604051613c388161067d565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590613de3575b613dd65783613da0575f5b60d15f526001600160a01b0316613c955f805160206159f58339815191528601613c2b565b8051909790613cac906001600160a01b0316611620565b98613cd1613cc56020809b01516001600160601b031690565b6001600160601b031690565b948381108015613d96575b613d845791600193979a95613cfb613d07939488035b838c0390614e6d565b80920198870391612fd0565b01970193808611801590613d7a575b613d6f5760d15f528290613d385f805160206159f58339815191528701613c2b565b805190890151969992966001600160a01b039091169460019392613d079290916001600160601b0390911690613cfb908803613cf2565b945050509250509190565b5081851015613d16565b60405163e8722f8f60e01b8152600490fd5b50808b1115613cdc565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316613c70565b505093505050505f905f90565b508415613c65565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91613e57575b50613e4557565b60405163e775715160e01b8152600490fd5b613e70915060203d6020116115265761151781836106cb565b5f613e3e565b604290467f000000000000000000000000000000000000000000000000000000000000000003613f255761010a54905b613ebd613eb66040830183612b60565b3691611378565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613f08816106b0565b5190206040519161190160f01b8352600283015260228201522090565b613f2d614e7f565b90613ea6565b60041115613f3d57565b634e487b7160e01b5f52602160045260245ffd5b613f5b8383614f4c565b50613f6881959295613f33565b159384614004575b508315613f7e575b50505090565b5f929350908291604051613fb681612a306020820194630b135d3f60e11b998a8752602484015260406044840152606483019061070d565b51915afa90613fc3612c95565b82613ff6575b82613fd9575b50505f8080613f78565b613fee9192506020808251830101910161259d565b145f80613fcf565b915060208251101591613fc9565b6001600160a01b0383811691161493505f613f70565b906030116103dd5790603090565b906090116103dd5760300190606090565b9060b0116103dd5760900190602090565b909392938483116103dd5784116103dd578101920390565b359060208110614070575090565b5f199060200360031b1b1690565b969594906140bb9361409f6140ad926060979560808c5260808c0191612ac2565b9089820360208b015261070d565b918783036040890152612ac2565b930152565b906020610743928181520190612aaa565b916020610743938181520191612ac2565b60b091828104915f90816140f4614f86565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b87841061413657505050505050505050565b8261414591018092888761404a565b90614150828261401a565b9161416f6141696141618684614028565b969093614039565b90614062565b90893b156103dd575f908d61419c604094855198899485946304512a2360e31b86528a8a6004880161407e565b03816801bc16d674ec8000008d5af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1946141e8926141f7575b5051928392836140d1565b0390a160018193019290614124565b80610f9d6142049261069d565b5f6141dd565b816030116103dd57614169917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614248614f86565b9061425f6142568486614028565b96909486614039565b94813b156103dd576801bc16d674ec8000005f946142c597604051988996879586946304512a2360e31b8652608060048701526142b66142a38d6084890190612aaa565b60031994858983030160248a015261070d565b92868403016044870152612ac2565b90606483015203925af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19261339a9261430e575b50604051918291826140c0565b6143179061069d565b5f614301565b6001600160801b0390818111614331571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146143d857600283558147106143c0575f918291829182916001600160a01b03165af16143a2612c95565b50156143ae5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614419575b1561440c5750905090565b6107439260801c91612fd0565b508015614401565b60cf546001600160801b0381169082158015614471575b1561444257505090565b60801c90614451828285612fd0565b928215612bb057096144605790565b6001810180911115610743576125dc565b508115614438565b614481613deb565b6001600160a01b031680156144c957609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b919061452c613deb565b6001600160a01b0383169081156108ba5780156145d85780614553611e1460cf5460801c90565b019361455d6129d0565b85116145c657610e40946145849161457f61457785614421565b97889361431d565b615162565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926145f6613deb565b6001600160a01b0382169182156108ba5781156145d8578161461d611e1460cf5460801c90565b016146266129d0565b81116145c657610e409561466d6145c1927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461457f61466588614421565b9a8b9361431d565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b9190916001600160801b0380809416911601918211610aea57565b93929190916146be61535b565b6146c6613deb565b6001600160a01b0385165f90815261016e602052604090206146e7906125b7565b946001600160801b0361470187516001600160801b031690565b16156148b65761471086612e2d565b6001600160a01b0381165f90815260d360205260409020614734906134fc90610ccb565b955f198414614886575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af195861561062c575f96614865575b5085986147d06147c36147b38461431d565b86516001600160801b0316614696565b6001600160801b03168552565b6147e4611e1485516001600160801b031690565b1161350b577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e589561482d614860946105948760018060a01b03165f5261016e60205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b61487f91965060203d6020116106255761061781836106cb565b945f6147a1565b925061489c611e1484516001600160801b031690565b808711156148ac5786039261473e565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c5761492191614911915f91614926575b5061431d565b6001600160801b03166020880152565b614710565b61493f915060203d6020116106255761061781836106cb565b5f61490b565b9061494f82613464565b61495881613464565b6001600160a01b0391821691821580156149c9575b6108ba57825f5260d360205260405f2090815492858403938411610aea575f805160206159d583398151915293602093556149b88160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b508082161561496d565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561062c57614a6e936001600160401b03610ca66040614a4d946020975f91614abe575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561062c575f91614aa5575090565b610743915060203d6020116106255761061781836106cb565b614ad7915060603d606011610f7957610f6a81836106cb565b5f614a3e565b614ae5614aff565b614aed614e7f565b61010a80548203614afc575050565b55565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614b2e57565b604051631afcd79f60e31b8152600490fd5b614b48614aff565b61271061ffff831611614b7f57614b5e90614479565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614b99614aff565b8015614baf5760018101614baa5750565b60d455565b6040516331278a8760e01b8152600490fd5b614bc9614aff565b6801bc16d674ec800000614bdb6129d0565b10614baf57614be8614e7f565b61010a55565b614bf6614aff565b6001600160a01b031680614c075750565b6101a180546001600160a01b0319169091179055565b614c25614aff565b601e8151118015614d3f575b614d2d57614c3d614aff565b8051906001600160401b03821161069857614c6182614c5c5f54610631565b6155be565b602090816001601f851114614cb957509180614c9792614c9e95945f92614cae575b50508160011b915f199060031b1c19161790565b5f55615688565b612982614ca96138a4565b600455565b015190505f80614c83565b5f80529190601f1984165f80516020615975833981519152935f905b828210614d15575050916001939185614c9e97969410614cfd575b505050811b015f55615688565b01515f1960f88460031b161c191690555f8080614cf0565b80600186978294978701518155019601940190614cd5565b604051632d3f993760e21b8152600490fd5b50600a825111614c31565b614d52614aff565b614d5a614aff565b614d62614aff565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614d9b5761272f3430614522565b60405163ea2559bb60e01b8152600490fd5b908160209103126103dd5751610743816121ed565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614e4c575b50614e1257604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206159b58339815191528403614e3357612982929350615766565b604051632a87526960e21b815260048101859052602490fd5b614e6691955060203d6020116106255761061781836106cb565b935f614dec565b9080821015614e7a575090565b905090565b6e5661756c7456616c696461746f727360881b6020604051614ea08161067d565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176106985760405251902090565b8151919060418303614f7c57614f759250602082015190606060408401519301515f1a90615808565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c820152602081526107438161067d565b9291908015611f62576001600160a01b038281169283156108ba57614fd5611b5e61589c565b6150de5790611c6c956150c26150a6857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161507b615020611e1460d0546001600160801b031690565b92612a3061504d8561504861503361557c565b615042611e1460d55460801c90565b90612beb565b612beb565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f90815260d36020526040902061509e8382546129f3565b90550161431d565b6001600160801b03166001600160801b031960d054161760d055565b60408051888152602081019590955291169290819081016145c1565b9293946150ea8361264a565b9384156145d8577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361513f8661515a93615135610e4061512a8461431d565b60cf5460801c612608565b6137e3848761537c565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b5f805160206159d583398151915260205f9261517d8561431d565b60cf54906151956001600160801b0391828416614696565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b6151e3476151dd611e1460d05460801c90565b906129f3565b9081156153565760d5546001600160801b03811690816152de575b5050615215611e1460d0546001600160801b031690565b91821580156152d6575b6152d057615236906152308461264a565b90614e6d565b80156152d057615245816143ea565b9283156152c95761512a612982926152666150a6612eaa88610e40966129f3565b615280611c1e6152758361431d565b60d05460801c614696565b61528a81876154f2565b60408051878152602081018390525f805160206159958339815191529190a1612eaa613a786152b88861431d565b60cf546001600160801b0316612608565b505f925050565b505f9150565b50801561521f565b81849294106152c95761527584615326935f8051602061599583398151915282611c1e9560801c61530f82826154f2565b604080519182526020820192909252a1039461431d565b61533a6001600160801b0360d5541660d555565b61534f6001600160801b031960d5541660d555565b5f806151fe565b5f9150565b61536361589c565b1561536a57565b604051630a62fbdb60e11b8152600490fd5b6001600160a01b03165f81815260d360205260409020805483810391908211610aea575f935f805160206159d583398151915292602092556153bd8161431d565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b60d154906801000000000000000082101561069857600182018060d155821015612c835760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206159f583398151915290910155565b61544d61557c565b60018101809111610aea576001600160a01b03808211615487579061298291604051916154798361067d565b1681525f60208201526153e7565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b80156154e0576154b561557c565b908101809111610aea576001600160a01b03808211615487579061298291604051916154798361067d565b604051632ec8835b60e21b8152600490fd5b91909180156154e05761550361557c565b908101809111610aea576001600160a01b03808211615487576001600160601b039081851161555c5790612982939461555792604051946155438661067d565b168452166001600160601b03166020830152565b6153e7565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60d1548061558957505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316611620565b601f81116155ca575050565b5f80525f80516020615975833981519152906020601f840160051c8301931061560d575b601f0160051c01905b818110615602575050565b5f81556001016155f7565b90915081906155ee565b90601f8211615624575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931061567e575b601f0160051c01905b81811061567457505050565b5f81558201615668565b909150819061565f565b9081516001600160401b038111610698576001906156af816156aa8454610631565b615617565b602080601f83116001146156e4575081906156e09394955f92614cae5750508160011b915f199060031b1c19161790565b9055565b90601f1983169561571660015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061574f5750508385969710615737575b505050811b019055565b01515f1960f88460031b161c191690555f808061572d565b80878596829496860151815501950193019061571a565b90813b156157e7575f805160206159b583398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156157cc5761272f9161590b565b5050346157d557565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161589157906158616020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561062c575f516001600160a01b0381161561588757905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f916158f2575090565b610743915060203d6020116115265761151781836106cb565b5f8061074393602081519101845af4615922612c95565b919061593857508051156143ae57805190602001fd5b8151158061596b575b615949575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561594156fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a26469706673582212201629caca5f73ed443a1870106ce3ecbfbc91dfd1616c7659127690242718758e64736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612e1a565b005b5f3560e01c806301d523b6146103c757806301e1d114146103c2578063066055e0146103bd57806306fdde03146103b857806307a2d13a146103b3578063095ea7b3146103ae5780630d392cd9146103a957806318160ddd1461036857806318f72950146103a45780631a7ff5531461039f578063201b9eb51461039a57806322758a4a1461039557806323b872dd146103905780632999ad3f1461038b5780632cdf740114610386578063313ce567146103815780633229fa951461037c57806333194c0a146103775780633644e5151461037257806336fe59d21461036d5780633a98ef3914610368578063439fab911461036357806343e82a791461035e57806346904840146103595780634ec96b22146103545780634f1ef2861461034f57806352d1902d1461034a57806353156f281461034557806354fd4d50146103405780635c60da1b1461033b5780635cfc1a511461033657806360d60e6e1461033157806370a08231146102c357806372b410a81461032c578063754c38881461032757806376b58b90146103225780637ecebe001461031d5780637fd6f15c1461031857806383d430d5146103135780638697d2c21461030e5780638ceab9aa146103095780639267842a1461030457806395d89b41146102ff578063a49a1e7d146102fa578063a9059cbb146102f5578063ac9650d8146102f0578063ad3cb1cc146102eb578063b1f0e7c7146102e6578063c6e6f592146102e1578063d505accf146102dc578063d83ad00c146102d7578063dd62ed3e146102d2578063e74b981b146102cd578063ee3bd5df146102c8578063f04da65b146102c3578063f6a6830f146102be578063f851a440146102b9578063f9609f08146102b45763f98f5b920361000e57612570565b612558565b612530565b6124ef565b6117c9565b6124c9565b61249c565b612458565b61240d565b6121f8565b6121cf565b6121b5565b612170565b61210b565b61206a565b612018565b611f74565b611d80565b611d28565b611b7d565b6119ad565b611989565b61194e565b6118fd565b611891565b611804565b611729565b61170f565b6116db565b6116c0565b61169c565b611633565b6113ae565b6112c8565b6112a0565b611193565b6110cd565b610908565b61105e565b611044565b61100a565b610fde565b610fc3565b610fa9565b610b18565b610a3c565b610a13565b6109f0565b610994565b61092e565b6108d6565b61082a565b61080c565b610746565b61048d565b61045c565b6103ef565b6001600160a01b038116036103dd57565b5f80fd5b908160809103126103dd5790565b60803660031901126103dd57600435610407816103cc565b604435610413816103cc565b606435906001600160401b0382116103dd5760209261044161043c61044a9436906004016103e1565b612708565b602435906127f5565b604051908152f35b5f9103126103dd57565b346103dd575f3660031901126103dd57602060cf5460801c604051908152f35b6001600160801b038116036103dd57565b346103dd5760203660031901126103dd576004356104aa8161047c565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561062c575f916105fd575b50335f90815261016e60205260409020610526906125b7565b916001600160801b0361054084516001600160801b031690565b16156105eb57610599836105566105e795612e2d565b6105806105738461056e84516001600160801b031690565b612608565b6001600160801b03168252565b335f90815261016e60205260409020612621565b612621565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61061f915060203d602011610625575b61061781836106cb565b81019061259d565b5f61050d565b503d61060d565b6125ac565b90600182811c9216801561065f575b602083101461064b57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610640565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761069857604052565b610669565b6001600160401b03811161069857604052565b608081019081106001600160401b0382111761069857604052565b90601f801991011681019081106001600160401b0382111761069857604052565b5f5b8381106106fd5750505f910152565b81810151838201526020016106ee565b90602091610726815180928185528580860191016106ec565b601f01601f1916010190565b90602061074392818152019061070d565b90565b346103dd575f3660031901126103dd576040515f805461076581610631565b808452906020906001908181169081156107e2575060011461079e575b6105e785610792818703826106cb565b60405191829182610732565b5f80805293505f805160206159758339815191525b8385106107cf57505050508101602001610792826105e7610782565b80548686018401529382019381016107b3565b8695506105e79693506020925061079294915060ff191682840152151560051b8201019293610782565b346103dd5760203660031901126103dd57602061044a60043561264a565b346103dd5760403660031901126103dd57600435610847816103cc565b6001600160a01b038116906024359082156108ba576108828291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b801515036103dd57565b346103dd5760403660031901126103dd576100206004356108f6816103cc565b60243590610903826108cc565b612670565b346103dd575f3660031901126103dd5760206001600160801b0360cf5416604051908152f35b60603660031901126103dd57600435610946816103cc565b602435610952816103cc565b604435906001600160401b0382116103dd5760209261097b61043c61044a9436906004016103e1565b61098433613464565b61098d81613464565b34906145ea565b346103dd5760203660031901126103dd576004356001600160401b0381116103dd5761043c6100209136906004016103e1565b60609060031901126103dd576004356109df816103cc565b9060243590604435610743816103cc565b346103dd57602061044a610a03366109c7565b91610a0d33613464565b336146b1565b346103dd575f3660031901126103dd5761026a546040516001600160a01b039091168152602090f35b346103dd5760603660031901126103dd57600435610a59816103cc565b60243590610a66826103cc565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610ab6575b610aaa84610aa5858883614945565b613486565b60405160018152602090f35b919093818503948511610aea575f928352600260209081526040808520338652909152909220939093559180610aaa610a96565b6125dc565b60609060031901126103dd5760043590602435610b0b816103cc565b90604435610743816103cc565b346103dd57610b2636610aef565b906001600160a01b03808316156108ba57610b3f613deb565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103dd5760408051631d8557d760e01b815260049491905f81878183875af1801561062c57610f90575b506001600160a01b0383165f90815261016e60205260409020610bb2906125b7565b6001600160801b039283610bcd83516001600160801b031690565b1615610f8057610bdc82612e2d565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561062c575f98610f4f575b50602097888101956001600160401b03918280610c558a516001600160401b031690565b1614610f3f57908c92918751918c8380610c816303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561062c57610cad938e5f94610f1a575b5050516001600160801b03165b1690612f5c565b96610cd1610ccb8a60018060a01b03165f5260d360205260405f2090565b5461264a565b928389118015610f0a575b610efa57908b610d1a9392610cf889516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561062c57670de0b6b3a764000094610d69948e5f95610ecd575b5050610d5b610d4d610d6192612bce565b93516001600160401b031690565b93612bce565b921690612fd0565b1015610ebf578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561062c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610e9c95610e1393610ea1575b5050610df6610573610de68c61431d565b83516001600160801b0316612608565b6001600160a01b0386165f90815261016e60205260409020612621565b610e1c826143ea565b90610e5b610e40610e2c8561431d565b60cf5460801c5b036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610e65828661537c565b610e6f8389614350565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610eb792903d106106255761061781836106cb565b505f80610dd5565b835163185cfc6d60e11b8152fd5b610d61929550610ef0610d5b9282610d4d93903d106106255761061781836106cb565b959250508e610d3c565b875163efda1a2760e01b81528590fd5b50610f1361274f565b8911610cdc565b610ca69294509081610f3792903d106106255761061781836106cb565b92908e610c99565b8651630709133160e01b81528490fd5b610f7291985060603d606011610f79575b610f6a81836106cb565b810190613531565b965f610c31565b503d610f60565b825163673f032f60e11b81528790fd5b80610f9d610fa39261069d565b80610452565b5f610b90565b346103dd575f3660031901126103dd57602061044a61274f565b346103dd575f3660031901126103dd57602060405160128152f35b346103dd575f3660031901126103dd576020610ff8612785565b6040516001600160a01b039091168152f35b346103dd575f3660031901126103dd5760206040517f3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d8152f35b346103dd575f3660031901126103dd57602061044a6127c0565b602061044a61106c366109c7565b916127f5565b9181601f840112156103dd578235916001600160401b0383116103dd57602083818601950101116103dd57565b60206003198201126103dd57600435906001600160401b0382116103dd576110c991600401611072565b9091565b6110d63661109f565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c16801561117f575b61116d57680100000000000000036111309368ffffffffffffffffff1916178455612900565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b038416101561110a565b346103dd576111a136610aef565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561062c5782915f91611271575b5016330361125f5781610e9c61122c86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd39661358b565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611293915060203d602011611299575b61128b81836106cb565b810190612822565b5f6111f4565b503d611281565b346103dd575f3660031901126103dd57609c546040516001600160a01b039091168152602090f35b346103dd5760203660031901126103dd576004356112e5816103cc565b60018060a01b03165f5261016e602052602060405f20604051906113088261067d565b54906001600160801b03918281169081835260801c84830152611330575b5116604051908152f35b61133981612e2d565b611326565b6040519060a082018281106001600160401b0382111761069857604052565b6001600160401b03811161069857601f01601f191660200190565b9291926113848261135d565b9161139260405193846106cb565b8294818452818301116103dd578281602093845f960137010152565b6040806003193601126103dd5760049081356113c9816103cc565b6024356001600160401b0381116103dd57366023820112156103dd576113f89036906024818701359101611378565b91611401613bbe565b8051926114388461142a60209363439fab9160e01b85840152846024840152604483019061070d565b03601f1981018652856106cb565b611440613bbe565b611448613c17565b6001600160a01b038381168015929190879084156115fe575b8415611590575b841561152d575b50508215611497575b5050611488576100208383614dc2565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561062c575f92611500575b5050155f80611478565b61151f9250803d10611526575b61151781836106cb565b8101906129de565b5f806114f6565b503d61150d565b855163054fd4d560e41b81529294508391839182905afa90811561062c57879160ff915f91611563575b5016141591865f61146f565b6115839150843d8611611589575b61157b81836106cb565b810190614dad565b5f611557565b503d611571565b935050835163198ca60560e11b815282818981875afa90811561062c5788917f3c60bf85548481aa53872c99e20f566d08c7fc12e0f05302f4002dedc8d45e4d915f916115e1575b50141593611468565b6115f89150853d87116106255761061781836106cb565b5f6115d8565b5f805160206159b583398151915254909450849061162c906001600160a01b03165b6001600160a01b031690565b1493611461565b346103dd575f3660031901126103dd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361168a5760206040515f805160206159b58339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126103dd576001600160a01b036116b7612785565b16330361125f57005b346103dd575f3660031901126103dd57602060405160038152f35b346103dd575f3660031901126103dd575f805160206159b5833981519152546040516001600160a01b039091168152602090f35b346103dd575f3660031901126103dd57602061044a6129d0565b346103dd5760203660031901126103dd5760d180549081905f6004355b8482106117775750505081101561176c576105e7905b6040519081529081906020820190565b506105e75f1961175c565b909193808316906001818518811c8301809311610aea575f8790525f805160206159f58339815191528301546001600160a01b03168410156117be575050935b9190611746565b9095910192506117b7565b346103dd5760203660031901126103dd576004356117e6816103cc565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561062c576020915f91611874575b506040519015158152f35b61188b9150823d84116115265761151781836106cb565b5f611869565b346103dd5760203660031901126103dd576004356118ae816103cc565b6118b6613c17565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103dd5760803660031901126103dd576105e7611931600435611920816103cc565b606435906044359060243590612a00565b604080519384526020840192909252908201529081906060820190565b346103dd5760203660031901126103dd5760043561196b816103cc565b60018060a01b03165f526003602052602060405f2054604051908152f35b346103dd575f3660031901126103dd57602061ffff609c5460a01c16604051908152f35b346103dd576003196040368201126103dd5760049081356001600160401b038082116103dd5760a08285019383360301126103dd576024359081116103dd576119f99036908501611072565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103dd5760405163837d444160e01b8152905f908290818381611a4c8c828f01612ae2565b03925af1801561062c57611b6a575b50611a64613deb565b611a6c612de3565b9081163314159182611b3b575b50509050611b2a576044019160b0611a918484612b60565b90500480158015611b12575b611b0257611ab2611aac61274f565b91612bb5565b11611af3575060b0611ac48383612b60565b9050145f14611ae05761002091611ada91612b60565b9061420a565b61002091611aed91612b60565b906140e2565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611b1d8484612b60565b905060b082021415611a9d565b604051634ca8886760e01b81528390fd5b611b5e9250611b58611b6294611b5088613e76565b923691611378565b91613f51565b1590565b805f80611a79565b80610f9d611b779261069d565b5f611a5b565b346103dd5760603660031901126103dd57600435602435611ba2604435828433612a00565b9192611bce7f000000000000000000000000000000000000000000000000000000000000000082612beb565b42108015611d20575b8015611d18575b611d06577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611c39611c1e611c138661431d565b60d05460801c612608565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611c7d9190611c6c6080826106cb565b5190205f5260d260205260405f2090565b555f9360018311611cb6575b50505050611c978233614350565b604080519485526020850191909152830152339180606081015b0390a2005b611cfc92939450611cc79088612beb565b60408051336020820190815291810193909352606083018290529094909190611c6c9082608081015b039081018352826106cb565b555f808080611c89565b604051630e3d8e8d60e11b8152600490fd5b508215611bde565b508115611bd7565b346103dd5760403660031901126103dd576020600435611d54602435611d4d816103cc565b8233614faf565b90611d5e33613486565b60405190815230905f805160206159d5833981519152843392a3604051908152f35b346103dd5760203660031901126103dd57600435611d9c613deb565b335f90815261016e60205260409020611db4906125b7565b6001600160801b0380611dce83516001600160801b031690565b16156105eb578290611ddf83612e2d565b82516001600160801b03161610611f6257335f90815260d3602052604090205482611e20611e1484516001600160801b031690565b6001600160801b031690565b14611f4c57611e449083611e3e611e1485516001600160801b031690565b91612fd0565b91611e71611e64611e548361431d565b84516001600160801b0316610e33565b6001600160801b03168352565b335f90815261016e60205260409020611e8b908390612621565b611ed36020611ec460018060a01b037f000000000000000000000000000000000000000000000000000000000000000016809633614faf565b9301516001600160801b031690565b833b156103dd5760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af191821561062c576105e792611f39575b506040519081529081906020820190565b80610f9d611f469261069d565b5f611f28565b335f90815261016e602052604081205591611e8b565b604051636edcc52360e01b8152600490fd5b346103dd575f3660031901126103dd576040515f60018054611f9581610631565b80855291602091600181169081156107e25750600114611fbf576105e785610792818703826106cb565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851061200557505050508101602001610792826105e7610782565b8054868601840152938201938101611fe9565b346103dd57611cb17f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61204a3661109f565b9290612054613c17565b6040519182916020835233956020840191612ac2565b346103dd5760403660031901126103dd5761209460043561208a816103cc565b6024359033614945565b61209d33613486565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120dd5750505050505090565b90919293949584806120fb600193603f198682030187528a5161070d565b98019301930191949392906120cd565b346103dd5760203660031901126103dd576001600160401b036004358181116103dd57366023820112156103dd5780600401359182116103dd573660248360051b830101116103dd576105e79160246121649201612d36565b604051918291826120a8565b346103dd575f3660031901126103dd576105e760405161218f8161067d565b60058152640352e302e360dc1b602082015260405191829160208352602083019061070d565b346103dd575f3660031901126103dd576020610ff8612de3565b346103dd5760203660031901126103dd57602061044a6004356143ea565b60ff8116036103dd57565b346103dd5760e03660031901126103dd57600435612215816103cc565b602435612221816103cc565b604435906064359260843590612236826121ed565b6001600160a01b038381169590929086156108ba574281106123fb576020915f91611cf061232989878a6122ec61226b6127c0565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b0391612300601f19938481018352826106cb565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa1561062c575f519282841680159081156123ee575b506123dc576123c985916123b47f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610e9c565b6040516323389ba560e21b8152600490fd5b905083831614155f61236f565b604051631ab7da6b60e01b8152600490fd5b346103dd575f3660031901126103dd5760206001600160801b0360d05416604051908152f35b60409060031901126103dd5760043561244b816103cc565b90602435610743816103cc565b346103dd57602061249361246b36612433565b6001600160a01b039182165f9081526002855260408082209290931681526020919091522090565b54604051908152f35b346103dd5760203660031901126103dd576100206004356124bc816103cc565b6124c4613c17565b614479565b346103dd575f3660031901126103dd5760206001600160801b0360d55416604051908152f35b346103dd5760203660031901126103dd5760043561250c816103cc565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b346103dd575f3660031901126103dd576037546040516001600160a01b039091168152602090f35b602061044a61256636612433565b9061098433613464565b346103dd5760203660031901126103dd57610020600435612590816103cc565b612598613c17565b6144db565b908160209103126103dd575190565b6040513d5f823e3d90fd5b906040516125c48161067d565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f190191908211610aea57565b6001600160801b039182169082160391908211610aea57565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161266257505090565b916107439260801c90612fd0565b61026a546001600160a01b0391908216330361125f576001600160a01b0381165f90815261026b60205260409020549215159260ff1615158314612703576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b61271461271b91613138565b91906132ce565b61272157565b6127296151ca565b80612732575b50565b5f906040519081525f805160206159d583398151915260203092a3565b4760d0546001600160801b0361276681831661264a565b9060d55416019060801c01908181115f1461277f570390565b50505f90565b6101a1546001600160a01b0316801561279b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036127ed5760045490565b6107436138a4565b90610743929161280433613464565b61280d33613464565b6128188334336145ea565b50610a0d33613464565b908160209103126103dd5751610743816103cc565b359061ffff821682036103dd57565b9080601f830112156103dd5781602061074393359101611378565b906020828203126103dd5781356001600160401b03928382116103dd57019060a0828203126103dd5761289261133e565b92823584526128a360208401612837565b602085015260408301358181116103dd57826128c0918501612846565b604085015260608301358181116103dd57826128dd918501612846565b606085015260808301359081116103dd576128f89201612846565b608082015290565b6037549091906001600160a01b03166129c65760405163e7f6f22560e01b8152906020908183600481335afa92831561062c575f936129a7575b50604051636f4fa30f60e01b8152938285600481335afa90811561062c576129829561297d945f93612984575b50506129769192810190612861565b9083613af2565b613bb2565b565b612976935090816129a092903d106112995761128b81836106cb565b915f612967565b6129bf919350823d84116112995761128b81836106cb565b915f61293a565b50506129826139ca565b60d4548061074357505f1990565b908160209103126103dd5751610743816108cc565b91908203918211610aea57565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612a3e81608081015b03601f1981018352826106cb565b5190205f5260d260205260405f2054918215612a6e57612a5f918391613c50565b9091828103908111610aea5792565b5050505f905f905f90565b9035601e19823603018112156103dd5701602081359101916001600160401b0382116103dd5781360383136103dd57565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061074392602081528235602082015260208301356040820152612b1e612b0e6040850185612a79565b84606085015260c0840191612ac2565b90612b51612b46612b326060870187612a79565b601f19858703810160808701529591612ac2565b946080810190612a79565b93909282860301910152612ac2565b903590601e19813603018212156103dd57018035906001600160401b0382116103dd576020019181360383136103dd57565b634e487b7160e01b5f52601260045260245ffd5b8115612bb0570490565b612b92565b906801bc16d674ec8000009180830292830403610aea57565b90670de0b6b3a764000091828102928184041490151715610aea57565b91908201809211610aea57565b6001600160401b0381116106985760051b60200190565b90612c1982612bf8565b612c2660405191826106cb565b8281528092612c37601f1991612bf8565b01905f5b828110612c4757505050565b806060602080938501015201612c3b565b634e487b7160e01b5f52603260045260245ffd5b90821015612c83576110c99160051b810190612b60565b612c58565b908092918237015f815290565b3d15612cbf573d90612ca68261135d565b91612cb460405193846106cb565b82523d5f602084013e565b606090565b6020818303126103dd578051906001600160401b0382116103dd570181601f820112156103dd578051612cf68161135d565b92612d0460405194856106cb565b818452602082840101116103dd5761074391602080850191016106ec565b8051821015612c835760209160051b010190565b919091612d4283612c0f565b925f5b818110612d5157505050565b5f80612d5e838587612c6c565b60409391612d70855180938193612c88565b0390305af490612d7e612c95565b9115612da5575090600191612d938288612d22565b52612d9e8187612d22565b5001612d45565b9060448151106103dd57612ddf612dca60049283810151602480918301019101612cc4565b925162461bcd60e51b81529283928301610732565b0390fd5b610109546001600160a01b03168061074357507f000000000000000000000000000000000000000000000000000000000000000090565b612e2333613464565b61272f3433614522565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91612ec3575b5060208201916001600160801b03918284511691828214612ebc5783612eaf612eaa612eb7958584865116612fd0565b61431d565b16905261431d565b169052565b5050505050565b612edc915060203d6020116106255761061781836106cb565b5f612e7a565b90808202905f1981840990828083109203918083039214612f51576127109082821115612f3f577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612fbf57670de0b6b3a76400009082821115612f3f577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146130435784831115612f3f57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107439250612ba6565b908160609103126103dd5780519160406020830151920151610743816108cc565b81835290916001600160fb1b0383116103dd5760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036103dd57604083015260408101356130c4816103cc565b6001600160a01b031660608381019190915281013536829003601e19018112156103dd5701602081359101906001600160401b0381116103dd578060051b360382136103dd5760a0836080806107439601520191613071565b9190915f8382019384129112908015821691151617610aea57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906131639060048301613095565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561062c575f915f905f95613289575b50841561323657816131ad612785565b16917f000000000000000000000000000000000000000000000000000000000000000016821461322f57509060205f92600460405180958193634641257d60e01b83525af190811561062c5761320a925f9261320e575b5061311d565b9190565b61322891925060203d6020116106255761061781836106cb565b905f613204565b908161323c575b50509190565b803b156103dd57604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561062c57613276575b80613236565b80610f9d6132839261069d565b5f613270565b919450506132af915060603d6060116132b7575b6132a781836106cb565b810190613050565b93905f61319d565b503d61329d565b600160ff1b8114610aea575f0390565b801561272f576132e3611e1460cf5460801c90565b5f82126133b557816132f491612beb565b90613301610e408361431d565b613316609c549161ffff8360a01c1690612ee2565b801561270357807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613354611e1460cf546001600160801b031690565b8061339f57505061339a90925b6001600160a01b0316916133758484615162565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b61339a926133af92039084612fd0565b92613361565b906133bf906132be565b6133d4611e1460d5546001600160801b031690565b806133f4575b50806133e4575050565b612eaa610e4091612982936129f3565b9061345b7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161175c61343f61343461342d8888612beb565b8785612fd0565b80809403960361431d565b6001600160801b03166001600160801b031960d554161760d555565b0390a15f6133da565b6001600160a01b03165f90815261026b602052604090205460ff161561125f57565b60018060a01b0381165f5261016e60205260405f2090604051916134a98361067d565b54906001600160801b03918281169081855260801c602085015215612703576134fc610ccb613501926134da613deb565b6134e386612e2d565b6001600160a01b03165f90815260d36020526040902090565b6149d3565b9151161161350b57565b604051633684c65960e01b8152600490fd5b51906001600160401b03821682036103dd57565b908160609103126103dd5760405190606082018281106001600160401b0382111761069857613583916040918252805161356a8161047c565b84526135786020820161351d565b60208501520161351d565b604082015290565b92906001600160a01b0390818116156108ba576135a6613deb565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156103dd57604094855193631d8557d760e01b85526004945f81878183895af1801561062c57613891575b506001600160a01b0388165f90815261016e60205260409020613619906125b7565b906001600160801b0361363383516001600160801b031690565b16156138815761364282612e2d565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561062c57613862575b508651936303d1689d60e11b978886526020918287806136bc888c83019190602083019252565b0381845afa96871561062c575f97613843575b5086996136ef610ccb8d60018060a01b03165f5260d360205260405f2090565b88118015613833575b6138235790836137359261371387516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561062c575f8594889461377a9c613806575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561062c57610de66137c1946137a493610573936129829a6137e8575b505061431d565b6001600160a01b0388165f90815261016e60205260409020612621565b6137e36137cd836143ea565b80976137de610e40610e2c8761431d565b61537c565b614350565b816137fe92903d106106255761061781836106cb565b505f8061379d565b61381c90873d89116106255761061781836106cb565b505f61374f565b825163efda1a2760e01b81528990fd5b5061383c61274f565b88116136f8565b61385b919750833d85116106255761061781836106cb565b955f6136cf565b61387a9060603d606011610f7957610f6a81836106cb565b505f613695565b875163673f032f60e11b81528690fd5b80610f9d61389e9261069d565b5f6135f7565b6040515f905f54906138b582610631565b9283825260209384830193600190866001821691825f146139aa575050600114613967575b505091816138f061396193612a309503826106cb565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f805160206159758339815191525b82841061399557505050820101816138f06138da565b8054868501860152879490930192810161397f565b60ff1916875292151560051b850190920192508391506138f090506138da565b6139d2614aff565b6139e7611e1460d0546001600160801b031690565b60018111613ae057600114613a5b575b60d654613a0261557c565b90808210613a1e575b5050613a165f60d655565b612982614add565b5f8051602061599583398151915291613a519103613a3b816154a7565b604080519182525f602083015290918291820190565b0390a15f80613a0b565b613a94613a78613a7360cf546001600160801b031690565b6125f0565b6001600160801b03166001600160801b031960cf54161760cf55565b613aa96001600160801b031960d0541660d055565b613ab1615445565b5f8051602061599583398151915260405180613ad881905f60206040840193600181520152565b0390a16139f7565b604051630299325160e41b8152600490fd5b9190613afc614aff565b608082015190613b0a614aff565b6001600160a01b03841680156108ba57613baa94613b9a93613b83926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613b713394602083019061070d565b0390a2602085015161ffff1690614b40565b613b8d8351614b91565b613b95614bc1565b614bee565b6060604082015191015190614c1d565b612982614d4a565b61298290612598614aff565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613bfc575b505061168a57565b5f805160206159b58339815191525416141590505f80613bf4565b6037546001600160a01b0316330361125f57565b90604051613c388161067d565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590613de3575b613dd65783613da0575f5b60d15f526001600160a01b0316613c955f805160206159f58339815191528601613c2b565b8051909790613cac906001600160a01b0316611620565b98613cd1613cc56020809b01516001600160601b031690565b6001600160601b031690565b948381108015613d96575b613d845791600193979a95613cfb613d07939488035b838c0390614e6d565b80920198870391612fd0565b01970193808611801590613d7a575b613d6f5760d15f528290613d385f805160206159f58339815191528701613c2b565b805190890151969992966001600160a01b039091169460019392613d079290916001600160601b0390911690613cfb908803613cf2565b945050509250509190565b5081851015613d16565b60405163e8722f8f60e01b8152600490fd5b50808b1115613cdc565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316613c70565b505093505050505f905f90565b508415613c65565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f91613e57575b50613e4557565b60405163e775715160e01b8152600490fd5b613e70915060203d6020116115265761151781836106cb565b5f613e3e565b604290467f000000000000000000000000000000000000000000000000000000000000000003613f255761010a54905b613ebd613eb66040830183612b60565b3691611378565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613f08816106b0565b5190206040519161190160f01b8352600283015260228201522090565b613f2d614e7f565b90613ea6565b60041115613f3d57565b634e487b7160e01b5f52602160045260245ffd5b613f5b8383614f4c565b50613f6881959295613f33565b159384614004575b508315613f7e575b50505090565b5f929350908291604051613fb681612a306020820194630b135d3f60e11b998a8752602484015260406044840152606483019061070d565b51915afa90613fc3612c95565b82613ff6575b82613fd9575b50505f8080613f78565b613fee9192506020808251830101910161259d565b145f80613fcf565b915060208251101591613fc9565b6001600160a01b0383811691161493505f613f70565b906030116103dd5790603090565b906090116103dd5760300190606090565b9060b0116103dd5760900190602090565b909392938483116103dd5784116103dd578101920390565b359060208110614070575090565b5f199060200360031b1b1690565b969594906140bb9361409f6140ad926060979560808c5260808c0191612ac2565b9089820360208b015261070d565b918783036040890152612ac2565b930152565b906020610743928181520190612aaa565b916020610743938181520191612ac2565b60b091828104915f90816140f4614f86565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b87841061413657505050505050505050565b8261414591018092888761404a565b90614150828261401a565b9161416f6141696141618684614028565b969093614039565b90614062565b90893b156103dd575f908d61419c604094855198899485946304512a2360e31b86528a8a6004880161407e565b03816801bc16d674ec8000008d5af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1946141e8926141f7575b5051928392836140d1565b0390a160018193019290614124565b80610f9d6142049261069d565b5f6141dd565b816030116103dd57614169917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614248614f86565b9061425f6142568486614028565b96909486614039565b94813b156103dd576801bc16d674ec8000005f946142c597604051988996879586946304512a2360e31b8652608060048701526142b66142a38d6084890190612aaa565b60031994858983030160248a015261070d565b92868403016044870152612ac2565b90606483015203925af190811561062c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19261339a9261430e575b50604051918291826140c0565b6143179061069d565b5f614301565b6001600160801b0390818111614331571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009160028354146143d857600283558147106143c0575f918291829182916001600160a01b03165af16143a2612c95565b50156143ae5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614419575b1561440c5750905090565b6107439260801c91612fd0565b508015614401565b60cf546001600160801b0381169082158015614471575b1561444257505090565b60801c90614451828285612fd0565b928215612bb057096144605790565b6001810180911115610743576125dc565b508115614438565b614481613deb565b6001600160a01b031680156144c957609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b919061452c613deb565b6001600160a01b0383169081156108ba5780156145d85780614553611e1460cf5460801c90565b019361455d6129d0565b85116145c657610e40946145849161457f61457785614421565b97889361431d565b615162565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b909291926145f6613deb565b6001600160a01b0382169182156108ba5781156145d8578161461d611e1460cf5460801c90565b016146266129d0565b81116145c657610e409561466d6145c1927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461457f61466588614421565b9a8b9361431d565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b9190916001600160801b0380809416911601918211610aea57565b93929190916146be61535b565b6146c6613deb565b6001600160a01b0385165f90815261016e602052604090206146e7906125b7565b946001600160801b0361470187516001600160801b031690565b16156148b65761471086612e2d565b6001600160a01b0381165f90815260d360205260409020614734906134fc90610ccb565b955f198414614886575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af195861561062c575f96614865575b5085986147d06147c36147b38461431d565b86516001600160801b0316614696565b6001600160801b03168552565b6147e4611e1485516001600160801b031690565b1161350b577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e589561482d614860946105948760018060a01b03165f5261016e60205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b61487f91965060203d6020116106255761061781836106cb565b945f6147a1565b925061489c611e1484516001600160801b031690565b808711156148ac5786039261473e565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c5761492191614911915f91614926575b5061431d565b6001600160801b03166020880152565b614710565b61493f915060203d6020116106255761061781836106cb565b5f61490b565b9061494f82613464565b61495881613464565b6001600160a01b0391821691821580156149c9575b6108ba57825f5260d360205260405f2090815492858403938411610aea575f805160206159d583398151915293602093556149b88160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b508082161561496d565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561062c57614a6e936001600160401b03610ca66040614a4d946020975f91614abe575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561062c575f91614aa5575090565b610743915060203d6020116106255761061781836106cb565b614ad7915060603d606011610f7957610f6a81836106cb565b5f614a3e565b614ae5614aff565b614aed614e7f565b61010a80548203614afc575050565b55565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614b2e57565b604051631afcd79f60e31b8152600490fd5b614b48614aff565b61271061ffff831611614b7f57614b5e90614479565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614b99614aff565b8015614baf5760018101614baa5750565b60d455565b6040516331278a8760e01b8152600490fd5b614bc9614aff565b6801bc16d674ec800000614bdb6129d0565b10614baf57614be8614e7f565b61010a55565b614bf6614aff565b6001600160a01b031680614c075750565b6101a180546001600160a01b0319169091179055565b614c25614aff565b601e8151118015614d3f575b614d2d57614c3d614aff565b8051906001600160401b03821161069857614c6182614c5c5f54610631565b6155be565b602090816001601f851114614cb957509180614c9792614c9e95945f92614cae575b50508160011b915f199060031b1c19161790565b5f55615688565b612982614ca96138a4565b600455565b015190505f80614c83565b5f80529190601f1984165f80516020615975833981519152935f905b828210614d15575050916001939185614c9e97969410614cfd575b505050811b015f55615688565b01515f1960f88460031b161c191690555f8080614cf0565b80600186978294978701518155019601940190614cd5565b604051632d3f993760e21b8152600490fd5b50600a825111614c31565b614d52614aff565b614d5a614aff565b614d62614aff565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614d9b5761272f3430614522565b60405163ea2559bb60e01b8152600490fd5b908160209103126103dd5751610743816121ed565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614e4c575b50614e1257604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206159b58339815191528403614e3357612982929350615766565b604051632a87526960e21b815260048101859052602490fd5b614e6691955060203d6020116106255761061781836106cb565b935f614dec565b9080821015614e7a575090565b905090565b6e5661756c7456616c696461746f727360881b6020604051614ea08161067d565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176106985760405251902090565b8151919060418303614f7c57614f759250602082015190606060408401519301515f1a90615808565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c820152602081526107438161067d565b9291908015611f62576001600160a01b038281169283156108ba57614fd5611b5e61589c565b6150de5790611c6c956150c26150a6857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161507b615020611e1460d0546001600160801b031690565b92612a3061504d8561504861503361557c565b615042611e1460d55460801c90565b90612beb565b612beb565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f90815260d36020526040902061509e8382546129f3565b90550161431d565b6001600160801b03166001600160801b031960d054161760d055565b60408051888152602081019590955291169290819081016145c1565b9293946150ea8361264a565b9384156145d8577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361513f8661515a93615135610e4061512a8461431d565b60cf5460801c612608565b6137e3848761537c565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b5f805160206159d583398151915260205f9261517d8561431d565b60cf54906151956001600160801b0391828416614696565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b6151e3476151dd611e1460d05460801c90565b906129f3565b9081156153565760d5546001600160801b03811690816152de575b5050615215611e1460d0546001600160801b031690565b91821580156152d6575b6152d057615236906152308461264a565b90614e6d565b80156152d057615245816143ea565b9283156152c95761512a612982926152666150a6612eaa88610e40966129f3565b615280611c1e6152758361431d565b60d05460801c614696565b61528a81876154f2565b60408051878152602081018390525f805160206159958339815191529190a1612eaa613a786152b88861431d565b60cf546001600160801b0316612608565b505f925050565b505f9150565b50801561521f565b81849294106152c95761527584615326935f8051602061599583398151915282611c1e9560801c61530f82826154f2565b604080519182526020820192909252a1039461431d565b61533a6001600160801b0360d5541660d555565b61534f6001600160801b031960d5541660d555565b5f806151fe565b5f9150565b61536361589c565b1561536a57565b604051630a62fbdb60e11b8152600490fd5b6001600160a01b03165f81815260d360205260409020805483810391908211610aea575f935f805160206159d583398151915292602092556153bd8161431d565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b60d154906801000000000000000082101561069857600182018060d155821015612c835760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206159f583398151915290910155565b61544d61557c565b60018101809111610aea576001600160a01b03808211615487579061298291604051916154798361067d565b1681525f60208201526153e7565b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b80156154e0576154b561557c565b908101809111610aea576001600160a01b03808211615487579061298291604051916154798361067d565b604051632ec8835b60e21b8152600490fd5b91909180156154e05761550361557c565b908101809111610aea576001600160a01b03808211615487576001600160601b039081851161555c5790612982939461555792604051946155438661067d565b168452166001600160601b03166020830152565b6153e7565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b60d1548061558957505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316611620565b601f81116155ca575050565b5f80525f80516020615975833981519152906020601f840160051c8301931061560d575b601f0160051c01905b818110615602575050565b5f81556001016155f7565b90915081906155ee565b90601f8211615624575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c8301931061567e575b601f0160051c01905b81811061567457505050565b5f81558201615668565b909150819061565f565b9081516001600160401b038111610698576001906156af816156aa8454610631565b615617565b602080601f83116001146156e4575081906156e09394955f92614cae5750508160011b915f199060031b1c19161790565b9055565b90601f1983169561571660015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061574f5750508385969710615737575b505050811b019055565b01515f1960f88460031b161c191690555f808061572d565b80878596829496860151815501950193019061571a565b90813b156157e7575f805160206159b583398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156157cc5761272f9161590b565b5050346157d557565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161589157906158616020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561062c575f516001600160a01b0381161561588757905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561062c575f916158f2575090565b610743915060203d6020116115265761151781836106cb565b5f8061074393602081519101845af4615922612c95565b919061593857508051156143ae57805190602001fd5b8151158061596b575b615949575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561594156fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce3a26469706673582212201629caca5f73ed443a1870106ce3ecbfbc91dfd1616c7659127690242718758e64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthPrivVault.json b/test/shared/artifacts/EthPrivVault.json deleted file mode 100644 index c857e0cb..00000000 --- a/test/shared/artifacts/EthPrivVault.json +++ /dev/null @@ -1,1745 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthPrivVault", - "sourceName": "contracts/vaults/ethereum/EthPrivVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101e034620002695762004fff6001600160401b03601f38839003908101601f1916840190828211858310176200026d5780859460409384528539610120938491810103126200026957620000548462000281565b91620000636020860162000281565b916200007181870162000281565b93620000806060880162000281565b916200008f6080890162000281565b936200009e60a08a0162000281565b95620000ad60c08b0162000281565b97620000bc60e08c0162000281565b91610100809c01519560805260a05260c0523060e052895246885261014092835260018060a01b03806101609516855280610180961686526101a0961686526101c09687527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166200025857808083160362000213575b5050505195614d6897886200029789396080518881816114720152818161160a015281816129e4015281816136a40152614c15015260a0518861113f015260c0518881816139940152613ab5015260e0518881816112be0152613467015251876126730152518661371a015251856117b001525184818161042701528181610739015281816126bd01528181612f62015281816141ea015281816143570152614a6b0152518381816107f801528181610dbc0152818161302101526149ef01525182611a7a01525181818161209a0152612a2c0152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200013c565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002695756fe60806040526004361015610022575b3615610018575f80fd5b610020612695565b005b5f3560e01c806301d523b61461031157806301e1d1141461030c578063066055e01461030757806307a2d13a146103025780630d392cd9146102fd57806318f72950146102f85780631a7ff553146102f3578063201b9eb5146102ee57806322758a4a146102e95780632999ad3f146102e45780632cdf7401146102df5780633229fa95146102da57806333194c0a146102d557806336fe59d2146102d05780633a98ef39146102cb578063439fab91146102c657806343e82a79146102c157806346904840146102bc5780634ec96b22146102b75780634f1ef286146102b257806352d1902d146102ad57806353156f28146102a857806354fd4d50146102a35780635c60da1b1461029e5780635cfc1a511461029957806360d60e6e1461029457806372b410a81461028f578063754c38881461028a57806376b58b90146102855780637fd6f15c1461028057806383d430d51461027b5780638697d2c2146102765780638ceab9aa146102715780639267842a1461026c578063a49a1e7d14610267578063ac9650d814610262578063ad3cb1cc1461025d578063b1f0e7c714610258578063c6e6f59214610253578063d83ad00c1461024e578063e74b981b14610249578063ee3bd5df14610244578063f04da65b1461023f578063f6a6830f1461023a578063f851a44014610235578063f9609f08146102305763f98f5b920361000e57611e86565b611e5c565b611e35565b611df4565b611db9565b611d93565b611d66565b611d40565b611d22565b611d08565b611cc3565b611c4d565b611b52565b61195e565b61192a565b611784565b6115b4565b611590565b61153f565b6114d4565b611447565b6113a2565b611388565b611354565b611339565b611315565b6112ac565b611027565b610ec2565b610e9a565b610d8d565b610cc7565b610c46565b610c32565b610bf8565b610bcc565b610bb2565b61070f565b6106bd565b61069a565b61063b565b6105d5565b6105a3565b61057b565b6103d7565b6103a6565b610339565b6001600160a01b0381160361032757565b5f80fd5b908160809103126103275790565b60803660031901126103275760043561035181610316565b60443561035d81610316565b606435906001600160401b0382116103275760209261038b61038661039494369060040161032b565b612027565b602435906120bc565b604051908152f35b5f91031261032757565b34610327575f36600319011261032757602060985460801c604051908152f35b6001600160801b0381160361032757565b34610327576020366003190112610327576004356103f4816103c6565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610576575f91610547575b50335f9081526101376020526040902061047090611ecd565b916001600160801b0361048a84516001600160801b031690565b1615610535576104e3836104a0610531956126a8565b6104ca6104bd846104b884516001600160801b031690565b611f1e565b6001600160801b03168252565b335f90815261013760205260409020611f37565b611f37565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610569915060203d60201161056f575b6105618183610fb5565b810190611eb3565b5f610457565b503d610557565b611ec2565b34610327576020366003190112610327576020610394600435611f69565b8015150361032757565b34610327576040366003190112610327576100206004356105c381610316565b602435906105d082610599565b611f8f565b6060366003190112610327576004356105ed81610316565b6024356105f981610316565b604435906001600160401b0382116103275760209261062261038661039494369060040161032b565b61062b33612ece565b61063481612ece565b3490613e87565b34610327576020366003190112610327576004356001600160401b0381116103275761038661002091369060040161032b565b60609060031901126103275760043561068681610316565b906024359060443561069781610316565b90565b346103275760206103946106ad3661066e565b916106b733612ece565b33614126565b34610327575f36600319011261032757610201546040516001600160a01b039091168152602090f35b6060906003190112610327576004359060243561070281610316565b9060443561069781610316565b346103275761071d366106e6565b906001600160a01b0380831615610ba057610736613689565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103275760408051631d8557d760e01b815260049491905f81878183875af1801561057657610b87575b506001600160a01b0383165f908152610137602052604090206107a990611ecd565b6001600160801b0392836107c483516001600160801b031690565b1615610b77576107d3826126a8565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610576575f98610b46575b50602097888101956001600160401b0391828061084c8a516001600160401b031690565b1614610b3657908c92918751918c83806108786303d1689d60e11b988983528a83019190602083019252565b03818a5afa918215610576576108a4938e5f94610b11575b5050516001600160801b03165b16906127d7565b966108c86108c28a60018060a01b03165f52609c60205260405f2090565b54611f69565b928389118015610b01575b610af157908b61091193926108ef89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561057657670de0b6b3a764000094610960948e5f95610ac4575b50506109526109446109589261244a565b93516001600160401b031690565b9361244a565b92169061284b565b1015610ab6578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610576577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610a9395610a0a93610a98575b50506109ed6104bd6109dd8c613bba565b83516001600160801b0316611f1e565b6001600160a01b0386165f90815261013760205260409020611f37565b610a1382613c87565b90610a52610a37610a2385613bba565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610a5c82866143d1565b610a668389613bed565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610aae92903d1061056f576105618183610fb5565b505f806109cc565b835163185cfc6d60e11b8152fd5b610958929550610ae7610952928261094493903d1061056f576105618183610fb5565b959250508e610933565b875163efda1a2760e01b81528590fd5b50610b0a61204b565b89116108d3565b61089d9294509081610b2e92903d1061056f576105618183610fb5565b92908e610890565b8651630709133160e01b81528490fd5b610b6991985060603d606011610b70575b610b618183610fb5565b810190612f04565b965f610828565b503d610b57565b825163673f032f60e11b81528790fd5b80610b94610b9a92610f6c565b8061039c565b5f610787565b60405163d92e233d60e01b8152600490fd5b34610327575f36600319011261032757602061039461204b565b34610327575f366003190112610327576020610be6612081565b6040516001600160a01b039091168152f35b34610327575f3660031901126103275760206040517fa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d98152f35b6020610394610c403661066e565b916120bc565b34610327575f3660031901126103275760206001600160801b0360985416604051908152f35b9181601f84011215610327578235916001600160401b038311610327576020838186019501011161032757565b602060031982011261032757600435906001600160401b03821161032757610cc391600401610c6c565b9091565b610cd036610c99565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610d79575b610d675768010000000000000003610d2a9368ffffffffffffffffff191617845561217d565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610d04565b3461032757610d9b366106e6565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105765782915f91610e6b575b50163303610e595781610a93610e2686867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396612f44565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610e8d915060203d602011610e93575b610e858183610fb5565b8101906120e9565b5f610dee565b503d610e7b565b34610327575f366003190112610327576065546040516001600160a01b039091168152602090f35b3461032757602036600319011261032757600435610edf81610316565b60018060a01b03165f52610137602052602060405f2060405190610f0282610f4c565b54906001600160801b03918281169081835260801c84830152610f2a575b5116604051908152f35b610f33816126a8565b610f20565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b03821117610f6757604052565b610f38565b6001600160401b038111610f6757604052565b606081019081106001600160401b03821117610f6757604052565b608081019081106001600160401b03821117610f6757604052565b90601f801991011681019081106001600160401b03821117610f6757604052565b6001600160401b038111610f6757601f01601f191660200190565b929192610ffd82610fd6565b9161100b6040519384610fb5565b829481845281830111610327578281602093845f960137010152565b60408060031936011261032757600490813561104281610316565b6024356001600160401b0381116103275736602382011215610327576110719036906024818701359101610ff1565b9161107a61345d565b8051926110b1846110a360209363439fab9160e01b858401528460248401526044830190611bc5565b03601f198101865285610fb5565b6110b961345d565b6110c16134b6565b6001600160a01b03838116801592919087908415611277575b8415611209575b84156111a6575b50508215611110575b5050611101576100208383614582565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610576575f92611179575b5050155f806110f1565b6111989250803d1061119f575b6111908183610fb5565b81019061225a565b5f8061116f565b503d611186565b855163054fd4d560e41b81529294508391839182905afa90811561057657879160ff915f916111dc575b5016141591865f6110e8565b6111fc9150843d8611611202575b6111f48183610fb5565b810190614569565b5f6111d0565b503d6111ea565b935050835163198ca60560e11b815282818981875afa9081156105765788917fa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9915f9161125a575b501415936110e1565b6112719150853d871161056f576105618183610fb5565b5f611251565b5f80516020614d138339815191525490945084906112a5906001600160a01b03165b6001600160a01b031690565b14936110da565b34610327575f366003190112610327577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036113035760206040515f80516020614d138339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112610327576001600160a01b03611330612081565b163303610e5957005b34610327575f36600319011261032757602060405160038152f35b34610327575f366003190112610327575f80516020614d13833981519152546040516001600160a01b039091168152602090f35b34610327575f36600319011261032757602061039461224c565b3461032757602036600319011261032757609a80549081905f6004355b8482106113f0575050508110156113e557610531905b6040519081529081906020820190565b506105315f196113d5565b909193808316906001818518811c8301809311611442575f8790525f80516020614cd38339815191528301546001600160a01b0316841015611437575050935b91906113bf565b909591019250611430565b611ef2565b34610327575f36600319011261032757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610576576020915f916114b7575b506040519015158152f35b6114ce9150823d841161119f576111908183610fb5565b5f6114ac565b34610327576020366003190112610327576004356114f181610316565b6114f96134b6565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103275760803660031901126103275761053161157360043561156281610316565b60643590604435906024359061227c565b604080519384526020840192909252908201529081906060820190565b34610327575f36600319011261032757602061ffff60655460a01c16604051908152f35b34610327576003196040368201126103275760049081356001600160401b038082116103275760a082850193833603011261032757602435908111610327576116009036908501610c6c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103275760405163837d444160e01b8152905f9082908183816116538c828f0161235e565b03925af1801561057657611771575b5061166b613689565b61167361265f565b9081163314159182611742575b50509050611731576044019160b061169884846123dc565b90500480158015611719575b611709576116b96116b361204b565b91612431565b116116fa575060b06116cb83836123dc565b9050145f146116e757610020916116e1916123dc565b90613aa7565b610020916116f4916123dc565b9061397f565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b5061172484846123dc565b905060b0820214156116a4565b604051634ca8886760e01b81528390fd5b611765925061175f6117699461175788613714565b923691610ff1565b916137ee565b1590565b805f80611680565b80610b9461177e92610f6c565b5f611662565b34610327576060366003190112610327576004356024356117a960443582843361227c565b91926117d57f000000000000000000000000000000000000000000000000000000000000000082612467565b42108015611922575b801561191a575b611908577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb569361184061182561181a86613bba565b60995460801c611f1e565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916118849190611873608082610fb5565b5190205f52609b60205260405f2090565b555f93600183116118bd575b5050505061189e8233613bed565b604080519485526020850191909152830152339180606081015b0390a2005b6118fe929394506118ce9088612467565b60408051336020820190815291810193909352606083018290526080958601835290949091906118739082610fb5565b555f808080611890565b604051630e3d8e8d60e11b8152600490fd5b5082156117e5565b5081156117de565b3461032757604036600319011261032757602061195560243561194c81610316565b600435336147dd565b6103943361475d565b346103275760203660031901126103275760043561197a613689565b335f9081526101376020526040902061199290611ecd565b6001600160801b03806119ac83516001600160801b031690565b16156105355782906119bd836126a8565b82516001600160801b03161610611b4057335f908152609c6020526040902054826119fe6119f284516001600160801b031690565b6001600160801b031690565b14611b2a57611a229083611a1c6119f285516001600160801b031690565b9161284b565b91611a4f611a42611a3283613bba565b84516001600160801b0316610a2a565b6001600160801b03168352565b335f90815261013760205260409020611a69908390611f37565b611ab16020611aa260018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336147dd565b9301516001600160801b031690565b833b156103275760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105765761053192611b17575b506040519081529081906020820190565b80610b94611b2492610f6c565b5f611b06565b335f908152610137602052604081205591611a69565b604051636edcc52360e01b8152600490fd5b34610327576118b87f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611b8436610c99565b9290611b8e6134b6565b604051918291602083523395602084019161233e565b5f5b838110611bb55750505f910152565b8181015183820152602001611ba6565b90602091611bde81518092818552858086019101611ba4565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611c1f5750505050505090565b9091929394958480611c3d600193603f198682030187528a51611bc5565b9801930193019194939290611c0f565b34610327576020366003190112610327576001600160401b036004358181116103275736602382011215610327578060040135918211610327573660248360051b8301011161032757610531916024611ca692016125b2565b60405191829182611bea565b906020610697928181520190611bc5565b34610327575f36600319011261032757610531604051611ce281610f4c565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611bc5565b34610327575f366003190112610327576020610be661265f565b34610327576020366003190112610327576020610394600435613c87565b34610327575f3660031901126103275760206001600160801b0360995416604051908152f35b3461032757602036600319011261032757610020600435611d8681610316565b611d8e6134b6565b613d16565b34610327575f3660031901126103275760206001600160801b03609e5416604051908152f35b3461032757602036600319011261032757600435611dd681610316565b60018060a01b03165f52609c602052602060405f2054604051908152f35b3461032757602036600319011261032757600435611e1181610316565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b34610327575f366003190112610327575f546040516001600160a01b039091168152602090f35b6040366003190112610327576020610394600435611e7981610316565b6024359061062282610316565b3461032757602036600319011261032757610020600435611ea681610316565b611eae6134b6565b613d78565b90816020910312610327575190565b6040513d5f823e3d90fd5b90604051611eda81610f4c565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f19019190821161144257565b6001600160801b03918216908216039190821161144257565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b0381169081611f8157505090565b916106979260801c9061284b565b610201546001600160a01b03919082163303610e59576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612022576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b61203361203a916129b3565b9190612b49565b61204057565b612048612cfa565b50565b476099546001600160801b03612062818316611f69565b90609e5416019060801c01908181115f1461207b570390565b50505f90565b61016a546001600160a01b031680156120975790565b507f000000000000000000000000000000000000000000000000000000000000000090565b9061069792916120cb33612ece565b6120d433612ece565b6120df833433613e87565b506106b733612ece565b90816020910312610327575161069781610316565b906020828203126103275781356001600160401b0392838211610327570191606083830312610327576040519261213484610f7f565b80358452602081013561ffff81168103610327576020850152604081013591821161032757019080601f830112156103275781602061217593359101610ff1565b604082015290565b5f549091906001600160a01b03166122425760405163e7f6f22560e01b8152906020908183600481335afa928315610576575f93612223575b50604051636f4fa30f60e01b8152938285600481335afa908115610576576121fe956121f9945f93612200575b50506121f291928101906120fe565b9083613369565b613451565b565b6121f29350908161221c92903d10610e9357610e858183610fb5565b915f6121e3565b61223b919350823d8411610e9357610e858183610fb5565b915f6121b6565b50506121fe61325d565b609d548061069757505f1990565b90816020910312610327575161069781610599565b9190820391821161144257565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906122ba81608081015b03601f198101835282610fb5565b5190205f52609b60205260405f20549182156122ea576122db9183916134ee565b90918281039081116114425792565b5050505f905f905f90565b9035601e19823603018112156103275701602081359101916001600160401b03821161032757813603831361032757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06106979260208152823560208201526020830135604082015261239a61238a60408501856122f5565b84606085015260c084019161233e565b906123cd6123c26123ae60608701876122f5565b601f1985870381016080870152959161233e565b9460808101906122f5565b9390928286030191015261233e565b903590601e198136030182121561032757018035906001600160401b0382116103275760200191813603831361032757565b634e487b7160e01b5f52601260045260245ffd5b811561242c570490565b61240e565b906801bc16d674ec800000918083029283040361144257565b90670de0b6b3a76400009182810292818404149015171561144257565b9190820180921161144257565b6001600160401b038111610f675760051b60200190565b9061249582612474565b6124a26040519182610fb5565b82815280926124b3601f1991612474565b01905f5b8281106124c357505050565b8060606020809385010152016124b7565b634e487b7160e01b5f52603260045260245ffd5b908210156124ff57610cc39160051b8101906123dc565b6124d4565b908092918237015f815290565b3d1561253b573d9061252282610fd6565b916125306040519384610fb5565b82523d5f602084013e565b606090565b602081830312610327578051906001600160401b038211610327570181601f8201121561032757805161257281610fd6565b926125806040519485610fb5565b81845260208284010111610327576106979160208085019101611ba4565b80518210156124ff5760209160051b010190565b9190916125be8361248b565b925f5b8181106125cd57505050565b5f806125da8385876124e8565b604093916125ec855180938193612504565b0390305af4906125fa612511565b911561262157509060019161260f828861259e565b5261261a818761259e565b50016125c1565b9060448151106103275761265b61264660049283810151602480918301019101612540565b925162461bcd60e51b81529283928301611cb2565b0390fd5b60d2546001600160a01b03168061069757507f000000000000000000000000000000000000000000000000000000000000000090565b61269e33612ece565b6120483433613dbf565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f9161273e575b5060208201916001600160801b03918284511691828214612737578361272a61272561273295858486511661284b565b613bba565b169052613bba565b169052565b5050505050565b612757915060203d60201161056f576105618183610fb5565b5f6126f5565b90808202905f19818409908280831092039180830392146127cc5761271090828211156127ba577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461283a57670de0b6b3a764000090828211156127ba577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146128be57848311156127ba57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106979250612422565b90816060910312610327578051916040602083015192015161069781610599565b81835290916001600160fb1b0383116103275760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103610327576040830152604081013561293f81610316565b6001600160a01b031660608381019190915281013536829003601e19018112156103275701602081359101906001600160401b038111610327578060051b360382136103275760a08360808061069796015201916128ec565b9190915f838201938412911290801582169115161761144257565b6040516325f56f1160e01b81526001600160a01b039291606090829081906129de9060048301612910565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610576575f915f905f95612b04575b508415612ab15781612a28612081565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612aaa57509060205f92600460405180958193634641257d60e01b83525af190811561057657612a85925f92612a89575b50612998565b9190565b612aa391925060203d60201161056f576105618183610fb5565b905f612a7f565b9081612ab7575b50509190565b803b1561032757604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561057657612af1575b80612ab1565b80610b94612afe92610f6c565b5f612aeb565b91945050612b2a915060603d606011612b32575b612b228183610fb5565b8101906128cb565b93905f612a18565b503d612b18565b600160ff1b8114611442575f0390565b801561204857612b5e6119f260985460801c90565b5f8212612c305781612b6f91612467565b90612b7c610a3783613bba565b612b916065549161ffff8360a01c169061275d565b801561202257807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793612bcf6119f26098546001600160801b031690565b80612c1a575050612c1590925b6001600160a01b031691612bf08484613f33565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b612c1592612c2a9203908461284b565b92612bdc565b90612c3a90612b39565b612c4f6119f2609e546001600160801b031690565b80612c6f575b5080612c5f575050565b612725610a37916121fe9361226f565b90612cd67f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916113d5612cba612caf612ca88888612467565b878561284b565b808094039603613bba565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f612c55565b9190916001600160801b038080941691160191821161144257565b612d1347612d0d6119f260995460801c90565b9061226f565b908115612ec957609e546001600160801b0381169081612e51575b5050612d456119f26099546001600160801b031690565b9182158015612e49575b612e4357612d6690612d6084611f69565b90614114565b8015612e4357612d7581613c87565b928315612e3c57612e316121fe92612db2612d9661272588610a379661226f565b6001600160801b03166001600160801b03196099541617609955565b612dcc611825612dc183613bba565b60995460801c612cdf565b612dd68187613fdd565b60408051878152602081018390525f80516020614cf38339815191529190a1612725612e15612e0488613bba565b6098546001600160801b0316611f1e565b6001600160801b03166001600160801b03196098541617609855565b60985460801c611f1e565b505f925050565b505f9150565b508015612d4f565b8184929410612e3c57612dc184612e99935f80516020614cf3833981519152826118259560801c612e828282613fdd565b604080519182526020820192909252a10394613bba565b612ead6001600160801b03609e5416609e55565b612ec26001600160801b0319609e5416609e55565b5f80612d2e565b5f9150565b6001600160a01b03165f908152610202602052604090205460ff1615610e5957565b51906001600160401b038216820361032757565b90816060910312610327576121756040805192612f2084610f7f565b8051612f2b816103c6565b8452612f3960208201612ef0565b602085015201612ef0565b92906001600160a01b039081811615610ba057612f5f613689565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561032757604094855193631d8557d760e01b85526004945f81878183895af180156105765761324a575b506001600160a01b0388165f90815261013760205260409020612fd290611ecd565b906001600160801b03612fec83516001600160801b031690565b161561323a57612ffb826126a8565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156105765761321b575b508651936303d1689d60e11b97888652602091828780613075888c83019190602083019252565b0381845afa968715610576575f976131fc575b5086996130a86108c28d60018060a01b03165f52609c60205260405f2090565b881180156131ec575b6131dc5790836130ee926130cc87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610576575f859488946131339c6131bf575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af1958615610576576109dd61317a9461315d936104bd936121fe9a6131a1575b5050613bba565b6001600160a01b0388165f90815261013760205260409020611f37565b61319c61318683613c87565b8097613197610a37610a2387613bba565b6143d1565b613bed565b816131b792903d1061056f576105618183610fb5565b505f80613156565b6131d590873d891161056f576105618183610fb5565b505f613108565b825163efda1a2760e01b81528990fd5b506131f561204b565b88116130b1565b613214919750833d851161056f576105618183610fb5565b955f613088565b6132339060603d606011610b7057610b618183610fb5565b505f61304e565b875163673f032f60e11b81528690fd5b80610b9461325792610f6c565b5f612fb0565b61326561443f565b61327a6119f26099546001600160801b031690565b60018111613357576001146132ee575b609f54613295614969565b908082106132b1575b50506132a95f609f55565b6121fe61441e565b5f80516020614cf3833981519152916132e491036132ce816140db565b604080519182525f602083015290918291820190565b0390a15f8061329e565b61330b612e156133066098546001600160801b031690565b611f06565b6133206001600160801b031960995416609955565b613328614099565b5f80516020614cf38339815191526040518061334f81905f60206040840193600181520152565b0390a161328a565b604051630299325160e41b8152600490fd5b61337161443f565b604083015161337e61443f565b6001600160a01b0382168015610ba0576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806133d733946020830190611bc5565b0390a26020830151926133e861443f565b61271061ffff85161161343f576134379361340561342a93613d16565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614480565b6134326144b0565b6144d7565b6121fe614506565b604051638a81d3b360e01b8152600490fd5b6121fe90611eae61443f565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821561349b575b505061130357565b5f80516020614d138339815191525416141590505f80613493565b5f546001600160a01b03163303610e5957565b906040516134d681610f4c565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613681575b613674578361363e575f5b609a5f526001600160a01b03166135335f80516020614cd383398151915286016134c9565b805190979061354a906001600160a01b0316611299565b9861356f6135636020809b01516001600160601b031690565b6001600160601b031690565b948381108015613634575b6136225791600193979a956135996135a5939488035b838c0390614114565b8092019887039161284b565b01970193808611801590613618575b61360d57609a5f5282906135d65f80516020614cd383398151915287016134c9565b805190890151969992966001600160a01b0390911694600193926135a59290916001600160601b0390911690613599908803613590565b945050509250509190565b50818510156135b4565b60405163e8722f8f60e01b8152600490fd5b50808b111561357a565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031661350e565b505093505050505f905f90565b508415613503565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f916136f5575b506136e357565b60405163e775715160e01b8152600490fd5b61370e915060203d60201161119f576111908183610fb5565b5f6136dc565b604290467f0000000000000000000000000000000000000000000000000000000000000000036137c25760d354905b61375a61375360408301836123dc565b3691610ff1565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526137a581610f9a565b5190206040519161190160f01b8352600283015260228201522090565b6137ca61462d565b90613743565b600411156137da57565b634e487b7160e01b5f52602160045260245ffd5b6137f883836146fa565b50613805819592956137d0565b1593846138a1575b50831561381b575b50505090565b5f929350908291604051613853816122ac6020820194630b135d3f60e11b998a87526024840152604060448401526064830190611bc5565b51915afa90613860612511565b82613893575b82613876575b50505f8080613815565b61388b91925060208082518301019101611eb3565b145f8061386c565b915060208251101591613866565b6001600160a01b0383811691161493505f61380d565b906030116103275790603090565b906090116103275760300190606090565b9060b0116103275760900190602090565b90939293848311610327578411610327578101920390565b35906020811061390d575090565b5f199060200360031b1b1690565b969594906139589361393c61394a926060979560808c5260808c019161233e565b9089820360208b0152611bc5565b91878303604089015261233e565b930152565b906020610697928181520190612326565b91602061069793818152019161233e565b60b091828104915f9081613991614734565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b8784106139d357505050505050505050565b826139e29101809288876138e7565b906139ed82826138b7565b91613a0c613a066139fe86846138c5565b9690936138d6565b906138ff565b90893b15610327575f908d613a39604094855198899485946304512a2360e31b86528a8a6004880161391b565b03816801bc16d674ec8000008d5af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194613a8592613a94575b50519283928361396e565b0390a1600181930192906139c1565b80610b94613aa192610f6c565b5f613a7a565b8160301161032757613a06917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613ae5614734565b90613afc613af384866138c5565b969094866138d6565b94813b15610327576801bc16d674ec8000005f94613b6297604051988996879586946304512a2360e31b865260806004870152613b53613b408d6084890190612326565b60031994858983030160248a0152611bc5565b9286840301604487015261233e565b90606483015203925af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192612c1592613bab575b506040519182918261395d565b613bb490610f6c565b5f613b9e565b6001600160801b0390818111613bce571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613c755760028355814710613c5d575f918291829182916001600160a01b03165af1613c3f612511565b5015613c4b5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b03821681158015613cb6575b15613ca95750905090565b6106979260801c9161284b565b508015613c9e565b6098546001600160801b0381169082158015613d0e575b15613cdf57505090565b60801c90613cee82828561284b565b92821561242c5709613cfd5790565b600181018091111561069757611ef2565b508115613cd5565b613d1e613689565b6001600160a01b03168015613d6657606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61020180546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b9190613dc9613689565b6001600160a01b038316908115610ba0578015613e755780613df06119f260985460801c90565b0193613dfa61224c565b8511613e6357610a3794613e2191613e1c613e1485613cbe565b978893613bba565b613f33565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613e93613689565b6001600160a01b038216918215610ba0578115613e755781613eba6119f260985460801c90565b01613ec361224c565b8111613e6357610a3795613f0a613e5e927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613e1c613f0288613cbe565b9a8b93613bba565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613f3c82613bba565b60985490613f546001600160801b0391828416612cdf565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609a549068010000000000000000821015610f67576001820180609a558210156124ff57609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614cd383398151915290910155565b919091801561408757613fee614969565b908101809111611442576001600160a01b03808211614067576001600160601b039081851161404757906121fe9394614042926040519461402e86610f4c565b168452166001600160601b03166020830152565b613f7f565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b6140a1614969565b60018101809111611442576001600160a01b0380821161406757906121fe91604051916140cd83610f4c565b1681525f6020820152613f7f565b8015614087576140e9614969565b908101809111611442576001600160a01b0380821161406757906121fe91604051916140cd83610f4c565b9080821015614121575090565b905090565b93929190916141336149ab565b61413b613689565b6001600160a01b0385165f9081526101376020526040902061415c90611ecd565b946001600160801b0361417687516001600160801b031690565b161561434257614185866126a8565b6001600160a01b0381165f908152609c602052604090206141ae906141a9906108c2565b6149cc565b955f198414614312575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610576575f966142f1575b50859861424a61423d61422d84613bba565b86516001600160801b0316612cdf565b6001600160801b03168552565b61425e6119f285516001600160801b031690565b116142df577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58956142a76142da946104de8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61430b91965060203d60201161056f576105618183610fb5565b945f61421b565b92506143286119f284516001600160801b031690565b80871115614338578603926141b8565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576576143ad9161439d915f916143b2575b50613bba565b6001600160801b03166020880152565b614185565b6143cb915060203d60201161056f576105618183610fb5565b5f614397565b60018060a01b03165f52609c60205260405f20908154818103908111611442576143fb9255613bba565b609854906001600160801b03908183160316906001600160801b03191617609855565b61442661443f565b61442e61462d565b60d354810361443a5750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561446e57565b604051631afcd79f60e31b8152600490fd5b61448861443f565b801561449e57600181016144995750565b609d55565b6040516331278a8760e01b8152600490fd5b6144b861443f565b6801bc16d674ec8000006144ca61224c565b1061449e5761443a61462d565b6144df61443f565b6001600160a01b0316806144f05750565b61016a80546001600160a01b0319169091179055565b61450e61443f565b61451661443f565b61451e61443f565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614557576120483430613dbf565b60405163ea2559bb60e01b8152600490fd5b90816020910312610327575160ff811681036103275790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948161460c575b506145d257604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614d1383398151915284036145f3576121fe929350614ad6565b604051632a87526960e21b815260048101859052602490fd5b61462691955060203d60201161056f576105618183610fb5565b935f6145ac565b6e5661756c7456616c696461746f727360881b602060405161464e81610f4c565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610f675760405251902090565b815191906041830361472a576147239250602082015190606060408401519301515f1a90614b78565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261069781610f4c565b60018060a01b0381165f5261013760205260405f20906040519161478083610f4c565b54906001600160801b03918281169081855260801c602085015215612022576141a96108c26147d3926147b1613689565b6147ba866126a8565b6001600160a01b03165f908152609c6020526040902090565b915116116142df57565b9291908015611b40576001600160a01b03828116928315610ba057614803611765614bfa565b6148f05790611873956148d4612d96857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f95816148a961484e6119f26099546001600160801b031690565b926122ac61487b85614876614861614969565b6148706119f2609e5460801c90565b90612467565b612467565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c602052604090206148cc83825461226f565b905501613bba565b6040805188815260208101959095529116929081908101613e5e565b9293946148fc83611f69565b938415613e75577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea8348093614946866149619361493c610a37612e3184613bba565b61319c84876143d1565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b609a548061497657505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b0316611299565b6149b3614bfa565b156149ba57565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561057657614a67936001600160401b0361089d6040614a46946020975f91614ab7575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610576575f91614a9e575090565b610697915060203d60201161056f576105618183610fb5565b614ad0915060603d606011610b7057610b618183610fb5565b5f614a37565b90813b15614b57575f80516020614d1383398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614b3c5761204891614c69565b505034614b4557565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614bef579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610576575f516001600160a01b03811615614be557905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f91614c50575090565b610697915060203d60201161119f576111908183610fb5565b5f8061069793602081519101845af4614c80612511565b9190614c965750805115613c4b57805190602001fd5b81511580614cc9575b614ca7575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614c9f56fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212204c918f55e91104380be7ef7c103845b4c187704a0f4748c5828f43eed67deeb664736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612695565b005b5f3560e01c806301d523b61461031157806301e1d1141461030c578063066055e01461030757806307a2d13a146103025780630d392cd9146102fd57806318f72950146102f85780631a7ff553146102f3578063201b9eb5146102ee57806322758a4a146102e95780632999ad3f146102e45780632cdf7401146102df5780633229fa95146102da57806333194c0a146102d557806336fe59d2146102d05780633a98ef39146102cb578063439fab91146102c657806343e82a79146102c157806346904840146102bc5780634ec96b22146102b75780634f1ef286146102b257806352d1902d146102ad57806353156f28146102a857806354fd4d50146102a35780635c60da1b1461029e5780635cfc1a511461029957806360d60e6e1461029457806372b410a81461028f578063754c38881461028a57806376b58b90146102855780637fd6f15c1461028057806383d430d51461027b5780638697d2c2146102765780638ceab9aa146102715780639267842a1461026c578063a49a1e7d14610267578063ac9650d814610262578063ad3cb1cc1461025d578063b1f0e7c714610258578063c6e6f59214610253578063d83ad00c1461024e578063e74b981b14610249578063ee3bd5df14610244578063f04da65b1461023f578063f6a6830f1461023a578063f851a44014610235578063f9609f08146102305763f98f5b920361000e57611e86565b611e5c565b611e35565b611df4565b611db9565b611d93565b611d66565b611d40565b611d22565b611d08565b611cc3565b611c4d565b611b52565b61195e565b61192a565b611784565b6115b4565b611590565b61153f565b6114d4565b611447565b6113a2565b611388565b611354565b611339565b611315565b6112ac565b611027565b610ec2565b610e9a565b610d8d565b610cc7565b610c46565b610c32565b610bf8565b610bcc565b610bb2565b61070f565b6106bd565b61069a565b61063b565b6105d5565b6105a3565b61057b565b6103d7565b6103a6565b610339565b6001600160a01b0381160361032757565b5f80fd5b908160809103126103275790565b60803660031901126103275760043561035181610316565b60443561035d81610316565b606435906001600160401b0382116103275760209261038b61038661039494369060040161032b565b612027565b602435906120bc565b604051908152f35b5f91031261032757565b34610327575f36600319011261032757602060985460801c604051908152f35b6001600160801b0381160361032757565b34610327576020366003190112610327576004356103f4816103c6565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610576575f91610547575b50335f9081526101376020526040902061047090611ecd565b916001600160801b0361048a84516001600160801b031690565b1615610535576104e3836104a0610531956126a8565b6104ca6104bd846104b884516001600160801b031690565b611f1e565b6001600160801b03168252565b335f90815261013760205260409020611f37565b611f37565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610569915060203d60201161056f575b6105618183610fb5565b810190611eb3565b5f610457565b503d610557565b611ec2565b34610327576020366003190112610327576020610394600435611f69565b8015150361032757565b34610327576040366003190112610327576100206004356105c381610316565b602435906105d082610599565b611f8f565b6060366003190112610327576004356105ed81610316565b6024356105f981610316565b604435906001600160401b0382116103275760209261062261038661039494369060040161032b565b61062b33612ece565b61063481612ece565b3490613e87565b34610327576020366003190112610327576004356001600160401b0381116103275761038661002091369060040161032b565b60609060031901126103275760043561068681610316565b906024359060443561069781610316565b90565b346103275760206103946106ad3661066e565b916106b733612ece565b33614126565b34610327575f36600319011261032757610201546040516001600160a01b039091168152602090f35b6060906003190112610327576004359060243561070281610316565b9060443561069781610316565b346103275761071d366106e6565b906001600160a01b0380831615610ba057610736613689565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156103275760408051631d8557d760e01b815260049491905f81878183875af1801561057657610b87575b506001600160a01b0383165f908152610137602052604090206107a990611ecd565b6001600160801b0392836107c483516001600160801b031690565b1615610b77576107d3826126a8565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610576575f98610b46575b50602097888101956001600160401b0391828061084c8a516001600160401b031690565b1614610b3657908c92918751918c83806108786303d1689d60e11b988983528a83019190602083019252565b03818a5afa918215610576576108a4938e5f94610b11575b5050516001600160801b03165b16906127d7565b966108c86108c28a60018060a01b03165f52609c60205260405f2090565b54611f69565b928389118015610b01575b610af157908b61091193926108ef89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561057657670de0b6b3a764000094610960948e5f95610ac4575b50506109526109446109589261244a565b93516001600160401b031690565b9361244a565b92169061284b565b1015610ab6578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610576577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610a9395610a0a93610a98575b50506109ed6104bd6109dd8c613bba565b83516001600160801b0316611f1e565b6001600160a01b0386165f90815261013760205260409020611f37565b610a1382613c87565b90610a52610a37610a2385613bba565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610a5c82866143d1565b610a668389613bed565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610aae92903d1061056f576105618183610fb5565b505f806109cc565b835163185cfc6d60e11b8152fd5b610958929550610ae7610952928261094493903d1061056f576105618183610fb5565b959250508e610933565b875163efda1a2760e01b81528590fd5b50610b0a61204b565b89116108d3565b61089d9294509081610b2e92903d1061056f576105618183610fb5565b92908e610890565b8651630709133160e01b81528490fd5b610b6991985060603d606011610b70575b610b618183610fb5565b810190612f04565b965f610828565b503d610b57565b825163673f032f60e11b81528790fd5b80610b94610b9a92610f6c565b8061039c565b5f610787565b60405163d92e233d60e01b8152600490fd5b34610327575f36600319011261032757602061039461204b565b34610327575f366003190112610327576020610be6612081565b6040516001600160a01b039091168152f35b34610327575f3660031901126103275760206040517fa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d98152f35b6020610394610c403661066e565b916120bc565b34610327575f3660031901126103275760206001600160801b0360985416604051908152f35b9181601f84011215610327578235916001600160401b038311610327576020838186019501011161032757565b602060031982011261032757600435906001600160401b03821161032757610cc391600401610c6c565b9091565b610cd036610c99565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610d79575b610d675768010000000000000003610d2a9368ffffffffffffffffff191617845561217d565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610d04565b3461032757610d9b366106e6565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105765782915f91610e6b575b50163303610e595781610a93610e2686867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396612f44565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610e8d915060203d602011610e93575b610e858183610fb5565b8101906120e9565b5f610dee565b503d610e7b565b34610327575f366003190112610327576065546040516001600160a01b039091168152602090f35b3461032757602036600319011261032757600435610edf81610316565b60018060a01b03165f52610137602052602060405f2060405190610f0282610f4c565b54906001600160801b03918281169081835260801c84830152610f2a575b5116604051908152f35b610f33816126a8565b610f20565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b03821117610f6757604052565b610f38565b6001600160401b038111610f6757604052565b606081019081106001600160401b03821117610f6757604052565b608081019081106001600160401b03821117610f6757604052565b90601f801991011681019081106001600160401b03821117610f6757604052565b6001600160401b038111610f6757601f01601f191660200190565b929192610ffd82610fd6565b9161100b6040519384610fb5565b829481845281830111610327578281602093845f960137010152565b60408060031936011261032757600490813561104281610316565b6024356001600160401b0381116103275736602382011215610327576110719036906024818701359101610ff1565b9161107a61345d565b8051926110b1846110a360209363439fab9160e01b858401528460248401526044830190611bc5565b03601f198101865285610fb5565b6110b961345d565b6110c16134b6565b6001600160a01b03838116801592919087908415611277575b8415611209575b84156111a6575b50508215611110575b5050611101576100208383614582565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610576575f92611179575b5050155f806110f1565b6111989250803d1061119f575b6111908183610fb5565b81019061225a565b5f8061116f565b503d611186565b855163054fd4d560e41b81529294508391839182905afa90811561057657879160ff915f916111dc575b5016141591865f6110e8565b6111fc9150843d8611611202575b6111f48183610fb5565b810190614569565b5f6111d0565b503d6111ea565b935050835163198ca60560e11b815282818981875afa9081156105765788917fa90b5863127e5f962890f832f07b9f40c8df2fc043326a0e4b538552d600f2d9915f9161125a575b501415936110e1565b6112719150853d871161056f576105618183610fb5565b5f611251565b5f80516020614d138339815191525490945084906112a5906001600160a01b03165b6001600160a01b031690565b14936110da565b34610327575f366003190112610327577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036113035760206040515f80516020614d138339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f366003190112610327576001600160a01b03611330612081565b163303610e5957005b34610327575f36600319011261032757602060405160038152f35b34610327575f366003190112610327575f80516020614d13833981519152546040516001600160a01b039091168152602090f35b34610327575f36600319011261032757602061039461224c565b3461032757602036600319011261032757609a80549081905f6004355b8482106113f0575050508110156113e557610531905b6040519081529081906020820190565b506105315f196113d5565b909193808316906001818518811c8301809311611442575f8790525f80516020614cd38339815191528301546001600160a01b0316841015611437575050935b91906113bf565b909591019250611430565b611ef2565b34610327575f36600319011261032757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610576576020915f916114b7575b506040519015158152f35b6114ce9150823d841161119f576111908183610fb5565b5f6114ac565b34610327576020366003190112610327576004356114f181610316565b6114f96134b6565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346103275760803660031901126103275761053161157360043561156281610316565b60643590604435906024359061227c565b604080519384526020840192909252908201529081906060820190565b34610327575f36600319011261032757602061ffff60655460a01c16604051908152f35b34610327576003196040368201126103275760049081356001600160401b038082116103275760a082850193833603011261032757602435908111610327576116009036908501610c6c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156103275760405163837d444160e01b8152905f9082908183816116538c828f0161235e565b03925af1801561057657611771575b5061166b613689565b61167361265f565b9081163314159182611742575b50509050611731576044019160b061169884846123dc565b90500480158015611719575b611709576116b96116b361204b565b91612431565b116116fa575060b06116cb83836123dc565b9050145f146116e757610020916116e1916123dc565b90613aa7565b610020916116f4916123dc565b9061397f565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b5061172484846123dc565b905060b0820214156116a4565b604051634ca8886760e01b81528390fd5b611765925061175f6117699461175788613714565b923691610ff1565b916137ee565b1590565b805f80611680565b80610b9461177e92610f6c565b5f611662565b34610327576060366003190112610327576004356024356117a960443582843361227c565b91926117d57f000000000000000000000000000000000000000000000000000000000000000082612467565b42108015611922575b801561191a575b611908577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb569361184061182561181a86613bba565b60995460801c611f1e565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916118849190611873608082610fb5565b5190205f52609b60205260405f2090565b555f93600183116118bd575b5050505061189e8233613bed565b604080519485526020850191909152830152339180606081015b0390a2005b6118fe929394506118ce9088612467565b60408051336020820190815291810193909352606083018290526080958601835290949091906118739082610fb5565b555f808080611890565b604051630e3d8e8d60e11b8152600490fd5b5082156117e5565b5081156117de565b3461032757604036600319011261032757602061195560243561194c81610316565b600435336147dd565b6103943361475d565b346103275760203660031901126103275760043561197a613689565b335f9081526101376020526040902061199290611ecd565b6001600160801b03806119ac83516001600160801b031690565b16156105355782906119bd836126a8565b82516001600160801b03161610611b4057335f908152609c6020526040902054826119fe6119f284516001600160801b031690565b6001600160801b031690565b14611b2a57611a229083611a1c6119f285516001600160801b031690565b9161284b565b91611a4f611a42611a3283613bba565b84516001600160801b0316610a2a565b6001600160801b03168352565b335f90815261013760205260409020611a69908390611f37565b611ab16020611aa260018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336147dd565b9301516001600160801b031690565b833b156103275760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af19182156105765761053192611b17575b506040519081529081906020820190565b80610b94611b2492610f6c565b5f611b06565b335f908152610137602052604081205591611a69565b604051636edcc52360e01b8152600490fd5b34610327576118b87f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611b8436610c99565b9290611b8e6134b6565b604051918291602083523395602084019161233e565b5f5b838110611bb55750505f910152565b8181015183820152602001611ba6565b90602091611bde81518092818552858086019101611ba4565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611c1f5750505050505090565b9091929394958480611c3d600193603f198682030187528a51611bc5565b9801930193019194939290611c0f565b34610327576020366003190112610327576001600160401b036004358181116103275736602382011215610327578060040135918211610327573660248360051b8301011161032757610531916024611ca692016125b2565b60405191829182611bea565b906020610697928181520190611bc5565b34610327575f36600319011261032757610531604051611ce281610f4c565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611bc5565b34610327575f366003190112610327576020610be661265f565b34610327576020366003190112610327576020610394600435613c87565b34610327575f3660031901126103275760206001600160801b0360995416604051908152f35b3461032757602036600319011261032757610020600435611d8681610316565b611d8e6134b6565b613d16565b34610327575f3660031901126103275760206001600160801b03609e5416604051908152f35b3461032757602036600319011261032757600435611dd681610316565b60018060a01b03165f52609c602052602060405f2054604051908152f35b3461032757602036600319011261032757600435611e1181610316565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b34610327575f366003190112610327575f546040516001600160a01b039091168152602090f35b6040366003190112610327576020610394600435611e7981610316565b6024359061062282610316565b3461032757602036600319011261032757610020600435611ea681610316565b611eae6134b6565b613d78565b90816020910312610327575190565b6040513d5f823e3d90fd5b90604051611eda81610f4c565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f19019190821161144257565b6001600160801b03918216908216039190821161144257565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b0381169081611f8157505090565b916106979260801c9061284b565b610201546001600160a01b03919082163303610e59576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612022576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b61203361203a916129b3565b9190612b49565b61204057565b612048612cfa565b50565b476099546001600160801b03612062818316611f69565b90609e5416019060801c01908181115f1461207b570390565b50505f90565b61016a546001600160a01b031680156120975790565b507f000000000000000000000000000000000000000000000000000000000000000090565b9061069792916120cb33612ece565b6120d433612ece565b6120df833433613e87565b506106b733612ece565b90816020910312610327575161069781610316565b906020828203126103275781356001600160401b0392838211610327570191606083830312610327576040519261213484610f7f565b80358452602081013561ffff81168103610327576020850152604081013591821161032757019080601f830112156103275781602061217593359101610ff1565b604082015290565b5f549091906001600160a01b03166122425760405163e7f6f22560e01b8152906020908183600481335afa928315610576575f93612223575b50604051636f4fa30f60e01b8152938285600481335afa908115610576576121fe956121f9945f93612200575b50506121f291928101906120fe565b9083613369565b613451565b565b6121f29350908161221c92903d10610e9357610e858183610fb5565b915f6121e3565b61223b919350823d8411610e9357610e858183610fb5565b915f6121b6565b50506121fe61325d565b609d548061069757505f1990565b90816020910312610327575161069781610599565b9190820391821161144257565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906122ba81608081015b03601f198101835282610fb5565b5190205f52609b60205260405f20549182156122ea576122db9183916134ee565b90918281039081116114425792565b5050505f905f905f90565b9035601e19823603018112156103275701602081359101916001600160401b03821161032757813603831361032757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06106979260208152823560208201526020830135604082015261239a61238a60408501856122f5565b84606085015260c084019161233e565b906123cd6123c26123ae60608701876122f5565b601f1985870381016080870152959161233e565b9460808101906122f5565b9390928286030191015261233e565b903590601e198136030182121561032757018035906001600160401b0382116103275760200191813603831361032757565b634e487b7160e01b5f52601260045260245ffd5b811561242c570490565b61240e565b906801bc16d674ec800000918083029283040361144257565b90670de0b6b3a76400009182810292818404149015171561144257565b9190820180921161144257565b6001600160401b038111610f675760051b60200190565b9061249582612474565b6124a26040519182610fb5565b82815280926124b3601f1991612474565b01905f5b8281106124c357505050565b8060606020809385010152016124b7565b634e487b7160e01b5f52603260045260245ffd5b908210156124ff57610cc39160051b8101906123dc565b6124d4565b908092918237015f815290565b3d1561253b573d9061252282610fd6565b916125306040519384610fb5565b82523d5f602084013e565b606090565b602081830312610327578051906001600160401b038211610327570181601f8201121561032757805161257281610fd6565b926125806040519485610fb5565b81845260208284010111610327576106979160208085019101611ba4565b80518210156124ff5760209160051b010190565b9190916125be8361248b565b925f5b8181106125cd57505050565b5f806125da8385876124e8565b604093916125ec855180938193612504565b0390305af4906125fa612511565b911561262157509060019161260f828861259e565b5261261a818761259e565b50016125c1565b9060448151106103275761265b61264660049283810151602480918301019101612540565b925162461bcd60e51b81529283928301611cb2565b0390fd5b60d2546001600160a01b03168061069757507f000000000000000000000000000000000000000000000000000000000000000090565b61269e33612ece565b6120483433613dbf565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f9161273e575b5060208201916001600160801b03918284511691828214612737578361272a61272561273295858486511661284b565b613bba565b169052613bba565b169052565b5050505050565b612757915060203d60201161056f576105618183610fb5565b5f6126f5565b90808202905f19818409908280831092039180830392146127cc5761271090828211156127ba577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461283a57670de0b6b3a764000090828211156127ba577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146128be57848311156127ba57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106979250612422565b90816060910312610327578051916040602083015192015161069781610599565b81835290916001600160fb1b0383116103275760209260051b809284830137010190565b90602082528035602083015260208101358060130b809103610327576040830152604081013561293f81610316565b6001600160a01b031660608381019190915281013536829003601e19018112156103275701602081359101906001600160401b038111610327578060051b360382136103275760a08360808061069796015201916128ec565b9190915f838201938412911290801582169115161761144257565b6040516325f56f1160e01b81526001600160a01b039291606090829081906129de9060048301612910565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610576575f915f905f95612b04575b508415612ab15781612a28612081565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612aaa57509060205f92600460405180958193634641257d60e01b83525af190811561057657612a85925f92612a89575b50612998565b9190565b612aa391925060203d60201161056f576105618183610fb5565b905f612a7f565b9081612ab7575b50509190565b803b1561032757604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561057657612af1575b80612ab1565b80610b94612afe92610f6c565b5f612aeb565b91945050612b2a915060603d606011612b32575b612b228183610fb5565b8101906128cb565b93905f612a18565b503d612b18565b600160ff1b8114611442575f0390565b801561204857612b5e6119f260985460801c90565b5f8212612c305781612b6f91612467565b90612b7c610a3783613bba565b612b916065549161ffff8360a01c169061275d565b801561202257807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793612bcf6119f26098546001600160801b031690565b80612c1a575050612c1590925b6001600160a01b031691612bf08484613f33565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b612c1592612c2a9203908461284b565b92612bdc565b90612c3a90612b39565b612c4f6119f2609e546001600160801b031690565b80612c6f575b5080612c5f575050565b612725610a37916121fe9361226f565b90612cd67f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916113d5612cba612caf612ca88888612467565b878561284b565b808094039603613bba565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f612c55565b9190916001600160801b038080941691160191821161144257565b612d1347612d0d6119f260995460801c90565b9061226f565b908115612ec957609e546001600160801b0381169081612e51575b5050612d456119f26099546001600160801b031690565b9182158015612e49575b612e4357612d6690612d6084611f69565b90614114565b8015612e4357612d7581613c87565b928315612e3c57612e316121fe92612db2612d9661272588610a379661226f565b6001600160801b03166001600160801b03196099541617609955565b612dcc611825612dc183613bba565b60995460801c612cdf565b612dd68187613fdd565b60408051878152602081018390525f80516020614cf38339815191529190a1612725612e15612e0488613bba565b6098546001600160801b0316611f1e565b6001600160801b03166001600160801b03196098541617609855565b60985460801c611f1e565b505f925050565b505f9150565b508015612d4f565b8184929410612e3c57612dc184612e99935f80516020614cf3833981519152826118259560801c612e828282613fdd565b604080519182526020820192909252a10394613bba565b612ead6001600160801b03609e5416609e55565b612ec26001600160801b0319609e5416609e55565b5f80612d2e565b5f9150565b6001600160a01b03165f908152610202602052604090205460ff1615610e5957565b51906001600160401b038216820361032757565b90816060910312610327576121756040805192612f2084610f7f565b8051612f2b816103c6565b8452612f3960208201612ef0565b602085015201612ef0565b92906001600160a01b039081811615610ba057612f5f613689565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561032757604094855193631d8557d760e01b85526004945f81878183895af180156105765761324a575b506001600160a01b0388165f90815261013760205260409020612fd290611ecd565b906001600160801b03612fec83516001600160801b031690565b161561323a57612ffb826126a8565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156105765761321b575b508651936303d1689d60e11b97888652602091828780613075888c83019190602083019252565b0381845afa968715610576575f976131fc575b5086996130a86108c28d60018060a01b03165f52609c60205260405f2090565b881180156131ec575b6131dc5790836130ee926130cc87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610576575f859488946131339c6131bf575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af1958615610576576109dd61317a9461315d936104bd936121fe9a6131a1575b5050613bba565b6001600160a01b0388165f90815261013760205260409020611f37565b61319c61318683613c87565b8097613197610a37610a2387613bba565b6143d1565b613bed565b816131b792903d1061056f576105618183610fb5565b505f80613156565b6131d590873d891161056f576105618183610fb5565b505f613108565b825163efda1a2760e01b81528990fd5b506131f561204b565b88116130b1565b613214919750833d851161056f576105618183610fb5565b955f613088565b6132339060603d606011610b7057610b618183610fb5565b505f61304e565b875163673f032f60e11b81528690fd5b80610b9461325792610f6c565b5f612fb0565b61326561443f565b61327a6119f26099546001600160801b031690565b60018111613357576001146132ee575b609f54613295614969565b908082106132b1575b50506132a95f609f55565b6121fe61441e565b5f80516020614cf3833981519152916132e491036132ce816140db565b604080519182525f602083015290918291820190565b0390a15f8061329e565b61330b612e156133066098546001600160801b031690565b611f06565b6133206001600160801b031960995416609955565b613328614099565b5f80516020614cf38339815191526040518061334f81905f60206040840193600181520152565b0390a161328a565b604051630299325160e41b8152600490fd5b61337161443f565b604083015161337e61443f565b6001600160a01b0382168015610ba0576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806133d733946020830190611bc5565b0390a26020830151926133e861443f565b61271061ffff85161161343f576134379361340561342a93613d16565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614480565b6134326144b0565b6144d7565b6121fe614506565b604051638a81d3b360e01b8152600490fd5b6121fe90611eae61443f565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821561349b575b505061130357565b5f80516020614d138339815191525416141590505f80613493565b5f546001600160a01b03163303610e5957565b906040516134d681610f4c565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613681575b613674578361363e575f5b609a5f526001600160a01b03166135335f80516020614cd383398151915286016134c9565b805190979061354a906001600160a01b0316611299565b9861356f6135636020809b01516001600160601b031690565b6001600160601b031690565b948381108015613634575b6136225791600193979a956135996135a5939488035b838c0390614114565b8092019887039161284b565b01970193808611801590613618575b61360d57609a5f5282906135d65f80516020614cd383398151915287016134c9565b805190890151969992966001600160a01b0390911694600193926135a59290916001600160601b0390911690613599908803613590565b945050509250509190565b50818510156135b4565b60405163e8722f8f60e01b8152600490fd5b50808b111561357a565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b031661350e565b505093505050505f905f90565b508415613503565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f916136f5575b506136e357565b60405163e775715160e01b8152600490fd5b61370e915060203d60201161119f576111908183610fb5565b5f6136dc565b604290467f0000000000000000000000000000000000000000000000000000000000000000036137c25760d354905b61375a61375360408301836123dc565b3691610ff1565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526137a581610f9a565b5190206040519161190160f01b8352600283015260228201522090565b6137ca61462d565b90613743565b600411156137da57565b634e487b7160e01b5f52602160045260245ffd5b6137f883836146fa565b50613805819592956137d0565b1593846138a1575b50831561381b575b50505090565b5f929350908291604051613853816122ac6020820194630b135d3f60e11b998a87526024840152604060448401526064830190611bc5565b51915afa90613860612511565b82613893575b82613876575b50505f8080613815565b61388b91925060208082518301019101611eb3565b145f8061386c565b915060208251101591613866565b6001600160a01b0383811691161493505f61380d565b906030116103275790603090565b906090116103275760300190606090565b9060b0116103275760900190602090565b90939293848311610327578411610327578101920390565b35906020811061390d575090565b5f199060200360031b1b1690565b969594906139589361393c61394a926060979560808c5260808c019161233e565b9089820360208b0152611bc5565b91878303604089015261233e565b930152565b906020610697928181520190612326565b91602061069793818152019161233e565b60b091828104915f9081613991614734565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b8784106139d357505050505050505050565b826139e29101809288876138e7565b906139ed82826138b7565b91613a0c613a066139fe86846138c5565b9690936138d6565b906138ff565b90893b15610327575f908d613a39604094855198899485946304512a2360e31b86528a8a6004880161391b565b03816801bc16d674ec8000008d5af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194613a8592613a94575b50519283928361396e565b0390a1600181930192906139c1565b80610b94613aa192610f6c565b5f613a7a565b8160301161032757613a06917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613ae5614734565b90613afc613af384866138c5565b969094866138d6565b94813b15610327576801bc16d674ec8000005f94613b6297604051988996879586946304512a2360e31b865260806004870152613b53613b408d6084890190612326565b60031994858983030160248a0152611bc5565b9286840301604487015261233e565b90606483015203925af1908115610576577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192612c1592613bab575b506040519182918261395d565b613bb490610f6c565b5f613b9e565b6001600160801b0390818111613bce571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613c755760028355814710613c5d575f918291829182916001600160a01b03165af1613c3f612511565b5015613c4b5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b03821681158015613cb6575b15613ca95750905090565b6106979260801c9161284b565b508015613c9e565b6098546001600160801b0381169082158015613d0e575b15613cdf57505090565b60801c90613cee82828561284b565b92821561242c5709613cfd5790565b600181018091111561069757611ef2565b508115613cd5565b613d1e613689565b6001600160a01b03168015613d6657606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61020180546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b9190613dc9613689565b6001600160a01b038316908115610ba0578015613e755780613df06119f260985460801c90565b0193613dfa61224c565b8511613e6357610a3794613e2191613e1c613e1485613cbe565b978893613bba565b613f33565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613e93613689565b6001600160a01b038216918215610ba0578115613e755781613eba6119f260985460801c90565b01613ec361224c565b8111613e6357610a3795613f0a613e5e927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613e1c613f0288613cbe565b9a8b93613bba565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613f3c82613bba565b60985490613f546001600160801b0391828416612cdf565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609a549068010000000000000000821015610f67576001820180609a558210156124ff57609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614cd383398151915290910155565b919091801561408757613fee614969565b908101809111611442576001600160a01b03808211614067576001600160601b039081851161404757906121fe9394614042926040519461402e86610f4c565b168452166001600160601b03166020830152565b613f7f565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b6140a1614969565b60018101809111611442576001600160a01b0380821161406757906121fe91604051916140cd83610f4c565b1681525f6020820152613f7f565b8015614087576140e9614969565b908101809111611442576001600160a01b0380821161406757906121fe91604051916140cd83610f4c565b9080821015614121575090565b905090565b93929190916141336149ab565b61413b613689565b6001600160a01b0385165f9081526101376020526040902061415c90611ecd565b946001600160801b0361417687516001600160801b031690565b161561434257614185866126a8565b6001600160a01b0381165f908152609c602052604090206141ae906141a9906108c2565b6149cc565b955f198414614312575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610576575f966142f1575b50859861424a61423d61422d84613bba565b86516001600160801b0316612cdf565b6001600160801b03168552565b61425e6119f285516001600160801b031690565b116142df577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58956142a76142da946104de8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b61430b91965060203d60201161056f576105618183610fb5565b945f61421b565b92506143286119f284516001600160801b031690565b80871115614338578603926141b8565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576576143ad9161439d915f916143b2575b50613bba565b6001600160801b03166020880152565b614185565b6143cb915060203d60201161056f576105618183610fb5565b5f614397565b60018060a01b03165f52609c60205260405f20908154818103908111611442576143fb9255613bba565b609854906001600160801b03908183160316906001600160801b03191617609855565b61442661443f565b61442e61462d565b60d354810361443a5750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561446e57565b604051631afcd79f60e31b8152600490fd5b61448861443f565b801561449e57600181016144995750565b609d55565b6040516331278a8760e01b8152600490fd5b6144b861443f565b6801bc16d674ec8000006144ca61224c565b1061449e5761443a61462d565b6144df61443f565b6001600160a01b0316806144f05750565b61016a80546001600160a01b0319169091179055565b61450e61443f565b61451661443f565b61451e61443f565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca003410614557576120483430613dbf565b60405163ea2559bb60e01b8152600490fd5b90816020910312610327575160ff811681036103275790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948161460c575b506145d257604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614d1383398151915284036145f3576121fe929350614ad6565b604051632a87526960e21b815260048101859052602490fd5b61462691955060203d60201161056f576105618183610fb5565b935f6145ac565b6e5661756c7456616c696461746f727360881b602060405161464e81610f4c565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610f675760405251902090565b815191906041830361472a576147239250602082015190606060408401519301515f1a90614b78565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261069781610f4c565b60018060a01b0381165f5261013760205260405f20906040519161478083610f4c565b54906001600160801b03918281169081855260801c602085015215612022576141a96108c26147d3926147b1613689565b6147ba866126a8565b6001600160a01b03165f908152609c6020526040902090565b915116116142df57565b9291908015611b40576001600160a01b03828116928315610ba057614803611765614bfa565b6148f05790611873956148d4612d96857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f95816148a961484e6119f26099546001600160801b031690565b926122ac61487b85614876614861614969565b6148706119f2609e5460801c90565b90612467565b612467565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c602052604090206148cc83825461226f565b905501613bba565b6040805188815260208101959095529116929081908101613e5e565b9293946148fc83611f69565b938415613e75577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea8348093614946866149619361493c610a37612e3184613bba565b61319c84876143d1565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b609a548061497657505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b0316611299565b6149b3614bfa565b156149ba57565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561057657614a67936001600160401b0361089d6040614a46946020975f91614ab7575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610576575f91614a9e575090565b610697915060203d60201161056f576105618183610fb5565b614ad0915060603d606011610b7057610b618183610fb5565b5f614a37565b90813b15614b57575f80516020614d1383398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614b3c5761204891614c69565b505034614b4557565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614bef579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610576575f516001600160a01b03811615614be557905f905f90565b505f906001905f90565b5050505f9160039190565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610576575f91614c50575090565b610697915060203d60201161119f576111908183610fb5565b5f8061069793602081519101845af4614c80612511565b9190614c965750805115613c4b57805190602001fd5b81511580614cc9575b614ca7575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614c9f56fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212204c918f55e91104380be7ef7c103845b4c187704a0f4748c5828f43eed67deeb664736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthValidatorsRegistry.json b/test/shared/artifacts/EthValidatorsRegistry.json deleted file mode 100644 index af66ce6c..00000000 --- a/test/shared/artifacts/EthValidatorsRegistry.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "amount", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "index", - "type": "bytes" - } - ], - "name": "DepositEvent", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "deposit_data_root", - "type": "bytes32" - } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "get_deposit_count", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "get_deposit_root", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b5060005b601f8110156101025760026021826020811061002c57fe5b01546021836020811061003b57fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b602083106100925780518252601f199092019160209182019101610073565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa1580156100d1573d6000803e3d6000fd5b5050506040513d60208110156100e657600080fd5b5051602160018301602081106100f857fe5b0155600101610014565b506118d680620001136000396000f3fe60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220dceca8706b29e917dacf25fceef95acac8d90d765ac926663ce4096195952b6164736f6c634300060b0033" -} \ No newline at end of file diff --git a/test/shared/artifacts/EthVault.json b/test/shared/artifacts/EthVault.json deleted file mode 100644 index 6d7fb4ae..00000000 --- a/test/shared/artifacts/EthVault.json +++ /dev/null @@ -1,1638 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthVault", - "sourceName": "contracts/vaults/ethereum/EthVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidQueuedShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "depositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - } - ], - "name": "transferOsTokenPositionToEscrow", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDepositAndMintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6101e034620002695762004dad6001600160401b03601f38839003908101601f1916840190828211858310176200026d5780859460409384528539610120938491810103126200026957620000548462000281565b91620000636020860162000281565b916200007181870162000281565b93620000806060880162000281565b916200008f6080890162000281565b936200009e60a08a0162000281565b95620000ad60c08b0162000281565b97620000bc60e08c0162000281565b91610100809c01519560805260a05260c0523060e052895246885261014092835260018060a01b03806101609516855280610180961686526101a0961686526101c09687527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166200025857808083160362000213575b5050505195614b1697886200029789396080518881816113cc015281816115640152818161280201528181613744015261489f015260a05188611099015260c051888181613a340152613b55015260e05188818161121801526135070152518761249c015251866137ba0152518561170a0152518481816103f401528181610686015281816124dd01528181612db501528181612f220152818161300e015261423f01525183818161074501528181610d16015281816130cd01526141c3015251826119d4015251818181611eee015261284a0152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200013c565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002695756fe60806040526004361015610022575b3615610018575f80fd5b6100206124be565b005b5f3560e01c806301d523b6146102d157806301e1d114146102cc578063066055e0146102c757806307a2d13a146102c257806318f72950146102bd5780631a7ff553146102b8578063201b9eb5146102b35780632999ad3f146102ae5780632cdf7401146102a95780633229fa95146102a457806333194c0a1461029f57806336fe59d21461029a5780633a98ef3914610295578063439fab911461029057806343e82a791461028b57806346904840146102865780634ec96b22146102815780634f1ef2861461027c57806352d1902d1461027757806353156f281461027257806354fd4d501461026d5780635c60da1b146102685780635cfc1a511461026357806360d60e6e1461025e57806372b410a814610259578063754c38881461025457806376b58b901461024f5780637fd6f15c1461024a57806383d430d5146102455780638697d2c2146102405780638ceab9aa1461023b5780639267842a14610236578063a49a1e7d14610231578063ac9650d81461022c578063ad3cb1cc14610227578063b1f0e7c714610222578063c6e6f5921461021d578063d83ad00c14610218578063e74b981b14610213578063ee3bd5df1461020e578063f04da65b14610209578063f851a440146102045763f9609f080361000e57611d75565b611d4e565b611d13565b611ced565b611cc0565b611c9a565b611c7c565b611c62565b611c1d565b611ba7565b611aac565b6118b8565b611884565b6116de565b61150e565b6114ea565b611499565b61142e565b6113a1565b6112fc565b6112e2565b6112ae565b611293565b61126f565b611206565b610f81565b610e1c565b610df4565b610ce7565b610c21565b610ba0565b610b7f565b610b45565b610b19565b610aff565b61065c565b610619565b6105ba565b610566565b610548565b6103a4565b610373565b6102f9565b6001600160a01b038116036102e757565b5f80fd5b908160809103126102e75790565b60803660031901126102e757600435610311816102d6565b60443561031d816102d6565b606435906001600160401b0382116102e75760209261034b6103466103619436906004016102eb565b611e7b565b610356823433613ee0565b506024359033612cf1565b604051908152f35b5f9103126102e757565b346102e7575f3660031901126102e757602060985460801c604051908152f35b6001600160801b038116036102e757565b346102e75760203660031901126102e7576004356103c181610393565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610543575f91610514575b50335f9081526101376020526040902061043d90611db9565b916001600160801b0361045784516001600160801b031690565b1615610502576104b08361046d6104fe956124c8565b61049761048a8461048584516001600160801b031690565b611e0a565b6001600160801b03168252565b335f90815261013760205260409020611e23565b611e23565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610536915060203d60201161053c575b61052e8183610f0f565b810190611d9f565b5f610424565b503d610524565b611dae565b346102e75760203660031901126102e7576020610361600435611e55565b60603660031901126102e75760043561057e816102d6565b60243561058a816102d6565b604435906001600160401b0382116102e7576020926105b36103466103619436906004016102eb565b3490613ee0565b346102e75760203660031901126102e7576004356001600160401b0381116102e7576103466100209136906004016102eb565b60609060031901126102e757600435610605816102d6565b9060243590604435610616816102d6565b90565b346102e757602061036161062c366105ed565b9133612cf1565b60609060031901126102e7576004359060243561064f816102d6565b90604435610616816102d6565b346102e75761066a36610633565b906001600160a01b0380831615610aed57610683613729565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102e75760408051631d8557d760e01b815260049491905f81878183875af1801561054357610ad4575b506001600160a01b0383165f908152610137602052604090206106f690611db9565b6001600160801b03928361071183516001600160801b031690565b1615610ac457610720826124c8565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610543575f98610a93575b50602097888101956001600160401b039182806107998a516001600160401b031690565b1614610a8357908c92918751918c83806107c56303d1689d60e11b988983528a83019190602083019252565b03818a5afa918215610543576107f1938e5f94610a5e575b5050516001600160801b03165b16906125f7565b9661081561080f8a60018060a01b03165f52609c60205260405f2090565b54611e55565b928389118015610a4e575b610a3e57908b61085e939261083c89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561054357670de0b6b3a7640000946108ad948e5f95610a11575b505061089f6108916108a592612273565b93516001600160401b031690565b93612273565b92169061266b565b1015610a03578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610543577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c5350976109e095610957936109e5575b505061093a61048a61092a8c613c5a565b83516001600160801b0316611e0a565b6001600160a01b0386165f90815261013760205260409020611e23565b61096082613d27565b9061099f61098461097085613c5a565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b6109a982866142aa565b6109b38389613c8d565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b816109fb92903d1061053c5761052e8183610f0f565b505f80610919565b835163185cfc6d60e11b8152fd5b6108a5929550610a3461089f928261089193903d1061053c5761052e8183610f0f565b959250508e610880565b875163efda1a2760e01b81528590fd5b50610a57611e9f565b8911610820565b6107ea9294509081610a7b92903d1061053c5761052e8183610f0f565b92908e6107dd565b8651630709133160e01b81528490fd5b610ab691985060603d606011610abd575b610aae8183610f0f565b810190612fb0565b965f610775565b503d610aa4565b825163673f032f60e11b81528790fd5b80610ae1610ae792610ec6565b80610369565b5f6106d4565b60405163d92e233d60e01b8152600490fd5b346102e7575f3660031901126102e7576020610361611e9f565b346102e7575f3660031901126102e7576020610b33611ed5565b6040516001600160a01b039091168152f35b346102e7575f3660031901126102e75760206040517fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b8152f35b6020610361610b8d366105ed565b91610b99833433613ee0565b5033612cf1565b346102e7575f3660031901126102e75760206001600160801b0360985416604051908152f35b9181601f840112156102e7578235916001600160401b0383116102e757602083818601950101116102e757565b60206003198201126102e757600435906001600160401b0382116102e757610c1d91600401610bc6565b9091565b610c2a36610bf3565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610cd3575b610cc15768010000000000000003610c849368ffffffffffffffffff1916178455611fa4565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610c5e565b346102e757610cf536610633565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105435782915f91610dc5575b50163303610db357816109e0610d8086867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396612ff0565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610de7915060203d602011610ded575b610ddf8183610f0f565b810190611f10565b5f610d48565b503d610dd5565b346102e7575f3660031901126102e7576065546040516001600160a01b039091168152602090f35b346102e75760203660031901126102e757600435610e39816102d6565b60018060a01b03165f52610137602052602060405f2060405190610e5c82610ea6565b54906001600160801b03918281169081835260801c84830152610e84575b5116604051908152f35b610e8d816124c8565b610e7a565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b03821117610ec157604052565b610e92565b6001600160401b038111610ec157604052565b606081019081106001600160401b03821117610ec157604052565b608081019081106001600160401b03821117610ec157604052565b90601f801991011681019081106001600160401b03821117610ec157604052565b6001600160401b038111610ec157601f01601f191660200190565b929192610f5782610f30565b91610f656040519384610f0f565b8294818452818301116102e7578281602093845f960137010152565b6040806003193601126102e7576004908135610f9c816102d6565b6024356001600160401b0381116102e757366023820112156102e757610fcb9036906024818701359101610f4b565b91610fd46134fd565b80519261100b84610ffd60209363439fab9160e01b858401528460248401526044830190611b1f565b03601f198101865285610f0f565b6110136134fd565b61101b613556565b6001600160a01b038381168015929190879084156111d1575b8415611163575b8415611100575b5050821561106a575b505061105b57610020838361445b565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610543575f926110d3575b5050155f8061104b565b6110f29250803d106110f9575b6110ea8183610f0f565b810190612084565b5f806110c9565b503d6110e0565b855163054fd4d560e41b81529294508391839182905afa90811561054357879160ff915f91611136575b5016141591865f611042565b6111569150843d861161115c575b61114e8183610f0f565b810190614442565b5f61112a565b503d611144565b935050835163198ca60560e11b815282818981875afa9081156105435788917fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b915f916111b4575b5014159361103b565b6111cb9150853d871161053c5761052e8183610f0f565b5f6111ab565b5f80516020614ac18339815191525490945084906111ff906001600160a01b03165b6001600160a01b031690565b1493611034565b346102e7575f3660031901126102e7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361125d5760206040515f80516020614ac18339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126102e7576001600160a01b0361128a611ed5565b163303610db357005b346102e7575f3660031901126102e757602060405160038152f35b346102e7575f3660031901126102e7575f80516020614ac1833981519152546040516001600160a01b039091168152602090f35b346102e7575f3660031901126102e7576020610361612069565b346102e75760203660031901126102e757609a80549081905f6004355b84821061134a5750505081101561133f576104fe905b6040519081529081906020820190565b506104fe5f1961132f565b909193808316906001818518811c830180931161139c575f8790525f80516020614a818339815191528301546001600160a01b0316841015611391575050935b9190611319565b90959101925061138a565b611dde565b346102e7575f3660031901126102e757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610543576020915f91611411575b506040519015158152f35b6114289150823d84116110f9576110ea8183610f0f565b5f611406565b346102e75760203660031901126102e75760043561144b816102d6565b611453613556565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102e75760803660031901126102e7576104fe6114cd6004356114bc816102d6565b6064359060443590602435906120a5565b604080519384526020840192909252908201529081906060820190565b346102e7575f3660031901126102e757602061ffff60655460a01c16604051908152f35b346102e7576003196040368201126102e75760049081356001600160401b038082116102e75760a08285019383360301126102e7576024359081116102e75761155a9036908501610bc6565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102e75760405163837d444160e01b8152905f9082908183816115ad8c828f01612187565b03925af18015610543576116cb575b506115c5613729565b6115cd612488565b908116331415918261169c575b5050905061168b576044019160b06115f28484612205565b90500480158015611673575b6116635761161361160d611e9f565b9161225a565b11611654575060b06116258383612205565b9050145f14611641576100209161163b91612205565b90613b47565b6100209161164e91612205565b90613a1f565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b5061167e8484612205565b905060b0820214156115fe565b604051634ca8886760e01b81528390fd5b6116bf92506116b96116c3946116b1886137b4565b923691610f4b565b9161388e565b1590565b805f806115da565b80610ae16116d892610ec6565b5f6115bc565b346102e75760603660031901126102e7576004356024356117036044358284336120a5565b919261172f7f000000000000000000000000000000000000000000000000000000000000000082612290565b4210801561187c575b8015611874575b611862577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb569361179a61177f61177486613c5a565b60995460801c611e0a565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916117de91906117cd608082610f0f565b5190205f52609b60205260405f2090565b555f9360018311611817575b505050506117f88233613c8d565b604080519485526020850191909152830152339180606081015b0390a2005b611858929394506118289088612290565b60408051336020820190815291810193909352606083018290526080958601835290949091906117cd9082610f0f565b555f8080806117ea565b604051630e3d8e8d60e11b8152600490fd5b50821561173f565b508115611738565b346102e75760403660031901126102e75760206118af6024356118a6816102d6565b600435336146b6565b61036133614636565b346102e75760203660031901126102e7576004356118d4613729565b335f908152610137602052604090206118ec90611db9565b6001600160801b038061190683516001600160801b031690565b1615610502578290611917836124c8565b82516001600160801b03161610611a9a57335f908152609c60205260409020548261195861194c84516001600160801b031690565b6001600160801b031690565b14611a845761197c908361197661194c85516001600160801b031690565b9161266b565b916119a961199c61198c83613c5a565b84516001600160801b0316610977565b6001600160801b03168352565b335f908152610137602052604090206119c3908390611e23565b611a0b60206119fc60018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336146b6565b9301516001600160801b031690565b833b156102e75760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af1918215610543576104fe92611a71575b506040519081529081906020820190565b80610ae1611a7e92610ec6565b5f611a60565b335f9081526101376020526040812055916119c3565b604051636edcc52360e01b8152600490fd5b346102e7576118127f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611ade36610bf3565b9290611ae8613556565b6040519182916020835233956020840191612167565b5f5b838110611b0f5750505f910152565b8181015183820152602001611b00565b90602091611b3881518092818552858086019101611afe565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611b795750505050505090565b9091929394958480611b97600193603f198682030187528a51611b1f565b9801930193019194939290611b69565b346102e75760203660031901126102e7576001600160401b036004358181116102e757366023820112156102e75780600401359182116102e7573660248360051b830101116102e7576104fe916024611c0092016123db565b60405191829182611b44565b906020610616928181520190611b1f565b346102e7575f3660031901126102e7576104fe604051611c3c81610ea6565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611b1f565b346102e7575f3660031901126102e7576020610b33612488565b346102e75760203660031901126102e7576020610361600435613d27565b346102e7575f3660031901126102e75760206001600160801b0360995416604051908152f35b346102e75760203660031901126102e757610020600435611ce0816102d6565b611ce8613556565b613db6565b346102e7575f3660031901126102e75760206001600160801b03609e5416604051908152f35b346102e75760203660031901126102e757600435611d30816102d6565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102e7575f3660031901126102e7575f546040516001600160a01b039091168152602090f35b60403660031901126102e7576020610361600435611d92816102d6565b602435906105b3826102d6565b908160209103126102e7575190565b6040513d5f823e3d90fd5b90604051611dc681610ea6565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f19019190821161139c57565b6001600160801b03918216908216039190821161139c57565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b0381169081611e6d57505090565b916106169260801c9061266b565b611e87611e8e916127d1565b9190612967565b611e9457565b611e9c612b1d565b50565b476099546001600160801b03611eb6818316611e55565b90609e5416019060801c01908181115f14611ecf570390565b50505f90565b61016a546001600160a01b03168015611eeb5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102e75751610616816102d6565b906020828203126102e75781356001600160401b03928382116102e75701916060838303126102e75760405192611f5b84610ed9565b80358452602081013561ffff811681036102e757602085015260408101359182116102e757019080601f830112156102e757816020611f9c93359101610f4b565b604082015290565b5f549091906001600160a01b031661205f576040519063e7f6f22560e01b82526020928383600481335afa928315610543575f93612040575b50604051636f4fa30f60e01b8152908482600481335afa9182156105435761201b955f9361201d575b50506120159192810190611f25565b91613415565b565b6120159350908161203992903d10610ded57610ddf8183610f0f565b915f612006565b612058919350843d8611610ded57610ddf8183610f0f565b915f611fdd565b505061201b613309565b609d548061061657505f1990565b519081151582036102e757565b908160209103126102e75761061690612077565b9190820391821161139c57565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906120e381608081015b03601f198101835282610f0f565b5190205f52609b60205260405f20549182156121135761210491839161358e565b909182810390811161139c5792565b5050505f905f905f90565b9035601e19823603018112156102e75701602081359101916001600160401b0382116102e75781360383136102e757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610616926020815282356020820152602083013560408201526121c36121b3604085018561211e565b84606085015260c0840191612167565b906121f66121eb6121d7606087018761211e565b601f19858703810160808701529591612167565b94608081019061211e565b93909282860301910152612167565b903590601e19813603018212156102e757018035906001600160401b0382116102e7576020019181360383136102e757565b634e487b7160e01b5f52601260045260245ffd5b8115612255570490565b612237565b906801bc16d674ec800000918083029283040361139c57565b90670de0b6b3a76400009182810292818404149015171561139c57565b9190820180921161139c57565b6001600160401b038111610ec15760051b60200190565b906122be8261229d565b6122cb6040519182610f0f565b82815280926122dc601f199161229d565b01905f5b8281106122ec57505050565b8060606020809385010152016122e0565b634e487b7160e01b5f52603260045260245ffd5b9082101561232857610c1d9160051b810190612205565b6122fd565b908092918237015f815290565b3d15612364573d9061234b82610f30565b916123596040519384610f0f565b82523d5f602084013e565b606090565b6020818303126102e7578051906001600160401b0382116102e7570181601f820112156102e757805161239b81610f30565b926123a96040519485610f0f565b818452602082840101116102e7576106169160208085019101611afe565b80518210156123285760209160051b010190565b9190916123e7836122b4565b925f5b8181106123f657505050565b5f80612403838587612311565b6040939161241585518093819361232d565b0390305af49061242361233a565b911561244a57509060019161243882886123c7565b5261244381876123c7565b50016123ea565b9060448151106102e75761248461246f60049283810151602480918301019101612369565b925162461bcd60e51b81529283928301611c0c565b0390fd5b60d2546001600160a01b03168061061657507f000000000000000000000000000000000000000000000000000000000000000090565b611e9c3433613e18565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610543575f9161255e575b5060208201916001600160801b03918284511691828214612557578361254a61254561255295858486511661266b565b613c5a565b169052613c5a565b169052565b5050505050565b612577915060203d60201161053c5761052e8183610f0f565b5f612515565b90808202905f19818409908280831092039180830392146125ec5761271090828211156125da577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461265a57670de0b6b3a764000090828211156125da577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146126de57848311156125da57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090610616925061224b565b908160609103126102e757805191610616604060208401519301612077565b81835290916001600160fb1b0383116102e75760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102e7576040830152604081013561275d816102d6565b6001600160a01b031660608381019190915281013536829003601e19018112156102e75701602081359101906001600160401b0381116102e7578060051b360382136102e75760a083608080610616960152019161270a565b9190915f838201938412911290801582169115161761139c57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906127fc906004830161272e565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610543575f915f905f95612922575b5084156128cf5781612846611ed5565b16917f00000000000000000000000000000000000000000000000000000000000000001682146128c857509060205f92600460405180958193634641257d60e01b83525af1908115610543576128a3925f926128a7575b506127b6565b9190565b6128c191925060203d60201161053c5761052e8183610f0f565b905f61289d565b90816128d5575b50509190565b803b156102e757604051636ee3193160e11b815260048101929092525f908290602490829084905af180156105435761290f575b806128cf565b80610ae161291c92610ec6565b5f612909565b91945050612948915060603d606011612950575b6129408183610f0f565b8101906126eb565b93905f612836565b503d612936565b600160ff1b811461139c575f0390565b8015611e9c5761297c61194c60985460801c90565b5f8212612a53578161298d91612290565b9061299a61098483613c5a565b6129af6065549161ffff8360a01c169061257d565b8015612a4e57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936129ed61194c6098546001600160801b031690565b80612a38575050612a3390925b6001600160a01b031691612a0e8484613f8c565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b612a3392612a489203908461266b565b926129fa565b505050565b90612a5d90612957565b612a7261194c609e546001600160801b031690565b80612a92575b5080612a82575050565b6125456109849161201b93612098565b90612af97f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161132f612add612ad2612acb8888612290565b878561266b565b808094039603613c5a565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f612a78565b9190916001600160801b038080941691160191821161139c57565b612b3647612b3061194c60995460801c90565b90612098565b908115612cec57609e546001600160801b0381169081612c74575b5050612b6861194c6099546001600160801b031690565b9182158015612c6c575b612c6657612b8990612b8384611e55565b9061416d565b8015612c6657612b9881613d27565b928315612c5f57612c5461201b92612bd5612bb96125458861098496612098565b6001600160801b03166001600160801b03196099541617609955565b612bef61177f612be483613c5a565b60995460801c612b02565b612bf98187614036565b60408051878152602081018390525f80516020614aa18339815191529190a1612545612c38612c2788613c5a565b6098546001600160801b0316611e0a565b6001600160801b03166001600160801b03196098541617609855565b60985460801c611e0a565b505f925050565b505f9150565b508015612b72565b8184929410612c5f57612be484612cbc935f80516020614aa18339815191528261177f9560801c612ca58282614036565b604080519182526020820192909252a10394613c5a565b612cd06001600160801b03609e5416609e55565b612ce56001600160801b0319609e5416609e55565b5f80612b51565b5f9150565b9392919091612cfe61417f565b612d06613729565b6001600160a01b0385165f90815261013760205260409020612d2790611db9565b946001600160801b03612d4187516001600160801b031690565b1615612f0d57612d50866124c8565b6001600160a01b0381165f908152609c60205260409020612d7990612d749061080f565b6141a0565b955f198414612edd575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610543575f96612ebc575b508598612e15612e08612df884613c5a565b86516001600160801b0316612b02565b6001600160801b03168552565b612e2961194c85516001600160801b031690565b11612eaa577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5895612e72612ea5946104ab8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b612ed691965060203d60201161053c5761052e8183610f0f565b945f612de6565b9250612ef361194c84516001600160801b031690565b80871115612f0357860392612d83565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561054357612f7891612f68915f91612f7d575b50613c5a565b6001600160801b03166020880152565b612d50565b612f96915060203d60201161053c5761052e8183610f0f565b5f612f62565b51906001600160401b03821682036102e757565b908160609103126102e757611f9c6040805192612fcc84610ed9565b8051612fd781610393565b8452612fe560208201612f9c565b602085015201612f9c565b92906001600160a01b039081811615610aed5761300b613729565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102e757604094855193631d8557d760e01b85526004945f81878183895af18015610543576132f6575b506001600160a01b0388165f9081526101376020526040902061307e90611db9565b906001600160801b0361309883516001600160801b031690565b16156132e6576130a7826124c8565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa8015610543576132c7575b508651936303d1689d60e11b97888652602091828780613121888c83019190602083019252565b0381845afa968715610543575f976132a8575b50869961315461080f8d60018060a01b03165f52609c60205260405f2090565b88118015613298575b61328857908361319a9261317887516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610543575f859488946131df9c61326b575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156105435761092a613226946132099361048a9361201b9a61324d575b5050613c5a565b6001600160a01b0388165f90815261013760205260409020611e23565b61324861323283613d27565b809761324361098461097087613c5a565b6142aa565b613c8d565b8161326392903d1061053c5761052e8183610f0f565b505f80613202565b61328190873d891161053c5761052e8183610f0f565b505f6131b4565b825163efda1a2760e01b81528990fd5b506132a1611e9f565b881161315d565b6132c0919750833d851161053c5761052e8183610f0f565b955f613134565b6132df9060603d606011610abd57610aae8183610f0f565b505f6130fa565b875163673f032f60e11b81528690fd5b80610ae161330392610ec6565b5f61305c565b613311614318565b61332661194c6099546001600160801b031690565b600181116134035760011461339a575b609f54613341614842565b9080821061335d575b50506133555f609f55565b61201b6142f7565b5f80516020614aa183398151915291613390910361337a81614134565b604080519182525f602083015290918291820190565b0390a15f8061334a565b6133b7612c386133b26098546001600160801b031690565b611df2565b6133cc6001600160801b031960995416609955565b6133d46140f2565b5f80516020614aa1833981519152604051806133fb81905f60206040840193600181520152565b0390a1613336565b604051630299325160e41b8152600490fd5b61341d614318565b604083015161342a614318565b6001600160a01b0382168015610aed576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061348333946020830190611b1f565b0390a2602083015192613494614318565b61271061ffff8516116134eb576134e3936134b16134d693613db6565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614359565b6134de614389565b6143b0565b61201b6143df565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821561353b575b505061125d57565b5f80516020614ac18339815191525416141590505f80613533565b5f546001600160a01b03163303610db357565b9060405161357681610ea6565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613721575b61371457836136de575f5b609a5f526001600160a01b03166135d35f80516020614a818339815191528601613569565b80519097906135ea906001600160a01b03166111f3565b9861360f6136036020809b01516001600160601b031690565b6001600160601b031690565b9483811080156136d4575b6136c25791600193979a95613639613645939488035b838c039061416d565b8092019887039161266b565b019701938086118015906136b8575b6136ad57609a5f5282906136765f80516020614a818339815191528701613569565b805190890151969992966001600160a01b0390911694600193926136459290916001600160601b0390911690613639908803613630565b945050509250509190565b5081851015613654565b60405163e8722f8f60e01b8152600490fd5b50808b111561361a565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b03166135ae565b505093505050505f905f90565b5084156135a3565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610543575f91613795575b5061378357565b60405163e775715160e01b8152600490fd5b6137ae915060203d6020116110f9576110ea8183610f0f565b5f61377c565b604290467f0000000000000000000000000000000000000000000000000000000000000000036138625760d354905b6137fa6137f36040830183612205565b3691610f4b565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815261384581610ef4565b5190206040519161190160f01b8352600283015260228201522090565b61386a614506565b906137e3565b6004111561387a57565b634e487b7160e01b5f52602160045260245ffd5b61389883836145d3565b506138a581959295613870565b159384613941575b5083156138bb575b50505090565b5f9293509082916040516138f3816120d56020820194630b135d3f60e11b998a87526024840152604060448401526064830190611b1f565b51915afa9061390061233a565b82613933575b82613916575b50505f80806138b5565b61392b91925060208082518301019101611d9f565b145f8061390c565b915060208251101591613906565b6001600160a01b0383811691161493505f6138ad565b906030116102e75790603090565b906090116102e75760300190606090565b9060b0116102e75760900190602090565b909392938483116102e75784116102e7578101920390565b3590602081106139ad575090565b5f199060200360031b1b1690565b969594906139f8936139dc6139ea926060979560808c5260808c0191612167565b9089820360208b0152611b1f565b918783036040890152612167565b930152565b90602061061692818152019061214f565b916020610616938181520191612167565b60b091828104915f9081613a3161460d565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b878410613a7357505050505050505050565b82613a82910180928887613987565b90613a8d8282613957565b91613aac613aa6613a9e8684613965565b969093613976565b9061399f565b90893b156102e7575f908d613ad9604094855198899485946304512a2360e31b86528a8a600488016139bb565b03816801bc16d674ec8000008d5af1908115610543577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194613b2592613b34575b505192839283613a0e565b0390a160018193019290613a61565b80610ae1613b4192610ec6565b5f613b1a565b816030116102e757613aa6917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613b8561460d565b90613b9c613b938486613965565b96909486613976565b94813b156102e7576801bc16d674ec8000005f94613c0297604051988996879586946304512a2360e31b865260806004870152613bf3613be08d608489019061214f565b60031994858983030160248a0152611b1f565b92868403016044870152612167565b90606483015203925af1908115610543577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192612a3392613c4b575b50604051918291826139fd565b613c5490610ec6565b5f613c3e565b6001600160801b0390818111613c6e571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613d155760028355814710613cfd575f918291829182916001600160a01b03165af1613cdf61233a565b5015613ceb5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b03821681158015613d56575b15613d495750905090565b6106169260801c9161266b565b508015613d3e565b6098546001600160801b0381169082158015613dae575b15613d7f57505090565b60801c90613d8e82828561266b565b9282156122555709613d9d5790565b600181018091111561061657611dde565b508115613d75565b613dbe613729565b6001600160a01b03168015613e0657606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190613e22613729565b6001600160a01b038316908115610aed578015613ece5780613e4961194c60985460801c90565b0193613e53612069565b8511613ebc5761098494613e7a91613e75613e6d85613d5e565b978893613c5a565b613f8c565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613eec613729565b6001600160a01b038216918215610aed578115613ece5781613f1361194c60985460801c90565b01613f1c612069565b8111613ebc5761098495613f63613eb7927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613e75613f5b88613d5e565b9a8b93613c5a565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613f9582613c5a565b60985490613fad6001600160801b0391828416612b02565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609a549068010000000000000000821015610ec1576001820180609a5582101561232857609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614a8183398151915290910155565b91909180156140e057614047614842565b90810180911161139c576001600160a01b038082116140c0576001600160601b03908185116140a0579061201b939461409b926040519461408786610ea6565b168452166001600160601b03166020830152565b613fd8565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b6140fa614842565b6001810180911161139c576001600160a01b038082116140c0579061201b916040519161412683610ea6565b1681525f6020820152613fd8565b80156140e057614142614842565b90810180911161139c576001600160a01b038082116140c0579061201b916040519161412683610ea6565b908082101561417a575090565b905090565b614187614884565b1561418e57565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156105435761423b936001600160401b036107ea604061421a946020975f9161428b575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610543575f91614272575090565b610616915060203d60201161053c5761052e8183610f0f565b6142a4915060603d606011610abd57610aae8183610f0f565b5f61420b565b60018060a01b03165f52609c60205260405f2090815481810390811161139c576142d49255613c5a565b609854906001600160801b03908183160316906001600160801b03191617609855565b6142ff614318565b614307614506565b60d35481036143135750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561434757565b604051631afcd79f60e31b8152600490fd5b614361614318565b801561437757600181016143725750565b609d55565b6040516331278a8760e01b8152600490fd5b614391614318565b6801bc16d674ec8000006143a3612069565b1061437757614313614506565b6143b8614318565b6001600160a01b0316806143c95750565b61016a80546001600160a01b0319169091179055565b6143e7614318565b6143ef614318565b6143f7614318565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341061443057611e9c3430613e18565b60405163ea2559bb60e01b8152600490fd5b908160209103126102e7575160ff811681036102e75790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816144e5575b506144ab57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614ac183398151915284036144cc5761201b9293506148f3565b604051632a87526960e21b815260048101859052602490fd5b6144ff91955060203d60201161053c5761052e8183610f0f565b935f614485565b6e5661756c7456616c696461746f727360881b602060405161452781610ea6565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610ec15760405251902090565b8151919060418303614603576145fc9250602082015190606060408401519301515f1a90614995565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261061681610ea6565b60018060a01b0381165f5261013760205260405f20906040519161465983610ea6565b54906001600160801b03918281169081855260801c602085015215612a4e57612d7461080f6146ac9261468a613729565b614693866124c8565b6001600160a01b03165f908152609c6020526040902090565b91511611612eaa57565b9291908015611a9a576001600160a01b03828116928315610aed576146dc6116bf614884565b6147c957906117cd956147ad612bb9857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161478261472761194c6099546001600160801b031690565b926120d56147548561474f61473a614842565b61474961194c609e5460801c90565b90612290565b612290565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c602052604090206147a5838254612098565b905501613c5a565b6040805188815260208101959095529116929081908101613eb7565b9293946147d583611e55565b938415613ece577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361481f8661483a93614815610984612c5484613c5a565b61324884876142aa565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b609a548061484f57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166111f3565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610543575f916148da575090565b610616915060203d6020116110f9576110ea8183610f0f565b90813b15614974575f80516020614ac183398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561495957611e9c91614a17565b50503461496257565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614a0c579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610543575f516001600160a01b03811615614a0257905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061061693602081519101845af4614a2e61233a565b9190614a445750805115613ceb57805190602001fd5b81511580614a77575b614a55575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614a4d56fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220bfc252ddce624b4e17b899c19f83b533ae868abc55e8580e4dbd0b889736bc9064736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b6100206124be565b005b5f3560e01c806301d523b6146102d157806301e1d114146102cc578063066055e0146102c757806307a2d13a146102c257806318f72950146102bd5780631a7ff553146102b8578063201b9eb5146102b35780632999ad3f146102ae5780632cdf7401146102a95780633229fa95146102a457806333194c0a1461029f57806336fe59d21461029a5780633a98ef3914610295578063439fab911461029057806343e82a791461028b57806346904840146102865780634ec96b22146102815780634f1ef2861461027c57806352d1902d1461027757806353156f281461027257806354fd4d501461026d5780635c60da1b146102685780635cfc1a511461026357806360d60e6e1461025e57806372b410a814610259578063754c38881461025457806376b58b901461024f5780637fd6f15c1461024a57806383d430d5146102455780638697d2c2146102405780638ceab9aa1461023b5780639267842a14610236578063a49a1e7d14610231578063ac9650d81461022c578063ad3cb1cc14610227578063b1f0e7c714610222578063c6e6f5921461021d578063d83ad00c14610218578063e74b981b14610213578063ee3bd5df1461020e578063f04da65b14610209578063f851a440146102045763f9609f080361000e57611d75565b611d4e565b611d13565b611ced565b611cc0565b611c9a565b611c7c565b611c62565b611c1d565b611ba7565b611aac565b6118b8565b611884565b6116de565b61150e565b6114ea565b611499565b61142e565b6113a1565b6112fc565b6112e2565b6112ae565b611293565b61126f565b611206565b610f81565b610e1c565b610df4565b610ce7565b610c21565b610ba0565b610b7f565b610b45565b610b19565b610aff565b61065c565b610619565b6105ba565b610566565b610548565b6103a4565b610373565b6102f9565b6001600160a01b038116036102e757565b5f80fd5b908160809103126102e75790565b60803660031901126102e757600435610311816102d6565b60443561031d816102d6565b606435906001600160401b0382116102e75760209261034b6103466103619436906004016102eb565b611e7b565b610356823433613ee0565b506024359033612cf1565b604051908152f35b5f9103126102e757565b346102e7575f3660031901126102e757602060985460801c604051908152f35b6001600160801b038116036102e757565b346102e75760203660031901126102e7576004356103c181610393565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610543575f91610514575b50335f9081526101376020526040902061043d90611db9565b916001600160801b0361045784516001600160801b031690565b1615610502576104b08361046d6104fe956124c8565b61049761048a8461048584516001600160801b031690565b611e0a565b6001600160801b03168252565b335f90815261013760205260409020611e23565b611e23565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610536915060203d60201161053c575b61052e8183610f0f565b810190611d9f565b5f610424565b503d610524565b611dae565b346102e75760203660031901126102e7576020610361600435611e55565b60603660031901126102e75760043561057e816102d6565b60243561058a816102d6565b604435906001600160401b0382116102e7576020926105b36103466103619436906004016102eb565b3490613ee0565b346102e75760203660031901126102e7576004356001600160401b0381116102e7576103466100209136906004016102eb565b60609060031901126102e757600435610605816102d6565b9060243590604435610616816102d6565b90565b346102e757602061036161062c366105ed565b9133612cf1565b60609060031901126102e7576004359060243561064f816102d6565b90604435610616816102d6565b346102e75761066a36610633565b906001600160a01b0380831615610aed57610683613729565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102e75760408051631d8557d760e01b815260049491905f81878183875af1801561054357610ad4575b506001600160a01b0383165f908152610137602052604090206106f690611db9565b6001600160801b03928361071183516001600160801b031690565b1615610ac457610720826124c8565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610543575f98610a93575b50602097888101956001600160401b039182806107998a516001600160401b031690565b1614610a8357908c92918751918c83806107c56303d1689d60e11b988983528a83019190602083019252565b03818a5afa918215610543576107f1938e5f94610a5e575b5050516001600160801b03165b16906125f7565b9661081561080f8a60018060a01b03165f52609c60205260405f2090565b54611e55565b928389118015610a4e575b610a3e57908b61085e939261083c89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561054357670de0b6b3a7640000946108ad948e5f95610a11575b505061089f6108916108a592612273565b93516001600160401b031690565b93612273565b92169061266b565b1015610a03578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610543577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c5350976109e095610957936109e5575b505061093a61048a61092a8c613c5a565b83516001600160801b0316611e0a565b6001600160a01b0386165f90815261013760205260409020611e23565b61096082613d27565b9061099f61098461097085613c5a565b60985460801c5b036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b6109a982866142aa565b6109b38389613c8d565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b816109fb92903d1061053c5761052e8183610f0f565b505f80610919565b835163185cfc6d60e11b8152fd5b6108a5929550610a3461089f928261089193903d1061053c5761052e8183610f0f565b959250508e610880565b875163efda1a2760e01b81528590fd5b50610a57611e9f565b8911610820565b6107ea9294509081610a7b92903d1061053c5761052e8183610f0f565b92908e6107dd565b8651630709133160e01b81528490fd5b610ab691985060603d606011610abd575b610aae8183610f0f565b810190612fb0565b965f610775565b503d610aa4565b825163673f032f60e11b81528790fd5b80610ae1610ae792610ec6565b80610369565b5f6106d4565b60405163d92e233d60e01b8152600490fd5b346102e7575f3660031901126102e7576020610361611e9f565b346102e7575f3660031901126102e7576020610b33611ed5565b6040516001600160a01b039091168152f35b346102e7575f3660031901126102e75760206040517fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b8152f35b6020610361610b8d366105ed565b91610b99833433613ee0565b5033612cf1565b346102e7575f3660031901126102e75760206001600160801b0360985416604051908152f35b9181601f840112156102e7578235916001600160401b0383116102e757602083818601950101116102e757565b60206003198201126102e757600435906001600160401b0382116102e757610c1d91600401610bc6565b9091565b610c2a36610bf3565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c168015610cd3575b610cc15768010000000000000003610c849368ffffffffffffffffff1916178455611fa4565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015610c5e565b346102e757610cf536610633565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105435782915f91610dc5575b50163303610db357816109e0610d8086867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396612ff0565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b610de7915060203d602011610ded575b610ddf8183610f0f565b810190611f10565b5f610d48565b503d610dd5565b346102e7575f3660031901126102e7576065546040516001600160a01b039091168152602090f35b346102e75760203660031901126102e757600435610e39816102d6565b60018060a01b03165f52610137602052602060405f2060405190610e5c82610ea6565b54906001600160801b03918281169081835260801c84830152610e84575b5116604051908152f35b610e8d816124c8565b610e7a565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b03821117610ec157604052565b610e92565b6001600160401b038111610ec157604052565b606081019081106001600160401b03821117610ec157604052565b608081019081106001600160401b03821117610ec157604052565b90601f801991011681019081106001600160401b03821117610ec157604052565b6001600160401b038111610ec157601f01601f191660200190565b929192610f5782610f30565b91610f656040519384610f0f565b8294818452818301116102e7578281602093845f960137010152565b6040806003193601126102e7576004908135610f9c816102d6565b6024356001600160401b0381116102e757366023820112156102e757610fcb9036906024818701359101610f4b565b91610fd46134fd565b80519261100b84610ffd60209363439fab9160e01b858401528460248401526044830190611b1f565b03601f198101865285610f0f565b6110136134fd565b61101b613556565b6001600160a01b038381168015929190879084156111d1575b8415611163575b8415611100575b5050821561106a575b505061105b57610020838361445b565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610543575f926110d3575b5050155f8061104b565b6110f29250803d106110f9575b6110ea8183610f0f565b810190612084565b5f806110c9565b503d6110e0565b855163054fd4d560e41b81529294508391839182905afa90811561054357879160ff915f91611136575b5016141591865f611042565b6111569150843d861161115c575b61114e8183610f0f565b810190614442565b5f61112a565b503d611144565b935050835163198ca60560e11b815282818981875afa9081156105435788917fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b915f916111b4575b5014159361103b565b6111cb9150853d871161053c5761052e8183610f0f565b5f6111ab565b5f80516020614ac18339815191525490945084906111ff906001600160a01b03165b6001600160a01b031690565b1493611034565b346102e7575f3660031901126102e7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361125d5760206040515f80516020614ac18339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126102e7576001600160a01b0361128a611ed5565b163303610db357005b346102e7575f3660031901126102e757602060405160038152f35b346102e7575f3660031901126102e7575f80516020614ac1833981519152546040516001600160a01b039091168152602090f35b346102e7575f3660031901126102e7576020610361612069565b346102e75760203660031901126102e757609a80549081905f6004355b84821061134a5750505081101561133f576104fe905b6040519081529081906020820190565b506104fe5f1961132f565b909193808316906001818518811c830180931161139c575f8790525f80516020614a818339815191528301546001600160a01b0316841015611391575050935b9190611319565b90959101925061138a565b611dde565b346102e7575f3660031901126102e757604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610543576020915f91611411575b506040519015158152f35b6114289150823d84116110f9576110ea8183610f0f565b5f611406565b346102e75760203660031901126102e75760043561144b816102d6565b611453613556565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102e75760803660031901126102e7576104fe6114cd6004356114bc816102d6565b6064359060443590602435906120a5565b604080519384526020840192909252908201529081906060820190565b346102e7575f3660031901126102e757602061ffff60655460a01c16604051908152f35b346102e7576003196040368201126102e75760049081356001600160401b038082116102e75760a08285019383360301126102e7576024359081116102e75761155a9036908501610bc6565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102e75760405163837d444160e01b8152905f9082908183816115ad8c828f01612187565b03925af18015610543576116cb575b506115c5613729565b6115cd612488565b908116331415918261169c575b5050905061168b576044019160b06115f28484612205565b90500480158015611673575b6116635761161361160d611e9f565b9161225a565b11611654575060b06116258383612205565b9050145f14611641576100209161163b91612205565b90613b47565b6100209161164e91612205565b90613a1f565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b5061167e8484612205565b905060b0820214156115fe565b604051634ca8886760e01b81528390fd5b6116bf92506116b96116c3946116b1886137b4565b923691610f4b565b9161388e565b1590565b805f806115da565b80610ae16116d892610ec6565b5f6115bc565b346102e75760603660031901126102e7576004356024356117036044358284336120a5565b919261172f7f000000000000000000000000000000000000000000000000000000000000000082612290565b4210801561187c575b8015611874575b611862577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb569361179a61177f61177486613c5a565b60995460801c611e0a565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f916117de91906117cd608082610f0f565b5190205f52609b60205260405f2090565b555f9360018311611817575b505050506117f88233613c8d565b604080519485526020850191909152830152339180606081015b0390a2005b611858929394506118289088612290565b60408051336020820190815291810193909352606083018290526080958601835290949091906117cd9082610f0f565b555f8080806117ea565b604051630e3d8e8d60e11b8152600490fd5b50821561173f565b508115611738565b346102e75760403660031901126102e75760206118af6024356118a6816102d6565b600435336146b6565b61036133614636565b346102e75760203660031901126102e7576004356118d4613729565b335f908152610137602052604090206118ec90611db9565b6001600160801b038061190683516001600160801b031690565b1615610502578290611917836124c8565b82516001600160801b03161610611a9a57335f908152609c60205260409020548261195861194c84516001600160801b031690565b6001600160801b031690565b14611a845761197c908361197661194c85516001600160801b031690565b9161266b565b916119a961199c61198c83613c5a565b84516001600160801b0316610977565b6001600160801b03168352565b335f908152610137602052604090206119c3908390611e23565b611a0b60206119fc60018060a01b037f0000000000000000000000000000000000000000000000000000000000000000168096336146b6565b9301516001600160801b031690565b833b156102e75760405163074ee96960e31b81523360048201526024810184905260448101929092526001600160801b03166064820152915f908390608490829084905af1918215610543576104fe92611a71575b506040519081529081906020820190565b80610ae1611a7e92610ec6565b5f611a60565b335f9081526101376020526040812055916119c3565b604051636edcc52360e01b8152600490fd5b346102e7576118127f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611ade36610bf3565b9290611ae8613556565b6040519182916020835233956020840191612167565b5f5b838110611b0f5750505f910152565b8181015183820152602001611b00565b90602091611b3881518092818552858086019101611afe565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611b795750505050505090565b9091929394958480611b97600193603f198682030187528a51611b1f565b9801930193019194939290611b69565b346102e75760203660031901126102e7576001600160401b036004358181116102e757366023820112156102e75780600401359182116102e7573660248360051b830101116102e7576104fe916024611c0092016123db565b60405191829182611b44565b906020610616928181520190611b1f565b346102e7575f3660031901126102e7576104fe604051611c3c81610ea6565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611b1f565b346102e7575f3660031901126102e7576020610b33612488565b346102e75760203660031901126102e7576020610361600435613d27565b346102e7575f3660031901126102e75760206001600160801b0360995416604051908152f35b346102e75760203660031901126102e757610020600435611ce0816102d6565b611ce8613556565b613db6565b346102e7575f3660031901126102e75760206001600160801b03609e5416604051908152f35b346102e75760203660031901126102e757600435611d30816102d6565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102e7575f3660031901126102e7575f546040516001600160a01b039091168152602090f35b60403660031901126102e7576020610361600435611d92816102d6565b602435906105b3826102d6565b908160209103126102e7575190565b6040513d5f823e3d90fd5b90604051611dc681610ea6565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039081165f19019190821161139c57565b6001600160801b03918216908216039190821161139c57565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b0381169081611e6d57505090565b916106169260801c9061266b565b611e87611e8e916127d1565b9190612967565b611e9457565b611e9c612b1d565b50565b476099546001600160801b03611eb6818316611e55565b90609e5416019060801c01908181115f14611ecf570390565b50505f90565b61016a546001600160a01b03168015611eeb5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102e75751610616816102d6565b906020828203126102e75781356001600160401b03928382116102e75701916060838303126102e75760405192611f5b84610ed9565b80358452602081013561ffff811681036102e757602085015260408101359182116102e757019080601f830112156102e757816020611f9c93359101610f4b565b604082015290565b5f549091906001600160a01b031661205f576040519063e7f6f22560e01b82526020928383600481335afa928315610543575f93612040575b50604051636f4fa30f60e01b8152908482600481335afa9182156105435761201b955f9361201d575b50506120159192810190611f25565b91613415565b565b6120159350908161203992903d10610ded57610ddf8183610f0f565b915f612006565b612058919350843d8611610ded57610ddf8183610f0f565b915f611fdd565b505061201b613309565b609d548061061657505f1990565b519081151582036102e757565b908160209103126102e75761061690612077565b9190820391821161139c57565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906120e381608081015b03601f198101835282610f0f565b5190205f52609b60205260405f20549182156121135761210491839161358e565b909182810390811161139c5792565b5050505f905f905f90565b9035601e19823603018112156102e75701602081359101916001600160401b0382116102e75781360383136102e757565b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610616926020815282356020820152602083013560408201526121c36121b3604085018561211e565b84606085015260c0840191612167565b906121f66121eb6121d7606087018761211e565b601f19858703810160808701529591612167565b94608081019061211e565b93909282860301910152612167565b903590601e19813603018212156102e757018035906001600160401b0382116102e7576020019181360383136102e757565b634e487b7160e01b5f52601260045260245ffd5b8115612255570490565b612237565b906801bc16d674ec800000918083029283040361139c57565b90670de0b6b3a76400009182810292818404149015171561139c57565b9190820180921161139c57565b6001600160401b038111610ec15760051b60200190565b906122be8261229d565b6122cb6040519182610f0f565b82815280926122dc601f199161229d565b01905f5b8281106122ec57505050565b8060606020809385010152016122e0565b634e487b7160e01b5f52603260045260245ffd5b9082101561232857610c1d9160051b810190612205565b6122fd565b908092918237015f815290565b3d15612364573d9061234b82610f30565b916123596040519384610f0f565b82523d5f602084013e565b606090565b6020818303126102e7578051906001600160401b0382116102e7570181601f820112156102e757805161239b81610f30565b926123a96040519485610f0f565b818452602082840101116102e7576106169160208085019101611afe565b80518210156123285760209160051b010190565b9190916123e7836122b4565b925f5b8181106123f657505050565b5f80612403838587612311565b6040939161241585518093819361232d565b0390305af49061242361233a565b911561244a57509060019161243882886123c7565b5261244381876123c7565b50016123ea565b9060448151106102e75761248461246f60049283810151602480918301019101612369565b925162461bcd60e51b81529283928301611c0c565b0390fd5b60d2546001600160a01b03168061061657507f000000000000000000000000000000000000000000000000000000000000000090565b611e9c3433613e18565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610543575f9161255e575b5060208201916001600160801b03918284511691828214612557578361254a61254561255295858486511661266b565b613c5a565b169052613c5a565b169052565b5050505050565b612577915060203d60201161053c5761052e8183610f0f565b5f612515565b90808202905f19818409908280831092039180830392146125ec5761271090828211156125da577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461265a57670de0b6b3a764000090828211156125da577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b9091828202915f19848209938380861095039480860395146126de57848311156125da57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b505090610616925061224b565b908160609103126102e757805191610616604060208401519301612077565b81835290916001600160fb1b0383116102e75760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102e7576040830152604081013561275d816102d6565b6001600160a01b031660608381019190915281013536829003601e19018112156102e75701602081359101906001600160401b0381116102e7578060051b360382136102e75760a083608080610616960152019161270a565b9190915f838201938412911290801582169115161761139c57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906127fc906004830161272e565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610543575f915f905f95612922575b5084156128cf5781612846611ed5565b16917f00000000000000000000000000000000000000000000000000000000000000001682146128c857509060205f92600460405180958193634641257d60e01b83525af1908115610543576128a3925f926128a7575b506127b6565b9190565b6128c191925060203d60201161053c5761052e8183610f0f565b905f61289d565b90816128d5575b50509190565b803b156102e757604051636ee3193160e11b815260048101929092525f908290602490829084905af180156105435761290f575b806128cf565b80610ae161291c92610ec6565b5f612909565b91945050612948915060603d606011612950575b6129408183610f0f565b8101906126eb565b93905f612836565b503d612936565b600160ff1b811461139c575f0390565b8015611e9c5761297c61194c60985460801c90565b5f8212612a53578161298d91612290565b9061299a61098483613c5a565b6129af6065549161ffff8360a01c169061257d565b8015612a4e57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936129ed61194c6098546001600160801b031690565b80612a38575050612a3390925b6001600160a01b031691612a0e8484613f8c565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b612a3392612a489203908461266b565b926129fa565b505050565b90612a5d90612957565b612a7261194c609e546001600160801b031690565b80612a92575b5080612a82575050565b6125456109849161201b93612098565b90612af97f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161132f612add612ad2612acb8888612290565b878561266b565b808094039603613c5a565b6001600160801b03166001600160801b0319609e541617609e55565b0390a15f612a78565b9190916001600160801b038080941691160191821161139c57565b612b3647612b3061194c60995460801c90565b90612098565b908115612cec57609e546001600160801b0381169081612c74575b5050612b6861194c6099546001600160801b031690565b9182158015612c6c575b612c6657612b8990612b8384611e55565b9061416d565b8015612c6657612b9881613d27565b928315612c5f57612c5461201b92612bd5612bb96125458861098496612098565b6001600160801b03166001600160801b03196099541617609955565b612bef61177f612be483613c5a565b60995460801c612b02565b612bf98187614036565b60408051878152602081018390525f80516020614aa18339815191529190a1612545612c38612c2788613c5a565b6098546001600160801b0316611e0a565b6001600160801b03166001600160801b03196098541617609855565b60985460801c611e0a565b505f925050565b505f9150565b508015612b72565b8184929410612c5f57612be484612cbc935f80516020614aa18339815191528261177f9560801c612ca58282614036565b604080519182526020820192909252a10394613c5a565b612cd06001600160801b03609e5416609e55565b612ce56001600160801b0319609e5416609e55565b5f80612b51565b5f9150565b9392919091612cfe61417f565b612d06613729565b6001600160a01b0385165f90815261013760205260409020612d2790611db9565b946001600160801b03612d4187516001600160801b031690565b1615612f0d57612d50866124c8565b6001600160a01b0381165f908152609c60205260409020612d7990612d749061080f565b6141a0565b955f198414612edd575b6040516329460cc560e11b81526001600160a01b0386811660048301526024820186905290949093906020866044815f7f00000000000000000000000000000000000000000000000000000000000000008a165af1958615610543575f96612ebc575b508598612e15612e08612df884613c5a565b86516001600160801b0316612b02565b6001600160801b03168552565b612e2961194c85516001600160801b031690565b11612eaa577fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5895612e72612ea5946104ab8760018060a01b03165f5261013760205260405f2090565b604080516001600160a01b03998a1681526020810192909252810191909152951660608601529116929081906080820190565b0390a2565b604051633684c65960e01b8152600490fd5b612ed691965060203d60201161053c5761052e8183610f0f565b945f612de6565b9250612ef361194c84516001600160801b031690565b80871115612f0357860392612d83565b505f955050505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561054357612f7891612f68915f91612f7d575b50613c5a565b6001600160801b03166020880152565b612d50565b612f96915060203d60201161053c5761052e8183610f0f565b5f612f62565b51906001600160401b03821682036102e757565b908160609103126102e757611f9c6040805192612fcc84610ed9565b8051612fd781610393565b8452612fe560208201612f9c565b602085015201612f9c565b92906001600160a01b039081811615610aed5761300b613729565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102e757604094855193631d8557d760e01b85526004945f81878183895af18015610543576132f6575b506001600160a01b0388165f9081526101376020526040902061307e90611db9565b906001600160801b0361309883516001600160801b031690565b16156132e6576130a7826124c8565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa8015610543576132c7575b508651936303d1689d60e11b97888652602091828780613121888c83019190602083019252565b0381845afa968715610543575f976132a8575b50869961315461080f8d60018060a01b03165f52609c60205260405f2090565b88118015613298575b61328857908361319a9261317887516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610543575f859488946131df9c61326b575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156105435761092a613226946132099361048a9361201b9a61324d575b5050613c5a565b6001600160a01b0388165f90815261013760205260409020611e23565b61324861323283613d27565b809761324361098461097087613c5a565b6142aa565b613c8d565b8161326392903d1061053c5761052e8183610f0f565b505f80613202565b61328190873d891161053c5761052e8183610f0f565b505f6131b4565b825163efda1a2760e01b81528990fd5b506132a1611e9f565b881161315d565b6132c0919750833d851161053c5761052e8183610f0f565b955f613134565b6132df9060603d606011610abd57610aae8183610f0f565b505f6130fa565b875163673f032f60e11b81528690fd5b80610ae161330392610ec6565b5f61305c565b613311614318565b61332661194c6099546001600160801b031690565b600181116134035760011461339a575b609f54613341614842565b9080821061335d575b50506133555f609f55565b61201b6142f7565b5f80516020614aa183398151915291613390910361337a81614134565b604080519182525f602083015290918291820190565b0390a15f8061334a565b6133b7612c386133b26098546001600160801b031690565b611df2565b6133cc6001600160801b031960995416609955565b6133d46140f2565b5f80516020614aa1833981519152604051806133fb81905f60206040840193600181520152565b0390a1613336565b604051630299325160e41b8152600490fd5b61341d614318565b604083015161342a614318565b6001600160a01b0382168015610aed576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061348333946020830190611b1f565b0390a2602083015192613494614318565b61271061ffff8516116134eb576134e3936134b16134d693613db6565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614359565b6134de614389565b6143b0565b61201b6143df565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811630811491821561353b575b505061125d57565b5f80516020614ac18339815191525416141590505f80613533565b5f546001600160a01b03163303610db357565b9060405161357681610ea6565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613721575b61371457836136de575f5b609a5f526001600160a01b03166135d35f80516020614a818339815191528601613569565b80519097906135ea906001600160a01b03166111f3565b9861360f6136036020809b01516001600160601b031690565b6001600160601b031690565b9483811080156136d4575b6136c25791600193979a95613639613645939488035b838c039061416d565b8092019887039161266b565b019701938086118015906136b8575b6136ad57609a5f5282906136765f80516020614a818339815191528701613569565b805190890151969992966001600160a01b0390911694600193926136459290916001600160601b0390911690613639908803613630565b945050509250509190565b5081851015613654565b60405163e8722f8f60e01b8152600490fd5b50808b111561361a565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b03166135ae565b505093505050505f905f90565b5084156135a3565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610543575f91613795575b5061378357565b60405163e775715160e01b8152600490fd5b6137ae915060203d6020116110f9576110ea8183610f0f565b5f61377c565b604290467f0000000000000000000000000000000000000000000000000000000000000000036138625760d354905b6137fa6137f36040830183612205565b3691610f4b565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815261384581610ef4565b5190206040519161190160f01b8352600283015260228201522090565b61386a614506565b906137e3565b6004111561387a57565b634e487b7160e01b5f52602160045260245ffd5b61389883836145d3565b506138a581959295613870565b159384613941575b5083156138bb575b50505090565b5f9293509082916040516138f3816120d56020820194630b135d3f60e11b998a87526024840152604060448401526064830190611b1f565b51915afa9061390061233a565b82613933575b82613916575b50505f80806138b5565b61392b91925060208082518301019101611d9f565b145f8061390c565b915060208251101591613906565b6001600160a01b0383811691161493505f6138ad565b906030116102e75790603090565b906090116102e75760300190606090565b9060b0116102e75760900190602090565b909392938483116102e75784116102e7578101920390565b3590602081106139ad575090565b5f199060200360031b1b1690565b969594906139f8936139dc6139ea926060979560808c5260808c0191612167565b9089820360208b0152611b1f565b918783036040890152612167565b930152565b90602061061692818152019061214f565b916020610616938181520191612167565b60b091828104915f9081613a3161460d565b957f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316935f92905b878410613a7357505050505050505050565b82613a82910180928887613987565b90613a8d8282613957565b91613aac613aa6613a9e8684613965565b969093613976565b9061399f565b90893b156102e7575f908d613ad9604094855198899485946304512a2360e31b86528a8a600488016139bb565b03816801bc16d674ec8000008d5af1908115610543577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb194613b2592613b34575b505192839283613a0e565b0390a160018193019290613a61565b80610ae1613b4192610ec6565b5f613b1a565b816030116102e757613aa6917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613b8561460d565b90613b9c613b938486613965565b96909486613976565b94813b156102e7576801bc16d674ec8000005f94613c0297604051988996879586946304512a2360e31b865260806004870152613bf3613be08d608489019061214f565b60031994858983030160248a0152611b1f565b92868403016044870152612167565b90606483015203925af1908115610543577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb192612a3392613c4b575b50604051918291826139fd565b613c5490610ec6565b5f613c3e565b6001600160801b0390818111613c6e571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613d155760028355814710613cfd575f918291829182916001600160a01b03165af1613cdf61233a565b5015613ceb5760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b03821681158015613d56575b15613d495750905090565b6106169260801c9161266b565b508015613d3e565b6098546001600160801b0381169082158015613dae575b15613d7f57505090565b60801c90613d8e82828561266b565b9282156122555709613d9d5790565b600181018091111561061657611dde565b508115613d75565b613dbe613729565b6001600160a01b03168015613e0657606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b9190613e22613729565b6001600160a01b038316908115610aed578015613ece5780613e4961194c60985460801c90565b0193613e53612069565b8511613ebc5761098494613e7a91613e75613e6d85613d5e565b978893613c5a565b613f8c565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613eec613729565b6001600160a01b038216918215610aed578115613ece5781613f1361194c60985460801c90565b01613f1c612069565b8111613ebc5761098495613f63613eb7927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613e75613f5b88613d5e565b9a8b93613c5a565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613f9582613c5a565b60985490613fad6001600160801b0391828416612b02565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609a549068010000000000000000821015610ec1576001820180609a5582101561232857609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614a8183398151915290910155565b91909180156140e057614047614842565b90810180911161139c576001600160a01b038082116140c0576001600160601b03908185116140a0579061201b939461409b926040519461408786610ea6565b168452166001600160601b03166020830152565b613fd8565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b6140fa614842565b6001810180911161139c576001600160a01b038082116140c0579061201b916040519161412683610ea6565b1681525f6020820152613fd8565b80156140e057614142614842565b90810180911161139c576001600160a01b038082116140c0579061201b916040519161412683610ea6565b908082101561417a575090565b905090565b614187614884565b1561418e57565b604051630a62fbdb60e11b8152600490fd5b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156105435761423b936001600160401b036107ea604061421a946020975f9161428b575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610543575f91614272575090565b610616915060203d60201161053c5761052e8183610f0f565b6142a4915060603d606011610abd57610aae8183610f0f565b5f61420b565b60018060a01b03165f52609c60205260405f2090815481810390811161139c576142d49255613c5a565b609854906001600160801b03908183160316906001600160801b03191617609855565b6142ff614318565b614307614506565b60d35481036143135750565b60d355565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561434757565b604051631afcd79f60e31b8152600490fd5b614361614318565b801561437757600181016143725750565b609d55565b6040516331278a8760e01b8152600490fd5b614391614318565b6801bc16d674ec8000006143a3612069565b1061437757614313614506565b6143b8614318565b6001600160a01b0316806143c95750565b61016a80546001600160a01b0319169091179055565b6143e7614318565b6143ef614318565b6143f7614318565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca00341061443057611e9c3430613e18565b60405163ea2559bb60e01b8152600490fd5b908160209103126102e7575160ff811681036102e75790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816144e5575b506144ab57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614ac183398151915284036144cc5761201b9293506148f3565b604051632a87526960e21b815260048101859052602490fd5b6144ff91955060203d60201161053c5761052e8183610f0f565b935f614485565b6e5661756c7456616c696461746f727360881b602060405161452781610ea6565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b03821117610ec15760405251902090565b8151919060418303614603576145fc9250602082015190606060408401519301515f1a90614995565b9192909190565b50505f9160029190565b604051600160f81b60208201525f60218201523060601b602c8201526020815261061681610ea6565b60018060a01b0381165f5261013760205260405f20906040519161465983610ea6565b54906001600160801b03918281169081855260801c602085015215612a4e57612d7461080f6146ac9261468a613729565b614693866124c8565b6001600160a01b03165f908152609c6020526040902090565b91511611612eaa57565b9291908015611a9a576001600160a01b03828116928315610aed576146dc6116bf614884565b6147c957906117cd956147ad612bb9857f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f958161478261472761194c6099546001600160801b031690565b926120d56147548561474f61473a614842565b61474961194c609e5460801c90565b90612290565b612290565b9e8f6040519283916020830195429087604091949392606082019560018060a01b0316825260208201520152565b556001600160a01b0385165f908152609c602052604090206147a5838254612098565b905501613c5a565b6040805188815260208101959095529116929081908101613eb7565b9293946147d583611e55565b938415613ece577f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809361481f8661483a93614815610984612c5484613c5a565b61324884876142aa565b60405193849316958360209093929193604081019481520152565b0390a35f1990565b609a548061484f57505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166111f3565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610543575f916148da575090565b610616915060203d6020116110f9576110ea8183610f0f565b90813b15614974575f80516020614ac183398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561495957611e9c91614a17565b50503461496257565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614a0c579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610543575f516001600160a01b03811615614a0257905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061061693602081519101845af4614a2e61233a565b9190614a445750805115613ceb57805190602001fd5b81511580614a77575b614a55575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614a4d56fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220bfc252ddce624b4e17b899c19f83b533ae868abc55e8580e4dbd0b889736bc9064736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/EthVaultV1.json b/test/shared/artifacts/EthVaultV1.json deleted file mode 100644 index e8ade253..00000000 --- a/test/shared/artifacts/EthVaultV1.json +++ /dev/null @@ -1,1596 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "EthVault", - "sourceName": "contracts/vaults/ethereum/EthVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitedAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "ClaimTooEarly", - "type": "error" - }, - { - "inputs": [], - "name": "Collateralized", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidLtv", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidProof", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSecurityDeposit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidator", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "MerkleProofInvalidMultiproof", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "RedemptionExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftShares", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "claimedShares", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "claimedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "claimedShares", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "claimedAssets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "keysManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFromMevEscrow", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeem", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "name": "registerValidator", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "uint256[]", - "name": "indexes", - "type": "uint256[]" - }, - { - "internalType": "bool[]", - "name": "proofFlags", - "type": "bool[]" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "keysManager_", - "type": "address" - } - ], - "name": "setKeysManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_validatorsRoot", - "type": "bytes32" - } - ], - "name": "setValidatorsRoot", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateStateAndDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x610180346200022657601f620049a438819003918201601f19168301926001600160401b03929091838511838610176200022a578160e09284926040978852833981010312620002265762000054816200023e565b9262000063602083016200023e565b90620000718184016200023e565b9362000080606085016200023e565b946200008f608086016200023e565b9360c0620000a060a088016200023e565b9601519760805260a05260c0523060e05261010095865260018060a01b038061012096168652610140931683526101609384527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c1662000215578080831603620001d0575b5050505192614750948562000254863960805185818161199e015281816121ae01528181612af801528181612f710152818161330e0152613f3f015260a051856115e4015260c0518581816139710152613b12015260e0518581816117d0015261348c015251846126bf01525183818161036f015281816106000152818161091301528181610f3701528181612c6d01526142c80152518281816106dc015281816109bf01528181610fe3015261424701525181818161248f0152612fb90152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80806200010e565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002265756fe60806040526004361015610022575b3615610018575f80fd5b610020612c4e565b005b5f3560e01c806301e1d114146102e1578063066055e0146102dc57806307a2d13a146102d757806318f72950146102d25780631a7ff553146102cd578063201b9eb5146102c85780632999ad3f146102c35780632cdf7401146102be5780633229fa95146102b957806333194c0a146102b45780633a98ef39146102af578063439fab91146102aa57806343e82a79146102a557806346904840146102a05780634ec96b221461029b5780634f1ef28614610296578063514e27081461029157806352d1902d1461028c57806353156f281461028757806354fd4d50146102825780635c60da1b1461027d5780635cfc1a51146102785780635dddf3a81461027357806360d60e6e1461026e57806372b410a81461026957806376b58b90146102645780637bde82f21461025f5780637fd6f15c1461025a5780638697d2c2146102555780638ceab9aa146102505780639b401cde1461024b578063a1bf49aa14610246578063a49a1e7d14610241578063aaa4e8361461023c578063ac9650d814610237578063ad3cb1cc14610232578063c6e6f5921461022d578063d83ad00c14610228578063e74b981b14610223578063ef2a21581461021e578063f04da65b14610219578063f5e9de4d14610214578063f851a4401461020f5763f9609f080361000e5761230d565b6122e6565b612156565b61211b565b612093565b612058565b612032565b612014565b611fcf565b611eda565b611d94565b611d3d565b611d20565b611d03565b611bbd565b611b98565b611b74565b611a51565b611a00565b611973565b6118ce565b6118b4565b61189a565b611866565b61184b565b611827565b6117be565b611752565b6114cc565b611373565b61134b565b610f0c565b610df3565b610d84565b610d4a565b610d1e565b610d04565b6108e9565b610590565b61055d565b610504565b6104bf565b610314565b6102f4565b5f9103126102f057565b5f80fd5b346102f0575f3660031901126102f057602060985460801c604051908152f35b346102f05760203660031901126102f0576001600160801b03600435818116908181036102f057604051633b9e9f0160e21b81523360048201526001600160801b0382166024820152916020836044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ba575f93610489575b50335f908152610137602052604090206103b890612351565b936103ca85516001600160801b031690565b1615610477578361040c6103ff6103ef610425946103ea61047399612c58565b612d08565b83516001600160801b031661238a565b6001600160801b03168252565b335f908152610137602052604090206123a3565b6123a3565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b6104ac91935060203d6020116104b3575b6104a4818361144b565b810190612337565b915f61039f565b503d61049a565b612346565b346102f05760203660031901126102f05760206104dd6004356123d5565b604051908152f35b6001600160a01b038116036102f057565b908160809103126102f05790565b60603660031901126102f05760043561051c816104e5565b602435610528816104e5565b604435906001600160401b0382116102f0576020926105566105516104dd9436906004016104f6565b6123fb565b3490613cdf565b346102f05760203660031901126102f0576004356001600160401b0381116102f0576105516100209136906004016104f6565b346102f05760603660031901126102f05760048035906105af826104e5565b60243590604435926105c0846104e5565b6105c86132d2565b6105d06132f3565b604080516329460cc560e11b81526001600160a01b038381168286019081526020818101889052929693959192907f00000000000000000000000000000000000000000000000000000000000000008416908290899081908a0103815f855af19788156104ba575f9861089e575b50335f90815261013760205260409020839061065990612351565b946001600160801b0361067387516001600160801b031690565b161561083c5761068286612c58565b6106ae6106a161069189612d08565b88516001600160801b031661242c565b6001600160801b03168752565b335f908152609c6020526040902084906106c9905b546123d5565b918a5193848092631331885160e31b82527f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ba5761075892859261071c925f9261081d575b50612d5e565b9261072e87516001600160801b031690565b908a5180809581946303d1689d60e11b83528a83019190916001600160801b036020820193169052565b03915afa9283156104ba575f936107fe575b5050106107f05750947fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58916107b7610473976104203360018060a01b03165f5261013760205260405f2090565b84516001600160a01b039485168152602081018790526040810191909152921660608301523391608090a2519081529081906020820190565b8451633684c65960e01b8152fd5b610815929350803d106104b3576104a4818361144b565b905f8061076a565b610835919250843d86116104b3576104a4818361144b565b905f610716565b885163752a536d60e01b8152915083828681865afa80156104ba5761086d61087c9187945f91610881575b50612d08565b6001600160801b031687860152565b610682565b6108989150873d89116104b3576104a4818361144b565b5f610867565b6108b6919850823d84116104b3576104a4818361144b565b965f61063e565b60609060031901126102f057600435906024356108d9816104e5565b906044356108e6816104e5565b90565b346102f0576108f7366108bd565b906001600160a01b0380831615610cf2576109106132f3565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102f05760408051631d8557d760e01b815260049491905f81878183875af180156104ba57610cd9575b506001600160a01b0383165f9081526101376020526040902061098390612351565b6001600160801b0361099c82516001600160801b031690565b1615610cc9576109ab81612c58565b81516330fe427560e21b81529260a08488817f00000000000000000000000000000000000000000000000000000000000000008a165afa9687156104ba57610a1a975f955f91610c90575b5084516303d1689d60e11b918282528c828060209d8e938883019190602083019252565b0381885afa80156104ba57610a35925f91610c735750612d5e565b95610a536106c38960018060a01b03165f52609c60205260405f2090565b918288118015610c63575b610c5357908a610a9b92610a7988516001600160801b031690565b908951948592839283528883019190916001600160801b036020820193169052565b0381885afa9081156104ba57670de0b6b3a764000093610ad7938d5f94610c2a575b5050610acb610ad191612ab4565b92612ad1565b91612dd8565b1015610c1c578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156104ba577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610bf995610b7193610bfe575b5050610b546103ff6103ef8c612d08565b6001600160a01b0386165f908152610137602052604090206123a3565b610b7a82613748565b90610bb8610b9d610b8a85612d08565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610bc28286613f93565b610bcc838961369b565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610c1492903d106104b3576104a4818361144b565b505f80610b43565b835163185cfc6d60e11b8152fd5b610ad1929450610acb9181610c4a92903d106104b3576104a4818361144b565b9391508d610abd565b865163efda1a2760e01b81528490fd5b50610c6c612447565b8811610a5e565b610c8a91508c8d3d106104b3576104a4818361144b565b5f610716565b9050610cb591955060a03d60a011610cc2575b610cad818361144b565b81019061337e565b509692509050945f6109f6565b503d610ca3565b815163673f032f60e11b81528690fd5b80610ce6610cec9261141d565b806102e6565b5f610961565b60405163d92e233d60e01b8152600490fd5b346102f0575f3660031901126102f05760206104dd612447565b346102f0575f3660031901126102f0576020610d38612476565b6040516001600160a01b039091168152f35b346102f0575f3660031901126102f05760206040517fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b8152f35b346102f0575f3660031901126102f05760206001600160801b0360985416604051908152f35b9060206003198301126102f0576004356001600160401b03928382116102f057806023830112156102f05781600401359384116102f057602484830101116102f0576024019190565b610dfc36610daa565b905f805160206146fb83398151915254916001600160401b0360ff8460401c1615931680159081610f04575b6001149081610efa575b159081610ef1575b50610edf575f805160206146fb833981519152805467ffffffffffffffff19166001179055610e6d9183610ebb576124c6565b610e7357005b5f805160206146fb833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b5f805160206146fb833981519152805460ff60401b1916600160401b1790556124c6565b60405163f92ee8a960e01b8152600490fd5b9050155f610e3a565b303b159150610e32565b849150610e28565b346102f057610f1a366108bd565b906001600160a01b039081831615610cf257610f346132f3565b817f000000000000000000000000000000000000000000000000000000000000000016803b156102f05760408051631d8557d760e01b815260049291905f81858183875af180156104ba57611338575b506001600160a01b0384165f90815261013760205260409020610fa690612351565b926001600160801b03610fc085516001600160801b031690565b161561132a57610fcf84612c58565b81516330fe427560e21b81529360a08583817f00000000000000000000000000000000000000000000000000000000000000008b165afa9384156104ba575f955f956112fc575b5083516303d1689d60e11b8082528482018c81529197602094939285908a90819083015b0381865afa9889156104ba575f996112dd575b506001600160a01b038a165f908152609c6020526040902061106e906106c3565b90818a1180156112cd575b6112bd576110b4908661109387516001600160801b031690565b8a51809481928883528c83019190916001600160801b036020820193169052565b0381885afa9182156104ba575f9261129c575b506110d29192612d5e565b1161128c578551633b9e9f0160e21b815233868201908152602081018e905290919085908390819060400103815f875af19182156104ba57859261126f575b5061111b8d612d08565b84516001600160801b0316906111309161238a565b6001600160801b031684526001600160a01b038a165f908152610137602052604090208461115d916123a3565b61116689613748565b976111708a612d08565b60985460801c036001600160801b031661119f906001600160801b036098549181199060801b16911617609855565b6111a9898c613f93565b6001600160a01b038b165f908152609c60205260409020546111ca906123d5565b906111d491612d5e565b935187519182526001600160801b0316868201908152909283918290036020019082905afa9283156104ba575f93611250575b505011611242575091610bf9917f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3959493610bcc838961369b565b9051631d8fa13d60e31b8152fd5b611267929350803d106104b3576104a4818361144b565b905f80611207565b61128590833d85116104b3576104a4818361144b565b505f611111565b855163324b20e160e11b81528590fd5b6110d292506112b790883d8a116104b3576104a4818361144b565b916110c7565b875163efda1a2760e01b81528790fd5b506112d6612447565b8a11611079565b6112f5919950853d87116104b3576104a4818361144b565b975f61104d565b61103a92965061131c91955060a03d60a011610cc257610cad818361144b565b505050959095949091611016565b905163673f032f60e11b8152fd5b80610ce66113459261141d565b5f610f84565b346102f0575f3660031901126102f0576065546040516001600160a01b039091168152602090f35b346102f05760203660031901126102f057600435611390816104e5565b60018060a01b03165f52610137602052602060405f20604051906113b3826113fd565b54906001600160801b03918281169081835260801c848301526113db575b5116604051908152f35b6113e481612c58565b6113d1565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761141857604052565b6113e9565b6001600160401b03811161141857604052565b606081019081106001600160401b0382111761141857604052565b90601f801991011681019081106001600160401b0382111761141857604052565b60405190611479826113fd565b565b6001600160401b03811161141857601f01601f191660200190565b9291926114a28261147b565b916114b0604051938461144b565b8294818452818301116102f0578281602093845f960137010152565b6040806003193601126102f05760049081356114e7816104e5565b6024356001600160401b0381116102f057366023820112156102f0576115169036906024818701359101611496565b9161151f613482565b8051926115568461154860209363439fab9160e01b858401528460248401526044830190611e52565b03601f19810186528561144b565b61155e613482565b611566613735565b6001600160a01b0383811680159291908790841561171d575b84156116af575b841561164b575b505082156115b5575b50506115a657610020838361410a565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ba575f9261161e575b5050155f80611596565b61163d9250803d10611644575b611635818361144b565b810190612618565b5f80611614565b503d61162b565b855163054fd4d560e41b81529294508391839182905afa9081156104ba5760029160ff915f91611682575b5016141591865f61158d565b6116a29150843d86116116a8575b61169a818361144b565b8101906140f1565b5f611676565b503d611690565b935050835163198ca60560e11b815282818981875afa9081156104ba5788917fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b915f91611700575b50141593611586565b6117179150853d87116104b3576104a4818361144b565b5f6116f7565b5f805160206146db83398151915254909450849061174b906001600160a01b03165b6001600160a01b031690565b149361157f565b346102f05760203660031901126102f0576004356001600160a01b036117766125ef565b1633036117ac578060d0555f60d155337fbe9758e2d6800505eeb0292a08fe647c52762ccea131177456e7062dd77b41065f80a3005b604051634ca8886760e01b8152600490fd5b346102f0575f3660031901126102f0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036118155760206040515f805160206146db8339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126102f0576001600160a01b03611842612476565b1633036117ac57005b346102f0575f3660031901126102f057602060405160018152f35b346102f0575f3660031901126102f0575f805160206146db833981519152546040516001600160a01b039091168152602090f35b346102f0575f3660031901126102f05760206104dd6125e1565b346102f0575f3660031901126102f0576020610d386125ef565b346102f05760203660031901126102f057609a80549081905f6004355b84821061191c5750505081101561191157610473905b6040519081529081906020820190565b506104735f19611901565b909193808316906001818518811c830180931161196e575f8790525f805160206146bb8339815191528301546001600160a01b0316841015611963575050935b91906118eb565b90959101925061195c565b612376565b346102f0575f3660031901126102f057604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104ba576020915f916119e3575b506040519015158152f35b6119fa9150823d841161164457611635818361144b565b5f6119d8565b346102f05760803660031901126102f057610473611a34600435611a23816104e5565b60643590604435906024359061263a565b604080519384526020840192909252908201529081906060820190565b346102f0576040806003193601126102f05760043560243591611a73836104e5565b611a7b614649565b8115611b64576001600160a01b0383168015611b5357611a9a836123d5565b928315611b4257611aa9612447565b8411611b3157611ae08461047396611ad1610b9d611ac684612d08565b60985460801c61238a565b611adb8433613f93565b61369b565b8251848152602081019190915233907f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809080604081015b0390a3611b23336141b5565b519081529081906020820190565b82516396d8043360e01b8152600490fd5b82516318374fd160e21b8152600490fd5b815163d92e233d60e01b8152600490fd5b51636edcc52360e01b8152600490fd5b346102f0575f3660031901126102f057602061ffff60655460a01c16604051908152f35b346102f05760603660031901126102f057610473611a346044356024356004356126b4565b346102f0576040806003193601126102f0576004359060243590611be0826104e5565b611be86132d2565b8215611b64576001600160a01b0382168015611b535783611cc8611cac61047396611c2a611c1e6099546001600160801b031690565b6001600160801b031690565b81611c8a611c3f83611c3a6144f4565b6126a7565b89516001600160a01b03909b1660208c019081524260408d015260608c01829052909a611c7981608081015b03601f19810183528261144b565b5190205f52609b60205260405f2090565b55335f908152609c60205260409020611ca483825461262d565b905501612d08565b6001600160801b03166001600160801b03196099541617609955565b8251848152602081019190915233907f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f908060408101611b17565b346102f0575f3660031901126102f057602060d054604051908152f35b346102f0575f3660031901126102f057602060d154604051908152f35b346102f057611d8f7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611d6f36610daa565b9290611d79613735565b604051918291602083523395602084019161284b565b0390a2005b346102f05760203660031901126102f057600435611db1816104e5565b611db9613735565b6001600160a01b03168015610cf25760d280546001600160a01b03191682179055337fb710e1d0ebf395f895942ac4e559a4a86d57f748a90cf05e9d70798c67e9c65b5f80a3005b9181601f840112156102f0578235916001600160401b0383116102f0576020808501948460051b0101116102f057565b5f5b838110611e425750505f910152565b8181015183820152602001611e33565b90602091611e6b81518092818552858086019101611e31565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611eac5750505050505090565b9091929394958480611eca600193603f198682030187528a51611e52565b9801930193019194939290611e9c565b346102f05760203660031901126102f057600480356001600160401b0381116102f057611f0b903690600401611e01565b91611f1583612882565b925f5b818110611f2d57604051806104738782611e77565b5f80611f3a838588612911565b60409391611f4c855180938193612931565b0390305af490611f5a61293e565b9115611f81575090600191611f6f82886129d8565b52611f7a81876129d8565b5001611f18565b848260448151106102f057611fa58183611fba93015160248091830101910161296d565b925162461bcd60e51b81529283928301611fbe565b0390fd5b9060206108e6928181520190611e52565b346102f0575f3660031901126102f057610473604051611fee816113fd565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611e52565b346102f05760203660031901126102f05760206104dd600435613748565b346102f0575f3660031901126102f05760206001600160801b0360995416604051908152f35b346102f05760203660031901126102f057610020600435612078816104e5565b612080613735565b6137d7565b908160a09103126102f05790565b346102f05760803660031901126102f0576001600160401b036004358181116102f0576120c4903690600401612085565b6024358281116102f0576120dc903690600401611e01565b6044929192358481116102f0576120f7903690600401611e01565b916064359586116102f057612113610020963690600401611e01565b959094612ae8565b346102f05760203660031901126102f057600435612138816104e5565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102f0576040806003193601126102f0576004906001600160401b0382358181116102f0576121899036908501612085565b906024359081116102f0576121a19036908501611e01565b9390926121ac6132f3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102f0575f8251809263837d444160e01b82528183816121fb8a8a8301612a1d565b03925af180156104ba576122d3575b506801bc16d674ec80000061221d612447565b106122c6578083019360b061223286866128df565b9050036122b8576122846122889160d1549760d0549061227761226f8b6122598c8c6128df565b611c6b8b94929451938492602084019687612c1a565b519020612c37565b6020815191012092613acc565b1590565b6122ab576100206001866122a561229f88886128df565b90613b04565b0160d155565b516309bde33960e01b8152fd5b5051631a0a9b9f60e21b8152fd5b516396d8043360e01b8152fd5b80610ce66122e09261141d565b5f61220a565b346102f0575f3660031901126102f0575f546040516001600160a01b039091168152602090f35b60403660031901126102f05760206104dd60043561232a816104e5565b60243590610556826104e5565b908160209103126102f0575190565b6040513d5f823e3d90fd5b9060405161235e816113fd565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161196e57565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816123ed57505090565b916108e69260801c90612dd8565b61240490612f40565b908061241d575b5061241257565b61241a6131d5565b50565b612426906130d6565b5f61240b565b9190916001600160801b038080941691160191821161196e57565b4760995461245d6001600160801b0382166123d5565b9060801c01908181115f14612470570390565b50505f90565b61016a546001600160a01b0316801561248c5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102f057516108e6816104e5565b60405163e7f6f22560e01b8152602092908381600481335afa9081156104ba575f916125c4575b50604051636f4fa30f60e01b8152918483600481335afa9283156104ba575f93612595575b5083019380848603126102f05783356001600160401b03948582116102f05701936060858703126102f0576040519461254a86611430565b803586528281013561ffff811681036102f0578387015260408101359182116102f057019480601f870112156102f0578561258b9261147997359101611496565b60408401526133a5565b6125b6919350853d87116125bd575b6125ae818361144b565b8101906124b1565b915f612512565b503d6125a4565b6125db9150843d86116125bd576125ae818361144b565b5f6124ed565b609d54806108e657505f1990565b60d2546001600160a01b039081168061260957505f541690565b905090565b801515036102f057565b908160209103126102f057516108e68161260e565b9190820391821161196e57565b604080516001600160a01b03909216602083019081529082019390935260608101829052909261268a9290916126738160808101611c6b565b5190205f52609b60205260405f2054928391613500565b909182810390811161196e5792565b906001820180921161196e57565b9190820180921161196e57565b929190915f936126e47f0000000000000000000000000000000000000000000000000000000000000000856126a7565b42106128215760408051336020820190815291810186905260608082018490528152601f19916127259161271960808261144b565b5190209486843361263a565b90969095878781156128135750505f908152609b6020526040812055600182116127c9575b50505061278261276761275c85612d08565b60995460801c61238a565b6001600160801b036099549181199060801b16911617609955565b61278c833361369b565b6040805191825260208201869052810183905233907feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5690606090a2565b61280a919297506127da87856126a7565b60408051336020820190815291810193909352606083018290526080998a0183529098909190611c79908261144b565b555f808061274a565b959950975093955050505050565b604051631613b7eb60e01b8152600490fd5b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b6001600160401b0381116114185760051b60200190565b9061288c8261286b565b612899604051918261144b565b82815280926128aa601f199161286b565b01905f5b8281106128ba57505050565b8060606020809385010152016128ae565b634e487b7160e01b5f52603260045260245ffd5b903590601e19813603018212156102f057018035906001600160401b0382116102f0576020019181360383136102f057565b9082101561292c576129289160051b8101906128df565b9091565b6128cb565b908092918237015f815290565b3d15612968573d9061294f8261147b565b9161295d604051938461144b565b82523d5f602084013e565b606090565b6020818303126102f0578051906001600160401b0382116102f0570181601f820112156102f057805161299f8161147b565b926129ad604051948561144b565b818452602082840101116102f0576108e69160208085019101611e31565b80511561292c5760200190565b805182101561292c5760209160051b010190565b9035601e19823603018112156102f05701602081359101916001600160401b0382116102f05781360383136102f057565b9060a06108e692602081528235602082015260208301356040820152612a59612a4960408501856129ec565b84606085015260c084019161284b565b90612a8c612a81612a6d60608701876129ec565b601f1985870381016080870152959161284b565b9460808101906129ec565b9390928286030191015261284b565b906801bc16d674ec800000918083029283040361196e57565b90670de0b6b3a76400009182810292818404149015171561196e57565b906127109182810292818404149015171561196e57565b929094939195612af66132f3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031695863b156102f0576040965f8851809263837d444160e01b8252818381612b4a8c60048301612a1d565b03925af180156104ba57612c07575b50612b62612447565b612b6b89612a9b565b11612bf65787158015612bdc575b612bcb5791612ba9959391612ba3896122849795612b9d60d054978c8101906128df565b90613947565b94613aba565b612bbb57506114799060d1540160d155565b516309bde33960e01b8152600490fd5b8651631c6c4cf360e31b8152600490fd5b50612be9878601866128df565b905060b089021415612b79565b86516396d8043360e01b8152600490fd5b80610ce6612c149261141d565b5f612b59565b939291602091612c329160408752604087019161284b565b930152565b9060405191602083015260208252611479826113fd565b61241a3433613c17565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ba575f91612ce9575b5060208201916001600160801b03918284511691828214612ce25783612cd56103ea612cdd958584865116612dd8565b169052612d08565b169052565b5050505050565b612d02915060203d6020116104b3576104a4818361144b565b5f612ca5565b6001600160801b0390818111612d1c571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b634e487b7160e01b5f52601260045260245ffd5b8115612d59570490565b612d3b565b90808202905f1981840990828083109203918083039214612dcd576127109082821115612dbb577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514612e4b5784831115612dbb57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906108e69250612d4f565b908160609103126102f057805191604060208301519201516108e68161260e565b81835290916001600160fb1b0383116102f05760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102f05760408301526040810135612ecc816104e5565b6001600160a01b031660608381019190915281013536829003601e19018112156102f05701602081359101906001600160401b0381116102f0578060051b360382136102f05760a0836080806108e69601520191612e79565b9190915f838201938412911290801582169115161761196e57565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612f6b9060048301612e9d565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ba575f915f905f95613091575b50841561303e5781612fb5612476565b16917f000000000000000000000000000000000000000000000000000000000000000016821461303757509060205f92600460405180958193634641257d60e01b83525af19081156104ba57613012925f92613016575b50612f25565b9190565b61303091925060203d6020116104b3576104a4818361144b565b905f61300c565b9081613044575b50509190565b803b156102f057604051636ee3193160e11b815260048101929092525f908290602490829084905af180156104ba5761307e575b8061303e565b80610ce661308b9261141d565b5f613078565b919450506130b7915060603d6060116130bf575b6130af818361144b565b810190612e58565b93905f612fa5565b503d6130a5565b600160ff1b811461196e575f0390565b6130e5611c1e60985460801c90565b5f82126131bc57816130f6916126a7565b90613103610b9d83612d08565b6131186065549161ffff8360a01c1690612d5e565b80156131b757807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613156611c1e6098546001600160801b031690565b806131a157505061319c90925b6001600160a01b0316916131778484613d8b565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b61319c926131b192039084612dd8565b92613163565b505050565b6103ea610b9d916131cf611479946130c6565b9061262d565b609954906001600160801b0382169182156132cc5760801c6132096131fa824761262d565b613203856123d5565b90613dd7565b9081156132c55761321982613748565b9384156132bd57826132456127676103ea61147996610b9d96611c3a611cac6103ea8d611ac69a61262d565b61324f8187613e3d565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a16103ea6132a161329088612d08565b6098546001600160801b031661238a565b6001600160801b03166001600160801b03196098541617609855565b505f93505050565b505f925050565b505f9150565b6132da613f24565b156132e157565b604051630a62fbdb60e11b8152600490fd5b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ba575f9161335f575b5061334d57565b60405163e775715160e01b8152600490fd5b613378915060203d60201161164457611635818361144b565b5f613346565b908160a09103126102f0578051916020820151916040810151916080606083015192015190565b6133ad613fe0565b60408301516133ba613fe0565b5f80546001600160a01b0319166001600160a01b03841617905560405133917f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf919081906134089082611fbe565b0390a2602083015192613419613fe0565b61271061ffff851611613470576134689361343661345b936137d7565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555161400e565b61346361403e565b61405f565b61147961408e565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149182156134c0575b505061181557565b5f805160206146db8339815191525416141590505f806134b8565b906040516134e8816113fd565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613693575b6136865783613650575f5b609a5f526001600160a01b03166135455f805160206146bb83398151915286016134db565b805190979061355c906001600160a01b031661173f565b986135816135756020809b01516001600160601b031690565b6001600160601b031690565b948381108015613646575b6136345791600193979a956135ab6135b7939488035b838c0390613dd7565b80920198870391612dd8565b0197019380861180159061362a575b61361f57609a5f5282906135e85f805160206146bb83398151915287016134db565b805190890151969992966001600160a01b0390911694600193926135b79290916001600160601b03909116906135ab9088036135a2565b945050509250509190565b50818510156135c6565b60405163e8722f8f60e01b8152600490fd5b50808b111561358c565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613520565b505093505050505f905f90565b508415613515565b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613723576002835581471061370b575f918291829182916001600160a01b03165af16136ed61293e565b50156136f95760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b5f546001600160a01b031633036117ac57565b609854906001600160801b03821681158015613777575b1561376a5750905090565b6108e69260801c91612dd8565b50801561375f565b6098546001600160801b03811690821580156137cf575b156137a057505090565b60801c906137af828285612dd8565b928215612d5957096137be5790565b60018101809111156108e657612376565b508115613796565b6137df6132f3565b6001600160a01b0316801561382757606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b906138438261286b565b613850604051918261144b565b8281528092613861601f199161286b565b0190602036910137565b906030116102f05790603090565b906090116102f05760300190606090565b9060b0116102f05760900190602090565b909392938483116102f05784116102f0578101920390565b901561292c5790565b919081101561292c5760051b0190565b3590602081106138da575090565b5f199060200360031b1b1690565b96959490612c3293613909613917926060979560808c5260808c019161284b565b9089820360208b0152611e52565b91878303604089015261284b565b9060206108e6928181520190612833565b9160206108e693818152019161284b565b9193929060d154925f925f9061395c81613839565b9761396561434e565b935f9760018060a01b037f000000000000000000000000000000000000000000000000000000000000000016945b848a106139a65750505050505050505050565b60b06139b691018099898561389b565b9960409a8d6139f28d516139da6020918281019061226f81611c6b8c8a8d87612c1a565b8051910120916139eb858b8b6138bc565b35906129d8565b526139fd818461386b565b9093613a1d613a17613a0f8584613879565b95909361388a565b906138cc565b908a3b156102f0578b8f5f93613a48915196879485946304512a2360e31b8652888c600488016138e8565b03816801bc16d674ec8000008d5af19384156104ba57613a9b60018e7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1958298613aa7575b5097019e5192839283613936565b0390a101989097613993565b80610ce6613ab49261141d565b5f613a8d565b90613ac8949593929161438f565b1490565b9192915f915b808310613ae0575050501490565b909192613afb600191613af48685876138bc565b359061460b565b93019190613ad2565b816030116102f057613a17917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613b4261434e565b90613b59613b508486613879565b9690948661388a565b94813b156102f0576801bc16d674ec8000005f94613bbf97604051988996879586946304512a2360e31b865260806004870152613bb0613b9d8d6084890190612833565b60031994858983030160248a0152611e52565b9286840301604487015261284b565b90606483015203925af19081156104ba577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19261319c92613c08575b5060405191829182613925565b613c119061141d565b5f613bfb565b9190613c216132f3565b6001600160a01b038316908115610cf2578015613ccd5780613c48611c1e60985460801c90565b0193613c526125e1565b8511613cbb57610b9d94613c7991613c74613c6c8561377f565b978893612d08565b613d8b565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613ceb6132f3565b6001600160a01b038216918215610cf2578115613ccd5781613d12611c1e60985460801c90565b01613d1b6125e1565b8111613cbb57610b9d95613d62613cb6927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613c74613d5a8861377f565b9a8b93612d08565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613d9482612d08565b60985490613dac6001600160801b039182841661242c565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015612609575090565b609a5490600160401b821015611418576001820180609a5582101561292c57609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206146bb83398151915290910155565b9081158015613f1c575b613f0a57609a5480613ed457505f905b6001600160a01b0391821692830192831061196e57818311613eb4576114799291613e9f613e87613eaf93614536565b91613e9061146c565b94166001600160a01b03168452565b6001600160601b03166020830152565b613de4565b6040516306dfcc6560e41b815260a0600482015260248101849052604490fd5b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031690613e57565b604051632ec8835b60e21b8152600490fd5b508015613e47565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ba575f91613f7a575090565b6108e6915060203d60201161164457611635818361144b565b60018060a01b03165f52609c60205260405f2090815481810390811161196e57613fbd9255612d08565b609854906001600160801b03908183160316906001600160801b03191617609855565b60ff5f805160206146fb8339815191525460401c1615613ffc57565b604051631afcd79f60e31b8152600490fd5b614016613fe0565b801561402c57600181016140275750565b609d55565b6040516331278a8760e01b8152600490fd5b614046613fe0565b6801bc16d674ec8000006140586125e1565b1061402c57565b614067613fe0565b6001600160a01b0316806140785750565b61016a80546001600160a01b0319169091179055565b614096613fe0565b61409e613fe0565b6140a6613fe0565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca0034106140df5761241a3430613c17565b60405163ea2559bb60e01b8152600490fd5b908160209103126102f0575160ff811681036102f05790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614194575b5061415a57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206146db833981519152840361417b57611479929350614569565b604051632a87526960e21b815260048101859052602490fd5b6141ae91955060203d6020116104b3576104a4818361144b565b935f614134565b6001600160a01b0381165f908152610137602052604090206141d690612351565b906001600160801b036141f083516001600160801b031690565b161561434a576106c3614227916142056132f3565b61420e84612c58565b6001600160a01b03165f908152609c6020526040902090565b604051631331885160e31b8152602092916001600160a01b0384836004817f000000000000000000000000000000000000000000000000000000000000000085165afa9182156104ba5761428a8693614298926142c4965f926143325750612d5e565b94516001600160801b031690565b6040516303d1689d60e11b81526001600160801b03909116600482015292839190829081906024820190565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9283156104ba575f93614313575b50501061430157565b604051633684c65960e01b8152600490fd5b61432a929350803d106104b3576104a4818361144b565b905f806142f8565b610835919250863d88116104b3576104a4818361144b565b5050565b604051600160f81b60208201525f60218201523060601b602c820152602081526108e6816113fd565b5f19811461196e5760010190565b356108e68161260e565b92939190918051936143a184866126a7565b6143aa87612699565b036143ec576143b886613839565b945f8094885f965f5b8281106144245750501591506143fe905057505050036143ec576143e8915f1901906129d8565b5190565b604051631a8a024960e11b8152600490fd5b9195509293501590506144165750506143e8906129cb565b61442092506138b3565b3590565b8a868610156144d757506144566144518261444861444189614377565b988c6129d8565b51955b876138bc565b614385565b156144bc578a8686101561449b57506144876001929361447f61447888614377565b978b6129d8565b515b9061460b565b614491828d6129d8565b5201908a916143c1565b92614487906144b6846144b060019691614377565b966129d8565b51614481565b61448760019293613af46144cf8c614377565b9b8d8b6138bc565b91614451826144ed836144b06144569591614377565b519561444b565b609a548061450157505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661173f565b6001600160601b039081811161454a571690565b604490604051906306dfcc6560e41b8252606060048301526024820152fd5b90813b156145ea575f805160206146db83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156145cf5761241a9161462c565b5050346145d857565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b8181101561461f575f5260205260405f2090565b905f5260205260405f2090565b5f806108e693602081519101845af461464361293e565b91614669565b614651613f24565b61465757565b6040516389a1dc6360e01b8152600490fd5b9061467e57508051156136f957805190602001fd5b815115806146b1575b61468f575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561468756fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220575227d2ab6f6dc09c808397834f8b2864f1374a42b4bf85b19f335a03976c6764736f6c63430008160033", - "deployedBytecode": "0x60806040526004361015610022575b3615610018575f80fd5b610020612c4e565b005b5f3560e01c806301e1d114146102e1578063066055e0146102dc57806307a2d13a146102d757806318f72950146102d25780631a7ff553146102cd578063201b9eb5146102c85780632999ad3f146102c35780632cdf7401146102be5780633229fa95146102b957806333194c0a146102b45780633a98ef39146102af578063439fab91146102aa57806343e82a79146102a557806346904840146102a05780634ec96b221461029b5780634f1ef28614610296578063514e27081461029157806352d1902d1461028c57806353156f281461028757806354fd4d50146102825780635c60da1b1461027d5780635cfc1a51146102785780635dddf3a81461027357806360d60e6e1461026e57806372b410a81461026957806376b58b90146102645780637bde82f21461025f5780637fd6f15c1461025a5780638697d2c2146102555780638ceab9aa146102505780639b401cde1461024b578063a1bf49aa14610246578063a49a1e7d14610241578063aaa4e8361461023c578063ac9650d814610237578063ad3cb1cc14610232578063c6e6f5921461022d578063d83ad00c14610228578063e74b981b14610223578063ef2a21581461021e578063f04da65b14610219578063f5e9de4d14610214578063f851a4401461020f5763f9609f080361000e5761230d565b6122e6565b612156565b61211b565b612093565b612058565b612032565b612014565b611fcf565b611eda565b611d94565b611d3d565b611d20565b611d03565b611bbd565b611b98565b611b74565b611a51565b611a00565b611973565b6118ce565b6118b4565b61189a565b611866565b61184b565b611827565b6117be565b611752565b6114cc565b611373565b61134b565b610f0c565b610df3565b610d84565b610d4a565b610d1e565b610d04565b6108e9565b610590565b61055d565b610504565b6104bf565b610314565b6102f4565b5f9103126102f057565b5f80fd5b346102f0575f3660031901126102f057602060985460801c604051908152f35b346102f05760203660031901126102f0576001600160801b03600435818116908181036102f057604051633b9e9f0160e21b81523360048201526001600160801b0382166024820152916020836044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ba575f93610489575b50335f908152610137602052604090206103b890612351565b936103ca85516001600160801b031690565b1615610477578361040c6103ff6103ef610425946103ea61047399612c58565b612d08565b83516001600160801b031661238a565b6001600160801b03168252565b335f908152610137602052604090206123a3565b6123a3565b604080518381526001600160801b0392909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a79190a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b6104ac91935060203d6020116104b3575b6104a4818361144b565b810190612337565b915f61039f565b503d61049a565b612346565b346102f05760203660031901126102f05760206104dd6004356123d5565b604051908152f35b6001600160a01b038116036102f057565b908160809103126102f05790565b60603660031901126102f05760043561051c816104e5565b602435610528816104e5565b604435906001600160401b0382116102f0576020926105566105516104dd9436906004016104f6565b6123fb565b3490613cdf565b346102f05760203660031901126102f0576004356001600160401b0381116102f0576105516100209136906004016104f6565b346102f05760603660031901126102f05760048035906105af826104e5565b60243590604435926105c0846104e5565b6105c86132d2565b6105d06132f3565b604080516329460cc560e11b81526001600160a01b038381168286019081526020818101889052929693959192907f00000000000000000000000000000000000000000000000000000000000000008416908290899081908a0103815f855af19788156104ba575f9861089e575b50335f90815261013760205260409020839061065990612351565b946001600160801b0361067387516001600160801b031690565b161561083c5761068286612c58565b6106ae6106a161069189612d08565b88516001600160801b031661242c565b6001600160801b03168752565b335f908152609c6020526040902084906106c9905b546123d5565b918a5193848092631331885160e31b82527f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ba5761075892859261071c925f9261081d575b50612d5e565b9261072e87516001600160801b031690565b908a5180809581946303d1689d60e11b83528a83019190916001600160801b036020820193169052565b03915afa9283156104ba575f936107fe575b5050106107f05750947fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58916107b7610473976104203360018060a01b03165f5261013760205260405f2090565b84516001600160a01b039485168152602081018790526040810191909152921660608301523391608090a2519081529081906020820190565b8451633684c65960e01b8152fd5b610815929350803d106104b3576104a4818361144b565b905f8061076a565b610835919250843d86116104b3576104a4818361144b565b905f610716565b885163752a536d60e01b8152915083828681865afa80156104ba5761086d61087c9187945f91610881575b50612d08565b6001600160801b031687860152565b610682565b6108989150873d89116104b3576104a4818361144b565b5f610867565b6108b6919850823d84116104b3576104a4818361144b565b965f61063e565b60609060031901126102f057600435906024356108d9816104e5565b906044356108e6816104e5565b90565b346102f0576108f7366108bd565b906001600160a01b0380831615610cf2576109106132f3565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102f05760408051631d8557d760e01b815260049491905f81878183875af180156104ba57610cd9575b506001600160a01b0383165f9081526101376020526040902061098390612351565b6001600160801b0361099c82516001600160801b031690565b1615610cc9576109ab81612c58565b81516330fe427560e21b81529260a08488817f00000000000000000000000000000000000000000000000000000000000000008a165afa9687156104ba57610a1a975f955f91610c90575b5084516303d1689d60e11b918282528c828060209d8e938883019190602083019252565b0381885afa80156104ba57610a35925f91610c735750612d5e565b95610a536106c38960018060a01b03165f52609c60205260405f2090565b918288118015610c63575b610c5357908a610a9b92610a7988516001600160801b031690565b908951948592839283528883019190916001600160801b036020820193169052565b0381885afa9081156104ba57670de0b6b3a764000093610ad7938d5f94610c2a575b5050610acb610ad191612ab4565b92612ad1565b91612dd8565b1015610c1c578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156104ba577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610bf995610b7193610bfe575b5050610b546103ff6103ef8c612d08565b6001600160a01b0386165f908152610137602052604090206123a3565b610b7a82613748565b90610bb8610b9d610b8a85612d08565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610bc28286613f93565b610bcc838961369b565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610c1492903d106104b3576104a4818361144b565b505f80610b43565b835163185cfc6d60e11b8152fd5b610ad1929450610acb9181610c4a92903d106104b3576104a4818361144b565b9391508d610abd565b865163efda1a2760e01b81528490fd5b50610c6c612447565b8811610a5e565b610c8a91508c8d3d106104b3576104a4818361144b565b5f610716565b9050610cb591955060a03d60a011610cc2575b610cad818361144b565b81019061337e565b509692509050945f6109f6565b503d610ca3565b815163673f032f60e11b81528690fd5b80610ce6610cec9261141d565b806102e6565b5f610961565b60405163d92e233d60e01b8152600490fd5b346102f0575f3660031901126102f05760206104dd612447565b346102f0575f3660031901126102f0576020610d38612476565b6040516001600160a01b039091168152f35b346102f0575f3660031901126102f05760206040517fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b8152f35b346102f0575f3660031901126102f05760206001600160801b0360985416604051908152f35b9060206003198301126102f0576004356001600160401b03928382116102f057806023830112156102f05781600401359384116102f057602484830101116102f0576024019190565b610dfc36610daa565b905f805160206146fb83398151915254916001600160401b0360ff8460401c1615931680159081610f04575b6001149081610efa575b159081610ef1575b50610edf575f805160206146fb833981519152805467ffffffffffffffff19166001179055610e6d9183610ebb576124c6565b610e7357005b5f805160206146fb833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b5f805160206146fb833981519152805460ff60401b1916600160401b1790556124c6565b60405163f92ee8a960e01b8152600490fd5b9050155f610e3a565b303b159150610e32565b849150610e28565b346102f057610f1a366108bd565b906001600160a01b039081831615610cf257610f346132f3565b817f000000000000000000000000000000000000000000000000000000000000000016803b156102f05760408051631d8557d760e01b815260049291905f81858183875af180156104ba57611338575b506001600160a01b0384165f90815261013760205260409020610fa690612351565b926001600160801b03610fc085516001600160801b031690565b161561132a57610fcf84612c58565b81516330fe427560e21b81529360a08583817f00000000000000000000000000000000000000000000000000000000000000008b165afa9384156104ba575f955f956112fc575b5083516303d1689d60e11b8082528482018c81529197602094939285908a90819083015b0381865afa9889156104ba575f996112dd575b506001600160a01b038a165f908152609c6020526040902061106e906106c3565b90818a1180156112cd575b6112bd576110b4908661109387516001600160801b031690565b8a51809481928883528c83019190916001600160801b036020820193169052565b0381885afa9182156104ba575f9261129c575b506110d29192612d5e565b1161128c578551633b9e9f0160e21b815233868201908152602081018e905290919085908390819060400103815f875af19182156104ba57859261126f575b5061111b8d612d08565b84516001600160801b0316906111309161238a565b6001600160801b031684526001600160a01b038a165f908152610137602052604090208461115d916123a3565b61116689613748565b976111708a612d08565b60985460801c036001600160801b031661119f906001600160801b036098549181199060801b16911617609855565b6111a9898c613f93565b6001600160a01b038b165f908152609c60205260409020546111ca906123d5565b906111d491612d5e565b935187519182526001600160801b0316868201908152909283918290036020019082905afa9283156104ba575f93611250575b505011611242575091610bf9917f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3959493610bcc838961369b565b9051631d8fa13d60e31b8152fd5b611267929350803d106104b3576104a4818361144b565b905f80611207565b61128590833d85116104b3576104a4818361144b565b505f611111565b855163324b20e160e11b81528590fd5b6110d292506112b790883d8a116104b3576104a4818361144b565b916110c7565b875163efda1a2760e01b81528790fd5b506112d6612447565b8a11611079565b6112f5919950853d87116104b3576104a4818361144b565b975f61104d565b61103a92965061131c91955060a03d60a011610cc257610cad818361144b565b505050959095949091611016565b905163673f032f60e11b8152fd5b80610ce66113459261141d565b5f610f84565b346102f0575f3660031901126102f0576065546040516001600160a01b039091168152602090f35b346102f05760203660031901126102f057600435611390816104e5565b60018060a01b03165f52610137602052602060405f20604051906113b3826113fd565b54906001600160801b03918281169081835260801c848301526113db575b5116604051908152f35b6113e481612c58565b6113d1565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761141857604052565b6113e9565b6001600160401b03811161141857604052565b606081019081106001600160401b0382111761141857604052565b90601f801991011681019081106001600160401b0382111761141857604052565b60405190611479826113fd565b565b6001600160401b03811161141857601f01601f191660200190565b9291926114a28261147b565b916114b0604051938461144b565b8294818452818301116102f0578281602093845f960137010152565b6040806003193601126102f05760049081356114e7816104e5565b6024356001600160401b0381116102f057366023820112156102f0576115169036906024818701359101611496565b9161151f613482565b8051926115568461154860209363439fab9160e01b858401528460248401526044830190611e52565b03601f19810186528561144b565b61155e613482565b611566613735565b6001600160a01b0383811680159291908790841561171d575b84156116af575b841561164b575b505082156115b5575b50506115a657610020838361410a565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ba575f9261161e575b5050155f80611596565b61163d9250803d10611644575b611635818361144b565b810190612618565b5f80611614565b503d61162b565b855163054fd4d560e41b81529294508391839182905afa9081156104ba5760029160ff915f91611682575b5016141591865f61158d565b6116a29150843d86116116a8575b61169a818361144b565b8101906140f1565b5f611676565b503d611690565b935050835163198ca60560e11b815282818981875afa9081156104ba5788917fd92dbcef7ed61a67c0eefa7cafcc41f41d9402a5046486977364b4724c821f8b915f91611700575b50141593611586565b6117179150853d87116104b3576104a4818361144b565b5f6116f7565b5f805160206146db83398151915254909450849061174b906001600160a01b03165b6001600160a01b031690565b149361157f565b346102f05760203660031901126102f0576004356001600160a01b036117766125ef565b1633036117ac578060d0555f60d155337fbe9758e2d6800505eeb0292a08fe647c52762ccea131177456e7062dd77b41065f80a3005b604051634ca8886760e01b8152600490fd5b346102f0575f3660031901126102f0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036118155760206040515f805160206146db8339815191528152f35b60405163703e46dd60e11b8152600490fd5b5f3660031901126102f0576001600160a01b03611842612476565b1633036117ac57005b346102f0575f3660031901126102f057602060405160018152f35b346102f0575f3660031901126102f0575f805160206146db833981519152546040516001600160a01b039091168152602090f35b346102f0575f3660031901126102f05760206104dd6125e1565b346102f0575f3660031901126102f0576020610d386125ef565b346102f05760203660031901126102f057609a80549081905f6004355b84821061191c5750505081101561191157610473905b6040519081529081906020820190565b506104735f19611901565b909193808316906001818518811c830180931161196e575f8790525f805160206146bb8339815191528301546001600160a01b0316841015611963575050935b91906118eb565b90959101925061195c565b612376565b346102f0575f3660031901126102f057604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104ba576020915f916119e3575b506040519015158152f35b6119fa9150823d841161164457611635818361144b565b5f6119d8565b346102f05760803660031901126102f057610473611a34600435611a23816104e5565b60643590604435906024359061263a565b604080519384526020840192909252908201529081906060820190565b346102f0576040806003193601126102f05760043560243591611a73836104e5565b611a7b614649565b8115611b64576001600160a01b0383168015611b5357611a9a836123d5565b928315611b4257611aa9612447565b8411611b3157611ae08461047396611ad1610b9d611ac684612d08565b60985460801c61238a565b611adb8433613f93565b61369b565b8251848152602081019190915233907f5cdf07ad0fc222442720b108e3ed4c4640f0fadc2ab2253e66f259a0fea834809080604081015b0390a3611b23336141b5565b519081529081906020820190565b82516396d8043360e01b8152600490fd5b82516318374fd160e21b8152600490fd5b815163d92e233d60e01b8152600490fd5b51636edcc52360e01b8152600490fd5b346102f0575f3660031901126102f057602061ffff60655460a01c16604051908152f35b346102f05760603660031901126102f057610473611a346044356024356004356126b4565b346102f0576040806003193601126102f0576004359060243590611be0826104e5565b611be86132d2565b8215611b64576001600160a01b0382168015611b535783611cc8611cac61047396611c2a611c1e6099546001600160801b031690565b6001600160801b031690565b81611c8a611c3f83611c3a6144f4565b6126a7565b89516001600160a01b03909b1660208c019081524260408d015260608c01829052909a611c7981608081015b03601f19810183528261144b565b5190205f52609b60205260405f2090565b55335f908152609c60205260409020611ca483825461262d565b905501612d08565b6001600160801b03166001600160801b03196099541617609955565b8251848152602081019190915233907f211091c5bf013c1230f996c3bb2bc327e3de429a3d3c356dcea9a0c858bc407f908060408101611b17565b346102f0575f3660031901126102f057602060d054604051908152f35b346102f0575f3660031901126102f057602060d154604051908152f35b346102f057611d8f7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611d6f36610daa565b9290611d79613735565b604051918291602083523395602084019161284b565b0390a2005b346102f05760203660031901126102f057600435611db1816104e5565b611db9613735565b6001600160a01b03168015610cf25760d280546001600160a01b03191682179055337fb710e1d0ebf395f895942ac4e559a4a86d57f748a90cf05e9d70798c67e9c65b5f80a3005b9181601f840112156102f0578235916001600160401b0383116102f0576020808501948460051b0101116102f057565b5f5b838110611e425750505f910152565b8181015183820152602001611e33565b90602091611e6b81518092818552858086019101611e31565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611eac5750505050505090565b9091929394958480611eca600193603f198682030187528a51611e52565b9801930193019194939290611e9c565b346102f05760203660031901126102f057600480356001600160401b0381116102f057611f0b903690600401611e01565b91611f1583612882565b925f5b818110611f2d57604051806104738782611e77565b5f80611f3a838588612911565b60409391611f4c855180938193612931565b0390305af490611f5a61293e565b9115611f81575090600191611f6f82886129d8565b52611f7a81876129d8565b5001611f18565b848260448151106102f057611fa58183611fba93015160248091830101910161296d565b925162461bcd60e51b81529283928301611fbe565b0390fd5b9060206108e6928181520190611e52565b346102f0575f3660031901126102f057610473604051611fee816113fd565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611e52565b346102f05760203660031901126102f05760206104dd600435613748565b346102f0575f3660031901126102f05760206001600160801b0360995416604051908152f35b346102f05760203660031901126102f057610020600435612078816104e5565b612080613735565b6137d7565b908160a09103126102f05790565b346102f05760803660031901126102f0576001600160401b036004358181116102f0576120c4903690600401612085565b6024358281116102f0576120dc903690600401611e01565b6044929192358481116102f0576120f7903690600401611e01565b916064359586116102f057612113610020963690600401611e01565b959094612ae8565b346102f05760203660031901126102f057600435612138816104e5565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102f0576040806003193601126102f0576004906001600160401b0382358181116102f0576121899036908501612085565b906024359081116102f0576121a19036908501611e01565b9390926121ac6132f3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102f0575f8251809263837d444160e01b82528183816121fb8a8a8301612a1d565b03925af180156104ba576122d3575b506801bc16d674ec80000061221d612447565b106122c6578083019360b061223286866128df565b9050036122b8576122846122889160d1549760d0549061227761226f8b6122598c8c6128df565b611c6b8b94929451938492602084019687612c1a565b519020612c37565b6020815191012092613acc565b1590565b6122ab576100206001866122a561229f88886128df565b90613b04565b0160d155565b516309bde33960e01b8152fd5b5051631a0a9b9f60e21b8152fd5b516396d8043360e01b8152fd5b80610ce66122e09261141d565b5f61220a565b346102f0575f3660031901126102f0575f546040516001600160a01b039091168152602090f35b60403660031901126102f05760206104dd60043561232a816104e5565b60243590610556826104e5565b908160209103126102f0575190565b6040513d5f823e3d90fd5b9060405161235e816113fd565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161196e57565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816123ed57505090565b916108e69260801c90612dd8565b61240490612f40565b908061241d575b5061241257565b61241a6131d5565b50565b612426906130d6565b5f61240b565b9190916001600160801b038080941691160191821161196e57565b4760995461245d6001600160801b0382166123d5565b9060801c01908181115f14612470570390565b50505f90565b61016a546001600160a01b0316801561248c5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102f057516108e6816104e5565b60405163e7f6f22560e01b8152602092908381600481335afa9081156104ba575f916125c4575b50604051636f4fa30f60e01b8152918483600481335afa9283156104ba575f93612595575b5083019380848603126102f05783356001600160401b03948582116102f05701936060858703126102f0576040519461254a86611430565b803586528281013561ffff811681036102f0578387015260408101359182116102f057019480601f870112156102f0578561258b9261147997359101611496565b60408401526133a5565b6125b6919350853d87116125bd575b6125ae818361144b565b8101906124b1565b915f612512565b503d6125a4565b6125db9150843d86116125bd576125ae818361144b565b5f6124ed565b609d54806108e657505f1990565b60d2546001600160a01b039081168061260957505f541690565b905090565b801515036102f057565b908160209103126102f057516108e68161260e565b9190820391821161196e57565b604080516001600160a01b03909216602083019081529082019390935260608101829052909261268a9290916126738160808101611c6b565b5190205f52609b60205260405f2054928391613500565b909182810390811161196e5792565b906001820180921161196e57565b9190820180921161196e57565b929190915f936126e47f0000000000000000000000000000000000000000000000000000000000000000856126a7565b42106128215760408051336020820190815291810186905260608082018490528152601f19916127259161271960808261144b565b5190209486843361263a565b90969095878781156128135750505f908152609b6020526040812055600182116127c9575b50505061278261276761275c85612d08565b60995460801c61238a565b6001600160801b036099549181199060801b16911617609955565b61278c833361369b565b6040805191825260208201869052810183905233907feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5690606090a2565b61280a919297506127da87856126a7565b60408051336020820190815291810193909352606083018290526080998a0183529098909190611c79908261144b565b555f808061274a565b959950975093955050505050565b604051631613b7eb60e01b8152600490fd5b90603060609281835260208301375f60508201520190565b908060209392818452848401375f828201840152601f01601f1916010190565b6001600160401b0381116114185760051b60200190565b9061288c8261286b565b612899604051918261144b565b82815280926128aa601f199161286b565b01905f5b8281106128ba57505050565b8060606020809385010152016128ae565b634e487b7160e01b5f52603260045260245ffd5b903590601e19813603018212156102f057018035906001600160401b0382116102f0576020019181360383136102f057565b9082101561292c576129289160051b8101906128df565b9091565b6128cb565b908092918237015f815290565b3d15612968573d9061294f8261147b565b9161295d604051938461144b565b82523d5f602084013e565b606090565b6020818303126102f0578051906001600160401b0382116102f0570181601f820112156102f057805161299f8161147b565b926129ad604051948561144b565b818452602082840101116102f0576108e69160208085019101611e31565b80511561292c5760200190565b805182101561292c5760209160051b010190565b9035601e19823603018112156102f05701602081359101916001600160401b0382116102f05781360383136102f057565b9060a06108e692602081528235602082015260208301356040820152612a59612a4960408501856129ec565b84606085015260c084019161284b565b90612a8c612a81612a6d60608701876129ec565b601f1985870381016080870152959161284b565b9460808101906129ec565b9390928286030191015261284b565b906801bc16d674ec800000918083029283040361196e57565b90670de0b6b3a76400009182810292818404149015171561196e57565b906127109182810292818404149015171561196e57565b929094939195612af66132f3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031695863b156102f0576040965f8851809263837d444160e01b8252818381612b4a8c60048301612a1d565b03925af180156104ba57612c07575b50612b62612447565b612b6b89612a9b565b11612bf65787158015612bdc575b612bcb5791612ba9959391612ba3896122849795612b9d60d054978c8101906128df565b90613947565b94613aba565b612bbb57506114799060d1540160d155565b516309bde33960e01b8152600490fd5b8651631c6c4cf360e31b8152600490fd5b50612be9878601866128df565b905060b089021415612b79565b86516396d8043360e01b8152600490fd5b80610ce6612c149261141d565b5f612b59565b939291602091612c329160408752604087019161284b565b930152565b9060405191602083015260208252611479826113fd565b61241a3433613c17565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ba575f91612ce9575b5060208201916001600160801b03918284511691828214612ce25783612cd56103ea612cdd958584865116612dd8565b169052612d08565b169052565b5050505050565b612d02915060203d6020116104b3576104a4818361144b565b5f612ca5565b6001600160801b0390818111612d1c571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b634e487b7160e01b5f52601260045260245ffd5b8115612d59570490565b612d3b565b90808202905f1981840990828083109203918083039214612dcd576127109082821115612dbb577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b9091828202915f1984820993838086109503948086039514612e4b5784831115612dbb57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906108e69250612d4f565b908160609103126102f057805191604060208301519201516108e68161260e565b81835290916001600160fb1b0383116102f05760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102f05760408301526040810135612ecc816104e5565b6001600160a01b031660608381019190915281013536829003601e19018112156102f05701602081359101906001600160401b0381116102f0578060051b360382136102f05760a0836080806108e69601520191612e79565b9190915f838201938412911290801582169115161761196e57565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612f6b9060048301612e9d565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ba575f915f905f95613091575b50841561303e5781612fb5612476565b16917f000000000000000000000000000000000000000000000000000000000000000016821461303757509060205f92600460405180958193634641257d60e01b83525af19081156104ba57613012925f92613016575b50612f25565b9190565b61303091925060203d6020116104b3576104a4818361144b565b905f61300c565b9081613044575b50509190565b803b156102f057604051636ee3193160e11b815260048101929092525f908290602490829084905af180156104ba5761307e575b8061303e565b80610ce661308b9261141d565b5f613078565b919450506130b7915060603d6060116130bf575b6130af818361144b565b810190612e58565b93905f612fa5565b503d6130a5565b600160ff1b811461196e575f0390565b6130e5611c1e60985460801c90565b5f82126131bc57816130f6916126a7565b90613103610b9d83612d08565b6131186065549161ffff8360a01c1690612d5e565b80156131b757807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613156611c1e6098546001600160801b031690565b806131a157505061319c90925b6001600160a01b0316916131778484613d8b565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a1565b61319c926131b192039084612dd8565b92613163565b505050565b6103ea610b9d916131cf611479946130c6565b9061262d565b609954906001600160801b0382169182156132cc5760801c6132096131fa824761262d565b613203856123d5565b90613dd7565b9081156132c55761321982613748565b9384156132bd57826132456127676103ea61147996610b9d96611c3a611cac6103ea8d611ac69a61262d565b61324f8187613e3d565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a16103ea6132a161329088612d08565b6098546001600160801b031661238a565b6001600160801b03166001600160801b03196098541617609855565b505f93505050565b505f925050565b505f9150565b6132da613f24565b156132e157565b604051630a62fbdb60e11b8152600490fd5b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ba575f9161335f575b5061334d57565b60405163e775715160e01b8152600490fd5b613378915060203d60201161164457611635818361144b565b5f613346565b908160a09103126102f0578051916020820151916040810151916080606083015192015190565b6133ad613fe0565b60408301516133ba613fe0565b5f80546001600160a01b0319166001600160a01b03841617905560405133917f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf919081906134089082611fbe565b0390a2602083015192613419613fe0565b61271061ffff851611613470576134689361343661345b936137d7565b6065805461ffff60a01b191660a09290921b61ffff60a01b169190911790555161400e565b61346361403e565b61405f565b61147961408e565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149182156134c0575b505061181557565b5f805160206146db8339815191525416141590505f806134b8565b906040516134e8816113fd565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613693575b6136865783613650575f5b609a5f526001600160a01b03166135455f805160206146bb83398151915286016134db565b805190979061355c906001600160a01b031661173f565b986135816135756020809b01516001600160601b031690565b6001600160601b031690565b948381108015613646575b6136345791600193979a956135ab6135b7939488035b838c0390613dd7565b80920198870391612dd8565b0197019380861180159061362a575b61361f57609a5f5282906135e85f805160206146bb83398151915287016134db565b805190890151969992966001600160a01b0390911694600193926135b79290916001600160601b03909116906135ab9088036135a2565b945050509250509190565b50818510156135c6565b60405163e8722f8f60e01b8152600490fd5b50808b111561358c565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613520565b505093505050505f905f90565b508415613515565b907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00916002835414613723576002835581471061370b575f918291829182916001600160a01b03165af16136ed61293e565b50156136f95760019055565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b5f546001600160a01b031633036117ac57565b609854906001600160801b03821681158015613777575b1561376a5750905090565b6108e69260801c91612dd8565b50801561375f565b6098546001600160801b03811690821580156137cf575b156137a057505090565b60801c906137af828285612dd8565b928215612d5957096137be5790565b60018101809111156108e657612376565b508115613796565b6137df6132f3565b6001600160a01b0316801561382757606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b906138438261286b565b613850604051918261144b565b8281528092613861601f199161286b565b0190602036910137565b906030116102f05790603090565b906090116102f05760300190606090565b9060b0116102f05760900190602090565b909392938483116102f05784116102f0578101920390565b901561292c5790565b919081101561292c5760051b0190565b3590602081106138da575090565b5f199060200360031b1b1690565b96959490612c3293613909613917926060979560808c5260808c019161284b565b9089820360208b0152611e52565b91878303604089015261284b565b9060206108e6928181520190612833565b9160206108e693818152019161284b565b9193929060d154925f925f9061395c81613839565b9761396561434e565b935f9760018060a01b037f000000000000000000000000000000000000000000000000000000000000000016945b848a106139a65750505050505050505050565b60b06139b691018099898561389b565b9960409a8d6139f28d516139da6020918281019061226f81611c6b8c8a8d87612c1a565b8051910120916139eb858b8b6138bc565b35906129d8565b526139fd818461386b565b9093613a1d613a17613a0f8584613879565b95909361388a565b906138cc565b908a3b156102f0578b8f5f93613a48915196879485946304512a2360e31b8652888c600488016138e8565b03816801bc16d674ec8000008d5af19384156104ba57613a9b60018e7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1958298613aa7575b5097019e5192839283613936565b0390a101989097613993565b80610ce6613ab49261141d565b5f613a8d565b90613ac8949593929161438f565b1490565b9192915f915b808310613ae0575050501490565b909192613afb600191613af48685876138bc565b359061460b565b93019190613ad2565b816030116102f057613a17917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613b4261434e565b90613b59613b508486613879565b9690948661388a565b94813b156102f0576801bc16d674ec8000005f94613bbf97604051988996879586946304512a2360e31b865260806004870152613bb0613b9d8d6084890190612833565b60031994858983030160248a0152611e52565b9286840301604487015261284b565b90606483015203925af19081156104ba577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb19261319c92613c08575b5060405191829182613925565b613c119061141d565b5f613bfb565b9190613c216132f3565b6001600160a01b038316908115610cf2578015613ccd5780613c48611c1e60985460801c90565b0193613c526125e1565b8511613cbb57610b9d94613c7991613c74613c6c8561377f565b978893612d08565b613d8b565b60408051918252602082018590525f9082015233907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9080606081015b0390a3565b6040516304ffa0ff60e51b8152600490fd5b6040516318374fd160e21b8152600490fd5b90929192613ceb6132f3565b6001600160a01b038216918215610cf2578115613ccd5781613d12611c1e60985460801c90565b01613d1b6125e1565b8111613cbb57610b9d95613d62613cb6927f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94613c74613d5a8861377f565b9a8b93612d08565b60408051948552602085018890526001600160a01b039091169084015233929081906060820190565b613d9482612d08565b60985490613dac6001600160801b039182841661242c565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b9080821015612609575090565b609a5490600160401b821015611418576001820180609a5582101561292c57609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f805160206146bb83398151915290910155565b9081158015613f1c575b613f0a57609a5480613ed457505f905b6001600160a01b0391821692830192831061196e57818311613eb4576114799291613e9f613e87613eaf93614536565b91613e9061146c565b94166001600160a01b03168452565b6001600160601b03166020830152565b613de4565b6040516306dfcc6560e41b815260a0600482015260248101849052604490fd5b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031690613e57565b604051632ec8835b60e21b8152600490fd5b508015613e47565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ba575f91613f7a575090565b6108e6915060203d60201161164457611635818361144b565b60018060a01b03165f52609c60205260405f2090815481810390811161196e57613fbd9255612d08565b609854906001600160801b03908183160316906001600160801b03191617609855565b60ff5f805160206146fb8339815191525460401c1615613ffc57565b604051631afcd79f60e31b8152600490fd5b614016613fe0565b801561402c57600181016140275750565b609d55565b6040516331278a8760e01b8152600490fd5b614046613fe0565b6801bc16d674ec8000006140586125e1565b1061402c57565b614067613fe0565b6001600160a01b0316806140785750565b61016a80546001600160a01b0319169091179055565b614096613fe0565b61409e613fe0565b6140a6613fe0565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055633b9aca0034106140df5761241a3430613c17565b60405163ea2559bb60e01b8152600490fd5b908160209103126102f0575160ff811681036102f05790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614194575b5061415a57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206146db833981519152840361417b57611479929350614569565b604051632a87526960e21b815260048101859052602490fd5b6141ae91955060203d6020116104b3576104a4818361144b565b935f614134565b6001600160a01b0381165f908152610137602052604090206141d690612351565b906001600160801b036141f083516001600160801b031690565b161561434a576106c3614227916142056132f3565b61420e84612c58565b6001600160a01b03165f908152609c6020526040902090565b604051631331885160e31b8152602092916001600160a01b0384836004817f000000000000000000000000000000000000000000000000000000000000000085165afa9182156104ba5761428a8693614298926142c4965f926143325750612d5e565b94516001600160801b031690565b6040516303d1689d60e11b81526001600160801b03909116600482015292839190829081906024820190565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9283156104ba575f93614313575b50501061430157565b604051633684c65960e01b8152600490fd5b61432a929350803d106104b3576104a4818361144b565b905f806142f8565b610835919250863d88116104b3576104a4818361144b565b5050565b604051600160f81b60208201525f60218201523060601b602c820152602081526108e6816113fd565b5f19811461196e5760010190565b356108e68161260e565b92939190918051936143a184866126a7565b6143aa87612699565b036143ec576143b886613839565b945f8094885f965f5b8281106144245750501591506143fe905057505050036143ec576143e8915f1901906129d8565b5190565b604051631a8a024960e11b8152600490fd5b9195509293501590506144165750506143e8906129cb565b61442092506138b3565b3590565b8a868610156144d757506144566144518261444861444189614377565b988c6129d8565b51955b876138bc565b614385565b156144bc578a8686101561449b57506144876001929361447f61447888614377565b978b6129d8565b515b9061460b565b614491828d6129d8565b5201908a916143c1565b92614487906144b6846144b060019691614377565b966129d8565b51614481565b61448760019293613af46144cf8c614377565b9b8d8b6138bc565b91614451826144ed836144b06144569591614377565b519561444b565b609a548061450157505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661173f565b6001600160601b039081811161454a571690565b604490604051906306dfcc6560e41b8252606060048301526024820152fd5b90813b156145ea575f805160206146db83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156145cf5761241a9161462c565b5050346145d857565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b8181101561461f575f5260205260405f2090565b905f5260205260405f2090565b5f806108e693602081519101845af461464361293e565b91614669565b614651613f24565b61465757565b6040516389a1dc6360e01b8152600490fd5b9061467e57508051156136f957805190602001fd5b815115806146b1575b61468f575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561468756fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a2646970667358221220575227d2ab6f6dc09c808397834f8b2864f1374a42b4bf85b19f335a03976c6764736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoBlocklistErc20Vault.json b/test/shared/artifacts/GnoBlocklistErc20Vault.json deleted file mode 100644 index 4c55c81c..00000000 --- a/test/shared/artifacts/GnoBlocklistErc20Vault.json +++ /dev/null @@ -1,1943 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoBlocklistErc20Vault", - "sourceName": "contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x610220346200023a5762005fee38819003601f8101601f191683016001600160401b038111848210176200023e57839282916040528339610140928391810103126200023a57620000508162000252565b916200005f6020830162000252565b906200006e6040840162000252565b936200007d6060850162000252565b6200008b6080860162000252565b906200009a60a0870162000252565b92620000a960c0880162000252565b94620000b860e0890162000252565b9561010099620000ca8b8b0162000252565b98610120809b01519460805260a05260c0523060e052620000ea62000267565b468a52885246815261016091825260018060a01b038061018094168452806101a0951685526101c09586526101e0961686526102009687526200012c62000267565b60405197615ce7998a620003078b396080518a8181611ae201528181611cb6015281816135a6015281816142dd0152614cb1015260a0518a61181e015260c0518a8181613d4a0152818161467b015281816148970152615484015260e0518a818161199e0152613fbd01525189612a25015251886131380152518761435301525186611e5c0152518581816104130152818161096f01528181610c6b01528181613207015281816139d80152614dc1015251848181610d2a0152818161152d01528181613a970152614d45015251838181612a0001526135ee01525182818161114401528181613cf9015281816146e5015281816148e101528181614a2501526151fa015251816130590152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200023a57565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620002f4576001600160401b036002600160401b031982821601620002b557505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d1141461037f578063066055e01461037a57806306fdde031461037557806307a2d13a14610370578063095ea7b31461036b57806314c4184b1461036657806318160ddd1461032f5780631a7ff55314610361578063201b9eb51461035c57806323b872dd146103575780632999ad3f146103525780632cdf74011461034d5780632e2d298414610348578063313ce567146103435780633229fa951461033e57806333194c0a146103395780633644e515146103345780633a98ef391461032f578063439fab911461032a57806343e82a791461032557806346904840146103205780634ec96b221461031b5780634f1ef2861461031657806352d1902d1461031157806354fd4d501461030c5780635c60da1b146103075780635cfc1a511461030257806360d60e6e146102fd57806370a082311461028557806372b410a8146102f8578063754c3888146102f357806376b58b90146102ee5780637ecebe00146102e95780637fd6f15c146102e457806383d430d5146102df5780638697d2c2146102da5780638ceab9aa146102d557806395d89b41146102d0578063a49a1e7d146102cb578063a9059cbb146102c6578063ac9650d8146102c1578063ad3cb1cc146102bc578063b0d11302146102b7578063b1f0e7c7146102b2578063b45a1eb5146102ad578063c6e6f592146102a8578063d0a64ddc146102a3578063d505accf1461029e578063d83ad00c14610299578063dd62ed3e14610294578063e74b981b1461028f578063ee3bd5df1461028a578063f04da65b14610285578063f45bf3d2146102805763f851a4400361000e576128c7565b612886565b611a7c565b612860565b612833565b6127d4565b6127ae565b612599565b612561565b612543565b612511565b6124ed565b6124ba565b612475565b612410565b61236f565b61231d565b612279565b612090565b611e30565b611c60565b611c3c565b611c01565b611bb0565b611b44565b611ab7565b611a5e565b611a44565b611a10565b6119f5565b61198c565b611706565b611623565b6115fb565b6114fe565b61135b565b61085f565b6112e6565b6112ac565b611280565b611265565b6110e5565b6110cb565b610c41565b610b65565b6108fd565b610885565b610836565b610794565b61075d565b610697565b6103c3565b610392565b5f91031261038e57565b5f80fd5b3461038e575f36600319011261038e57602060cf5460801c604051908152f35b6001600160801b0381160361038e57565b3461038e57602036600319011261038e576004356103e0816103b2565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610562575f91610533575b50335f90815261016e6020526040902061045c90612909565b916001600160801b0361047684516001600160801b031690565b1615610521576104ca8361048c61051d956131f2565b6104b66104a9846104a484516001600160801b031690565b612942565b6001600160801b03168252565b335f90815261016e6020526040902061295b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610555915060203d60201161055b575b61054d818361061c565b8101906128ef565b5f610443565b503d610543565b6128fe565b90600182811c92168015610595575b602083101461058157565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610576565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176105ce57604052565b61059f565b6001600160401b0381116105ce57604052565b60a081019081106001600160401b038211176105ce57604052565b608081019081106001600160401b038211176105ce57604052565b90601f801991011681019081106001600160401b038211176105ce57604052565b5f5b83811061064e5750505f910152565b818101518382015260200161063f565b906020916106778151809281855285808601910161063d565b601f01601f1916010190565b90602061069492818152019061065e565b90565b3461038e575f36600319011261038e576040515f80546106b681610567565b8084529060209060019081811690811561073357506001146106ef575b61051d856106e38187038261061c565b60405191829182610683565b5f80805293505f80516020615c128339815191525b838510610720575050505081016020016106e38261051d6106d3565b8054868601840152938201938101610704565b86955061051d969350602092506106e394915060ff191682840152151560051b82010192936106d3565b3461038e57602036600319011261038e57602061077b600435612984565b604051908152f35b6001600160a01b0381160361038e57565b3461038e57604036600319011261038e576004356107b181610783565b6001600160a01b03811690602435908215610824576107ec8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b3461038e575f36600319011261038e5761026a546040516001600160a01b039091168152602090f35b3461038e575f36600319011261038e5760206001600160801b0360cf5416604051908152f35b3461038e5760031960203682011261038e57600435906001600160401b03821161038e57608090823603011261038e576108c46108cb91600401613575565b919061370b565b6108d157005b6108d9615578565b806108e057005b5f906040519081525f80516020615c5283398151915260203092a3005b3461038e57606036600319011261038e5760043561091a81610783565b602435906044359061092b82610783565b61093433613890565b61093c614c96565b6109446142c2565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af1948515610562575f95610b46575b50335f90815261016e602052604090206109bf90612909565b926001600160801b036109d985516001600160801b031690565b1615610ae25750506109ea826131f2565b610a16610a096109f9876149d4565b84516001600160801b03166138b1565b6001600160801b03168352565b335f90815260d360205260409020610a3890610a33905b54612984565b614d22565b610a58610a4c84516001600160801b031690565b6001600160801b031690565b11610ad057335f90815261016e6020526040902061051d957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610a9e919061295b565b604080516001600160a01b0395861681526020810187905290810191909152921660608301523391806080810161050a565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561056257610b2492610b15915f91610b29575b506149d4565b6001600160801b031690840152565b6109ea565b610b409150833d851161055b5761054d818361061c565b5f610b0f565b610b5e919550833d851161055b5761054d818361061c565b935f6109a6565b3461038e57606036600319011261038e57600435610b8281610783565b60243590610b8f82610783565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610bdf575b610bd384610bce858883614e2c565b6138cc565b60405160018152602090f35b919093818503948511610c13575f928352600260209081526040808520338652909152909220939093559180610bd3610bbf565b61292e565b606090600319011261038e5760043590602435610c3481610783565b9060443561069481610783565b3461038e57610c4f36610c18565b906001600160a01b038083161561082457610c686142c2565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561038e5760408051631d8557d760e01b815260049491905f81878183875af18015610562576110b2575b506001600160a01b0383165f90815261016e60205260409020610cdb90612909565b6001600160801b039283610cf683516001600160801b031690565b16156110a257610d05826131f2565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610562575f98611071575b50602097888101956001600160401b03918280610d7e8a516001600160401b031690565b161461106157908c92918751918c8380610daa6303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561056257610dd6938e5f9461103c575b5050516001600160801b03165b1690613321565b96610df4610a2d8a60018060a01b03165f5260d360205260405f2090565b92838911801561102c575b61101c57908b610e3d9392610e1b89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561056257670de0b6b3a764000094610e8c948e5f95610fef575b5050610e7e610e70610e8492612e2e565b93516001600160401b031690565b93612e2e565b92169061341a565b1015610fe1578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610562577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610fbe95610f3693610fc3575b5050610f196104a9610f098c6149d4565b83516001600160801b0316612942565b6001600160a01b0386165f90815261016e6020526040902061295b565b610f3f82614b20565b90610f7d610f62610f4f856149d4565b60cf5460801c036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610f8782866156a8565b610f918389614a07565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610fd992903d1061055b5761054d818361061c565b505f80610ef8565b835163185cfc6d60e11b8152fd5b610e84929550611012610e7e9282610e7093903d1061055b5761054d818361061c565b959250508e610e5f565b875163efda1a2760e01b81528590fd5b506110356129aa565b8911610dff565b610dcf929450908161105992903d1061055b5761054d818361061c565b92908e610dc2565b8651630709133160e01b81528490fd5b61109491985060603d60601161109b575b61108c818361061c565b810190613960565b965f610d5a565b503d611082565b825163673f032f60e11b81528790fd5b806110bf6110c5926105d3565b80610384565b5f610cb9565b3461038e575f36600319011261038e57602061077b6129aa565b3461038e576110f336610c18565b916110fd33613890565b61110682613890565b61110e614af1565b60409261116884516323b872dd60e01b602082015233602482015230604482015283606482015260648152611142816105e6565b7f0000000000000000000000000000000000000000000000000000000000000000615713565b6111706142c2565b6001600160a01b0383169283156112545782156112435782611197610a4c60cf5460801c90565b01906111a1612b35565b821161123257611218610f6295936111f286947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c946111ed6111e560209c9a614ba6565b9a8b936149d4565b615510565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020615c928339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b3461038e575f36600319011261038e57602060405160128152f35b3461038e575f36600319011261038e57602061129a6129e7565b6040516001600160a01b039091168152f35b3461038e575f36600319011261038e5760206040517fc77e768dab534fa678edc458b42a344df0e260a0905ed4b4c3727a271a465cd08152f35b3461038e575f36600319011261038e57602061077b612a22565b9181601f8401121561038e578235916001600160401b03831161038e576020838186019501011161038e57565b602060031982011261038e57600435906001600160401b03821161038e5761135791600401611300565b9091565b3461038e576113693661132d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1680156114ea575b6114d85768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa928315610562575f936114b9575b50604051636f4fa30f60e01b8152938285600481335afa9081156105625761142695611421945f93611486575b505061141a9192810190612a96565b9083613ee7565b613fa7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b61141a935090816114ab92903d106114b2575b6114a3818361061c565b810190612a57565b915f61140b565b503d611499565b6114d1919350823d84116114b2576114a3818361061c565b915f6113de565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101561139a565b3461038e5761150c36610c18565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105625782915f916115dc575b501633036115ca5781610fbe61159786867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966139ba565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6115f5915060203d6020116114b2576114a3818361061c565b5f61155f565b3461038e575f36600319011261038e57609c546040516001600160a01b039091168152602090f35b3461038e57602036600319011261038e5760043561164081610783565b60018060a01b03165f5261016e602052602060405f2060405190611663826105b3565b54906001600160801b03918281169081835260801c8483015261168b575b5116604051908152f35b611694816131f2565b611681565b604051906116a6826105e6565b565b604051906116a6826105b3565b6001600160401b0381116105ce57601f01601f191660200190565b9291926116dc826116b5565b916116ea604051938461061c565b82948184528183011161038e578281602093845f960137010152565b60408060031936011261038e57600490813561172181610783565b6024356001600160401b03811161038e573660238201121561038e5761175090369060248187013591016116d0565b91611759613fb3565b8051926117908461178260209363439fab9160e01b85840152846024840152604483019061065e565b03601f19810186528561061c565b611798613fb3565b6117a0614093565b6001600160a01b03838116801592919087908415611957575b84156118e9575b8415611885575b505082156117ef575b50506117e0576100188383615245565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610562575f92611858575b5050155f806117d0565b6118779250803d1061187e575b61186f818361061c565b810190612c1d565b5f8061184e565b503d611865565b855163054fd4d560e41b81529294508391839182905afa9081156105625760039160ff915f916118bc575b5016141591865f6117c7565b6118dc9150843d86116118e2575b6118d4818361061c565b810190615230565b5f6118b0565b503d6118ca565b935050835163198ca60560e11b815282818981875afa9081156105625788917fc77e768dab534fa678edc458b42a344df0e260a0905ed4b4c3727a271a465cd0915f9161193a575b501415936117c0565b6119519150853d871161055b5761054d818361061c565b5f611931565b5f80516020615c32833981519152549094508490611985906001600160a01b03165b6001600160a01b031690565b14936117b9565b3461038e575f36600319011261038e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036119e35760206040515f80516020615c328339815191528152f35b60405163703e46dd60e11b8152600490fd5b3461038e575f36600319011261038e57602060405160028152f35b3461038e575f36600319011261038e575f80516020615c32833981519152546040516001600160a01b039091168152602090f35b3461038e575f36600319011261038e57602061077b612b35565b3461038e57602036600319011261038e57602061077b600435612b5e565b3461038e57602036600319011261038e57600435611a9981610783565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461038e575f36600319011261038e57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610562576020915f91611b27575b506040519015158152f35b611b3e9150823d841161187e5761186f818361061c565b5f611b1c565b3461038e57602036600319011261038e57600435611b6181610783565b611b69614093565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461038e57608036600319011261038e5761051d611be4600435611bd381610783565b606435906044359060243590612c3f565b604080519384526020840192909252908201529081906060820190565b3461038e57602036600319011261038e57600435611c1e81610783565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461038e575f36600319011261038e57602061ffff609c5460a01c16604051908152f35b3461038e5760031960403682011261038e5760049081356001600160401b0380821161038e5760a082850193833603011261038e5760243590811161038e57611cac9036908501611300565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561038e5760405163837d444160e01b8152905f908290818381611cff8c828f01612d43565b03925af1801561056257611e1d575b50611d176142c2565b611d1f613123565b9081163314159182611dee575b50509050611ddd576044019160b0611d448484612dc1565b90500480158015611dc5575b611db557611d65611d5f6129aa565b91612e16565b11611da6575060b0611d778383612dc1565b9050145f14611d935761001891611d8d91612dc1565b90614875565b61001891611da091612dc1565b90614645565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611dd08484612dc1565b905060b082021415611d50565b604051634ca8886760e01b81528390fd5b611e119250611e0b611e1594611e038861434d565b9236916116d0565b91614428565b1590565b805f80611d2c565b806110bf611e2a926105d3565b5f611d0e565b3461038e57606036600319011261038e57600435602435611e55604435828433612c3f565b9192611e817f000000000000000000000000000000000000000000000000000000000000000082612b51565b42108015612088575b8015612080575b61206e577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611ed586611ed0610a4c60d0546001600160801b031690565b61400c565b15611fdc57611f0f611ef4611ee9866149d4565b60d05460801c612942565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611f539190611f4260808261061c565b5190205f5260d260205260405f2090565b555f9360018311611f8c575b50505050611f6d8233614a07565b604080519485526020850191909152830152339180606081015b0390a2005b611fd292939450611f9d9088612b51565b60408051336020820190815291810193909352606083018290529094909190611f429082608081015b0390810183528261061c565b555f808080611f5f565b611fe46142c2565b612020612004611ff3866149d4565b60d5546001600160801b0316612942565b6001600160801b03166001600160801b031960d554161760d555565b61205561203a61202f856149d4565b60d55460801c612942565b6001600160801b0360d5549181199060801b1691161760d555565b6120696120648460d654612b51565b60d655565b611f0f565b604051630e3d8e8d60e11b8152600490fd5b508215611e91565b508115611e8a565b3461038e5760408060031936011261038e57602435906004356120b283610783565b6120ba6142c2565b8015612268576001600160a01b038316908115612257576120da81612984565b908115612246576120ea82615344565b6120f3836149d4565b60cf5460801c9061210391612942565b612122906001600160801b0360cf549181199060801b1691161760cf55565b61212c82336156a8565b60d554958660801c828160d6549061214391612b51565b9861214d876149d4565b61215f916001600160801b03166138b1565b61217f906001600160801b03166001600160801b031960d554161760d555565b61218891612b51565b612191906149d4565b6121b0906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906121e160808261061c565b5190206121f6905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a361223d336138cc565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461038e575f36600319011261038e576040515f6001805461229a81610567565b808552916020916001811690811561073357506001146122c45761051d856106e38187038261061c565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851061230a575050505081016020016106e38261051d6106d3565b80548686018401529382019381016122ee565b3461038e57611f877f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61234f3661132d565b9290612359614093565b6040519182916020835233956020840191612d23565b3461038e57604036600319011261038e5761239960043561238f81610783565b6024359033614e2c565b6123a2336138cc565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106123e25750505050505090565b9091929394958480612400600193603f198682030187528a5161065e565b98019301930191949392906123d2565b3461038e57602036600319011261038e576001600160401b0360043581811161038e573660238201121561038e57806004013591821161038e573660248360051b8301011161038e5761051d9160246124699201612f89565b604051918291826123ad565b3461038e575f36600319011261038e5761051d604051612494816105b3565b60058152640352e302e360dc1b602082015260405191829160208352602083019061065e565b3461038e575f36600319011261038e576124d2614af1565b6124da613036565b60015f80516020615c9283398151915255005b3461038e575f36600319011261038e57602061129a613123565b8015150361038e57565b3461038e57604036600319011261038e5761001860043561253181610783565b6024359061253e82612507565b61315a565b3461038e57602036600319011261038e57602061077b600435614b20565b3461038e57602036600319011261038e5761001860043561258181610783565b612589614093565b614bed565b60ff81160361038e57565b3461038e5760e036600319011261038e576004356125b681610783565b6024356125c281610783565b6044359060643592608435906125d78261258e565b6001600160a01b038381169590929086156108245742811061279c576020915f91611fc66126ca89878a61268d61260c612a22565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b03916126a1601f199384810183528261061c565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610562575f5192828416801590811561278f575b5061277d5761276a85916127557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610fbe565b6040516323389ba560e21b8152600490fd5b905083831614155f612710565b604051631ab7da6b60e01b8152600490fd5b3461038e575f36600319011261038e5760206001600160801b0360d05416604051908152f35b3461038e57604036600319011261038e57602061282a6004356127f681610783565b6024359061280382610783565b60018060a01b03165f526002835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461038e57602036600319011261038e5761001860043561285381610783565b61285b614093565b614c34565b3461038e575f36600319011261038e5760206001600160801b0360d55416604051908152f35b3461038e57602036600319011261038e576004356128a381610783565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b3461038e575f36600319011261038e576037546040516001600160a01b039091168152602090f35b9081602091031261038e575190565b6040513d5f823e3d90fd5b90604051612916816105b3565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039182169082160391908211610c1357565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161299c57505090565b916106949260801c9061341a565b6129b2613cd3565b60d0546001600160801b036129c8818316612984565b9060d55416019060801c01908181115f146129e1570390565b50505f90565b6101a1546001600160a01b031680156129fd5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003612a4f5760045490565b610694613dc1565b9081602091031261038e575161069481610783565b359061ffff8216820361038e57565b9080601f8301121561038e57816020610694933591016116d0565b9060208282031261038e5781356001600160401b039283821161038e57019060a08282031261038e57612ac7611699565b9282358452612ad860208401612a6c565b6020850152604083013581811161038e5782612af5918501612a7b565b6040850152606083013581811161038e5782612b12918501612a7b565b6060850152608083013590811161038e57612b2d9201612a7b565b608082015290565b60d4548061069457505f1990565b9060b08201809211610c1357565b91908201809211610c1357565b6001600160801b0360d05416612b726152f0565b908101809111610c13578110612ba557612b9660d654612b90614023565b90612b51565b1115612ba0575f90565b5f1990565b60d19060d1549182915f905b848210612bcb57505050811015612bc55790565b505f1990565b909193808316906001818518811c8301809311610c13575f8790525f80516020615c728339815191528301546001600160a01b0316841015612c12575050935b9190612bb1565b909591019250612c0b565b9081602091031261038e575161069481612507565b91908203918211610c1357565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612c7d81608081015b03601f19810183528261061c565b5190205f5260d260205260405f2054918215612ce7576001600160801b0360d0541690612ca86152f0565b918201809211610c13578391831015612cd55791612cc592614127565b90915b828103908111610c135792565b5090612ce0916140a7565b9091612cc8565b5050505f905f905f90565b9035601e198236030181121561038e5701602081359101916001600160401b03821161038e57813603831361038e57565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061069492602081528235602082015260208301356040820152612d7f612d6f6040850185612cf2565b84606085015260c0840191612d23565b90612db2612da7612d936060870187612cf2565b601f19858703810160808701529591612d23565b946080810190612cf2565b93909282860301910152612d23565b903590601e198136030182121561038e57018035906001600160401b03821161038e5760200191813603831361038e57565b634e487b7160e01b5f52601260045260245ffd5b8115612e11570490565b612df3565b90670de0b6b3a76400009180830292830403610c1357565b90670de0b6b3a764000091828102928184041490151715610c1357565b6001600160401b0381116105ce5760051b60200190565b90612e6c82612e4b565b612e79604051918261061c565b8281528092612e8a601f1991612e4b565b01905f5b828110612e9a57505050565b806060602080938501015201612e8e565b634e487b7160e01b5f52603260045260245ffd5b90821015612ed6576113579160051b810190612dc1565b612eab565b908092918237015f815290565b3d15612f12573d90612ef9826116b5565b91612f07604051938461061c565b82523d5f602084013e565b606090565b60208183031261038e578051906001600160401b03821161038e570181601f8201121561038e578051612f49816116b5565b92612f57604051948561061c565b8184526020828401011161038e57610694916020808501910161063d565b8051821015612ed65760209160051b010190565b919091612f9583612e62565b925f5b818110612fa457505050565b5f80612fb1838587612ebf565b60409391612fc3855180938193612edb565b0390305af490612fd1612ee8565b9115612ff8575090600191612fe68288612f75565b52612ff18187612f75565b5001612f98565b90604481511061038e5761303261301d60049283810151602480918301019101612f17565b925162461bcd60e51b81529283928301610683565b0390fd5b47633b9aca00811061312057604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610562575f926130ff575b506001600160ff1b0382116130e657907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db916130cc8261370b565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b61311991925060203d60201161055b5761054d818361061c565b905f613091565b50565b610109546001600160a01b03168061069457507f000000000000000000000000000000000000000000000000000000000000000090565b61026a546001600160a01b039190821633036115ca576001600160a01b0381165f90815261026b60205260409020549215159260ff16151583146131ed576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91613288575b5060208201916001600160801b03918284511691828214613281578361327461326f61327c95858486511661341a565b6149d4565b1690526149d4565b169052565b5050505050565b6132a1915060203d60201161055b5761054d818361061c565b5f61323f565b90808202905f1981840990828083109203918083039214613316576127109082821115613304577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461338457670de0b6b3a76400009082821115613304577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106949250612e07565b9091828202915f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b9081606091031261038e578051916040602083015192015161069481612507565b81835290916001600160fb1b03831161038e5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361038e576040830152604081013561350181610783565b6001600160a01b031660608381019190915281013536829003601e190181121561038e5701602081359101906001600160401b03811161038e578060051b3603821361038e5760a08360808061069496015201916134ae565b9190915f8382019384129112908015821691151617610c1357565b6040516325f56f1160e01b81526001600160a01b039291606090829081906135a090600483016134d2565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610562575f915f905f956136c6575b50841561367357816135ea6129e7565b16917f000000000000000000000000000000000000000000000000000000000000000016821461366c57509060205f92600460405180958193634641257d60e01b83525af190811561056257613647925f9261364b575b5061355a565b9190565b61366591925060203d60201161055b5761054d818361061c565b905f613641565b9081613679575b50509190565b803b1561038e57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015610562576136b3575b80613673565b806110bf6136c0926105d3565b5f6136ad565b919450506136ec915060603d6060116136f4575b6136e4818361061c565b81019061348d565b93905f6135da565b503d6136da565b600160ff1b8114610c13575f0390565b801561312057613720610a4c60cf5460801c90565b5f82126137ed578161373191612b51565b9061373e610f62836149d4565b613753609c549161ffff8360a01c16906132a7565b80156131ed57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613791610a4c60cf546001600160801b031690565b806137d75750506130e190925b6001600160a01b0316916137b28484615510565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b6130e1926137e79203908461341a565b9261379e565b906137f7906136fb565b61380c610a4c60d5546001600160801b031690565b8061382c575b508061381c575050565b61326f610f62916116a693612c32565b906138877f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161387761200461386c6138658888612b51565b878561341a565b8080940396036149d4565b6040519081529081906020820190565b0390a15f613812565b6001600160a01b03165f90815261026b602052604090205460ff166115ca57565b9190916001600160801b0380809416911601918211610c1357565b60018060a01b0381165f5261016e60205260405f2090604051916138ef836105b3565b54906001600160801b03918281169081855260801c6020850152156131ed57610a33610a2d613942926139206142c2565b613929866131f2565b6001600160a01b03165f90815260d36020526040902090565b91511611610ad057565b51906001600160401b038216820361038e57565b9081606091031261038e5760405190606082018281106001600160401b038211176105ce576139b29160409182528051613999816103b2565b84526139a76020820161394c565b60208501520161394c565b604082015290565b92906001600160a01b039081811615610824576139d56142c2565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561038e57604094855193631d8557d760e01b85526004945f81878183895af1801561056257613cc0575b506001600160a01b0388165f90815261016e60205260409020613a4890612909565b906001600160801b03613a6283516001600160801b031690565b1615613cb057613a71826131f2565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561056257613c91575b508651936303d1689d60e11b97888652602091828780613aeb888c83019190602083019252565b0381845afa968715610562575f97613c72575b508699613b1e610a2d8d60018060a01b03165f5260d360205260405f2090565b88118015613c62575b613c52579083613b6492613b4287516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610562575f85948894613ba99c613c35575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561056257610f09613bf094613bd3936104a9936116a69a613c17575b50506149d4565b6001600160a01b0388165f90815261016e6020526040902061295b565b613c12613bfc83614b20565b8097613c0d610f62610f4f876149d4565b6156a8565b614a07565b81613c2d92903d1061055b5761054d818361061c565b505f80613bcc565b613c4b90873d891161055b5761054d818361061c565b505f613b7e565b825163efda1a2760e01b81528990fd5b50613c6b6129aa565b8811613b27565b613c8a919750833d851161055b5761054d818361061c565b955f613afe565b613ca99060603d60601161109b5761108c818361061c565b505f613ac4565b875163673f032f60e11b81528690fd5b806110bf613ccd926105d3565b5f613a26565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610562575f91613da4575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561056257610694935f93613d85575b5050612b51565b613d9c929350803d1061055b5761054d818361061c565b905f80613d7e565b613dbb9150833d851161055b5761054d818361061c565b5f613d2a565b6040515f905f5490613dd282610567565b9283825260209384830193600190866001821691825f14613ec7575050600114613e84575b50509181613e0d613e7e93612c6f95038261061c565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020615c128339815191525b828410613eb25750505082010181613e0d613df7565b80548685018601528794909301928101613e9c565b60ff1916875292151560051b85019092019250839150613e0d9050613df7565b9190613ef1614f00565b608082015190613eff614f00565b6001600160a01b038416801561082457613f9f94613f8f93613f78926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613f663394602083019061065e565b0390a2602085015161ffff1690614f41565b613f828351614f92565b613f8a614fc2565b614fee565b606060408201519101519061501d565b6116a661514a565b6116a690612589614f00565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613ff1575b50506119e357565b5f80516020615c328339815191525416141590505f80613fe9565b906140156152f0565b918201809211610c13571090565b61402b613cd3565b60d0548060801c8203918211610c13578161404f6001600160801b03809316612984565b9081614075575b505081156129e157610694916140709160d5541690615332565b615344565b919250908181111561408b57035b905f80614056565b50505f614083565b6037546001600160a01b031633036115ca57565b6140af614023565b9160d654928301809311610c1357808311156140f9576140d0920390615332565b9060d5548060801c80155f146140e65750508190565b6001600160801b0361069492168461341a565b5050505f905f90565b9060405161410f816105b3565b91546001600160a01b038116835260a01c6020830152565b60d1545f9485949390918084108015906142ba575b6142ad5783614277575f5b60d15f526001600160a01b031661416c5f80516020615c728339815191528601614102565b8051909790614183906001600160a01b0316611979565b986141a861419c6020809b01516001600160601b031690565b6001600160601b031690565b94838110801561426d575b61425b5791600193979a956141d26141de939488035b838c0390615332565b8092019887039161341a565b01970193808611801590614251575b6142465760d15f52829061420f5f80516020615c728339815191528701614102565b805190890151969992966001600160a01b0390911694600193926141de9290916001600160601b03909116906141d29088036141c9565b945050509250509190565b50818510156141ed565b60405163e8722f8f60e01b8152600490fd5b50808b11156141b3565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316614147565b505093505050505f905f90565b50841561413c565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f9161432e575b5061431c57565b60405163e775715160e01b8152600490fd5b614347915060203d60201161187e5761186f818361061c565b5f614315565b604290467f0000000000000000000000000000000000000000000000000000000000000000036143fc5761010a54905b61439461438d6040830183612dc1565b36916116d0565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526143df81610601565b5190206040519161190160f01b8352600283015260228201522090565b61440461537b565b9061437d565b6004111561441457565b634e487b7160e01b5f52602160045260245ffd5b6144328383615448565b5061443f8195929561440a565b1593846144db575b508315614455575b50505090565b5f92935090829160405161448d81612c6f6020820194630b135d3f60e11b998a8752602484015260406044840152606483019061065e565b51915afa9061449a612ee8565b826144cd575b826144b0575b50505f808061444f565b6144c5919250602080825183010191016128ef565b145f806144a6565b9150602082511015916144a0565b6001600160a01b0383811691161493505f614447565b906144fb82612e4b565b614508604051918261061c565b8281528092614519601f1991612e4b565b0190602036910137565b9060301161038e5790603090565b9060901161038e5760300190606090565b9060b01161038e5760900190602090565b9093929384831161038e57841161038e578101920390565b602090836116a693959495604051968361458e899551809288808901910161063d565b84019185830137015f8382015203808552018361061c565b3590602081106145b4575090565b5f199060200360031b1b1690565b916020610694938181520191612d23565b91926145fd6145ed61460b9360808652608086019061065e565b602095858203602087015261065e565b90838203604085015261065e565b906060818303910152602080845192838152019301915f5b828110614631575050505090565b835185529381019392810192600101614623565b61464d615482565b6060906060905f809460b0810492614664846144f1565b965f905b85821061478357506001600160a01b03947f000000000000000000000000000000000000000000000000000000000000000094506146df9350602092506146af9150612e16565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561056257614764575b501661471c6154e7565b813b1561038e575f80946147466040519788968795869463c82655b760e01b8652600486016145d3565b03925af18015610562576147575750565b806110bf6116a6926105d3565b61477c9060203d60201161187e5761186f818361061c565b505f614712565b6148086147d86147e36147c56147bc7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612b43565b80998989614553565b92909a6147d2848d614523565b9161456b565b9a6147d2838c614531565b988b614802866147fc6147f68686614542565b906145a6565b92612f75565b52614523565b90614818604051928392836145c2565b0390a160010183614668565b929461485d670de0b6b3a76400009661484f6080979461486b969b9a9b60a0895260a0890191612d23565b90868203602088015261065e565b918483036040860152612d23565b9460608201520152565b9061487e615482565b6148888183614523565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af18015610562576149b5575b50169061491a6154e7565b916149336147f661492b8489614531565b949098614542565b95813b1561038e575f8094614960604051998a9687958694630cac9f3160e01b86528c8c60048801614824565b03925af1928315610562577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936149a2575b506130e1604051928392836145c2565b806110bf6149af926105d3565b5f614992565b6149cd9060203d60201161187e5761186f818361061c565b505f61490f565b6001600160801b03908181116149e8571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b90614a10614af1565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561056257614aaf94614aaa925f91614ad2575b508411614ac5575b60405163a9059cbb60e01b60208201526001600160a01b0391909116602482015260448082019490945292835260648361061c565b615713565b6116a660015f80516020615c9283398151915255565b614acd615482565b614a75565b614aeb915060203d60201161055b5761054d818361061c565b5f614a6d565b5f80516020615c928339815191526002815414614b0e5760029055565b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614b4f575b15614b425750905090565b6106949260801c9161341a565b508015614b37565b60cf546001600160801b0381169081614b74575050633b9aca0090565b60801c614b818183613395565b918115612e1157633b9aca0009614b955790565b60018101809111156106945761292e565b60cf546001600160801b0381169082158015614be5575b15614bc757505090565b60801c90614bd682828561341a565b928215612e115709614b955790565b508115614bbd565b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b614c3c6142c2565b6001600160a01b03168015614c8457609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91614d03575b5015614cf157565b604051630a62fbdb60e11b8152600490fd5b614d1c915060203d60201161187e5761186f818361061c565b5f614ce9565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561056257614dbd936001600160401b03610dcf6040614d9c946020975f91614e0d575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610562575f91614df4575090565b610694915060203d60201161055b5761054d818361061c565b614e26915060603d60601161109b5761108c818361061c565b5f614d8d565b90614e3682613890565b614e3f81613890565b6001600160a01b039182169182158015614eb0575b61082457825f5260d360205260405f2090815492858403938411610c13575f80516020615c528339815191529360209355614e9f8160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614e54565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca0060648083019190915281526116a691614aaa826105e6565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614f2f57565b604051631afcd79f60e31b8152600490fd5b614f49614f00565b61271061ffff831611614f8057614f5f90614c34565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614f9a614f00565b8015614fb05760018101614fab5750565b60d455565b6040516331278a8760e01b8152600490fd5b614fca614f00565b670de0b6b3a7640000614fdb612b35565b10614fb057614fe861537b565b61010a55565b614ff6614f00565b6001600160a01b0316806150075750565b6101a180546001600160a01b0319169091179055565b615025614f00565b601e815111801561513f575b61512d5761503d614f00565b8051906001600160401b0382116105ce576150618261505c5f54610567565b615784565b602090816001601f8511146150b9575091806150979261509e95945f926150ae575b50508160011b915f199060031b1c19161790565b5f5561584e565b6116a66150a9613dc1565b600455565b015190505f80615083565b5f80529190601f1984165f80516020615c12833981519152935f905b82821061511557505091600193918561509e979694106150fd575b505050811b015f5561584e565b01515f1960f88460031b161c191690555f80806150f0565b806001869782949787015181550196019401906150d5565b604051632d3f993760e21b8152600490fd5b50600a825111615031565b615152614f00565b61515a614f00565b615162614f00565b60015f80516020615c928339815191525561517b6142c2565b301561082457633b9aca008060cf5460801c01615196612b35565b811161521e576151b0610f626151aa614b57565b926149d4565b6151ba8130615510565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36116a630337f0000000000000000000000000000000000000000000000000000000000000000614eba565b6040516304ffa0ff60e51b8152600490fd5b9081602091031261038e57516106948161258e565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816152cf575b5061529557604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020615c3283398151915284036152b6576116a692935061592c565b604051632a87526960e21b815260048101859052602490fd5b6152e991955060203d60201161055b5761054d818361061c565b935f61526f565b60d154806152fd57505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316611979565b908082101561533f575090565b905090565b60d554908160801c81158015615373575b156153605750905090565b6001600160801b0361069493169161341a565b508015615355565b6e5661756c7456616c696461746f727360881b602060405161539c816105b3565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176105ce5760405251902090565b8151919060418303615478576154719250602082015190606060408401519301515f1a906159ce565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561038e575f809160246040518094819363a3066aab60e01b83523060048401525af18015610562576154de5750565b6116a6906105d3565b604051600160f81b60208201525f60218201523060601b602c82015260208152610694816105b3565b5f80516020615c5283398151915260205f9261552b856149d4565b60cf54906155436001600160801b03918284166138b1565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b0382169182156156a25760801c6155b36155a48261559f613cd3565b612c32565b6155ad85612984565b90615332565b90811561569b576155c382614b20565b9384156156935782615610611ef461326f6116a696610f629661560b6155ef61326f8d6156889a612c32565b6001600160801b03166001600160801b031960d054161760d055565b612b51565b61561a8187615ac0565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a161326f61566c61565b886149d4565b60cf546001600160801b0316612942565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c612942565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f81815260d360205260409020805483810391908211610c13575f935f80516020615c5283398151915292602092556156e9816149d4565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b5f8061573b9260018060a01b03169360208151910182865af1615734612ee8565b9083615bae565b8051908115159182615769575b50506157515750565b60249060405190635274afe760e01b82526004820152fd5b61577c9250602080918301019101612c1d565b155f80615748565b601f8111615790575050565b5f80525f80516020615c12833981519152906020601f840160051c830193106157d3575b601f0160051c01905b8181106157c8575050565b5f81556001016157bd565b90915081906157b4565b90601f82116157ea575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c83019310615844575b601f0160051c01905b81811061583a57505050565b5f8155820161582e565b9091508190615825565b9081516001600160401b0381116105ce57600190615875816158708454610567565b6157dd565b602080601f83116001146158aa575081906158a69394955f926150ae5750508160011b915f199060031b1c19161790565b9055565b90601f198316956158dc60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061591557505083859697106158fd575b505050811b019055565b01515f1960f88460031b161c191690555f80806158f3565b8087859682949686015181550195019301906158e0565b90813b156159ad575f80516020615c3283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156159925761312091615b95565b50503461599b57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615a575790615a276020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15610562575f516001600160a01b03811615615a4d57905f905f90565b505f906001905f90565b5050505f9160039190565b60d15490680100000000000000008210156105ce57600182018060d155821015612ed65760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020615c7283398151915290910155565b91909180158015615b8d575b615b7b57615ad86152f0565b908101809111610c13576001600160a01b03808211615b5b576001600160601b0390818511615b3b57906116a69394615b25615b3693615b166116a8565b95166001600160a01b03168552565b166001600160601b03166020830152565b615a62565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b508215615acc565b5f8061069493602081519101845af4615bac612ee8565b915b90615bd55750805115615bc357805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580615c08575b615be6575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15615bde56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212205e2a7bcdb163f7625bee491bdb92ae01286deff225a066cb7a56792c0826578364736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d1141461037f578063066055e01461037a57806306fdde031461037557806307a2d13a14610370578063095ea7b31461036b57806314c4184b1461036657806318160ddd1461032f5780631a7ff55314610361578063201b9eb51461035c57806323b872dd146103575780632999ad3f146103525780632cdf74011461034d5780632e2d298414610348578063313ce567146103435780633229fa951461033e57806333194c0a146103395780633644e515146103345780633a98ef391461032f578063439fab911461032a57806343e82a791461032557806346904840146103205780634ec96b221461031b5780634f1ef2861461031657806352d1902d1461031157806354fd4d501461030c5780635c60da1b146103075780635cfc1a511461030257806360d60e6e146102fd57806370a082311461028557806372b410a8146102f8578063754c3888146102f357806376b58b90146102ee5780637ecebe00146102e95780637fd6f15c146102e457806383d430d5146102df5780638697d2c2146102da5780638ceab9aa146102d557806395d89b41146102d0578063a49a1e7d146102cb578063a9059cbb146102c6578063ac9650d8146102c1578063ad3cb1cc146102bc578063b0d11302146102b7578063b1f0e7c7146102b2578063b45a1eb5146102ad578063c6e6f592146102a8578063d0a64ddc146102a3578063d505accf1461029e578063d83ad00c14610299578063dd62ed3e14610294578063e74b981b1461028f578063ee3bd5df1461028a578063f04da65b14610285578063f45bf3d2146102805763f851a4400361000e576128c7565b612886565b611a7c565b612860565b612833565b6127d4565b6127ae565b612599565b612561565b612543565b612511565b6124ed565b6124ba565b612475565b612410565b61236f565b61231d565b612279565b612090565b611e30565b611c60565b611c3c565b611c01565b611bb0565b611b44565b611ab7565b611a5e565b611a44565b611a10565b6119f5565b61198c565b611706565b611623565b6115fb565b6114fe565b61135b565b61085f565b6112e6565b6112ac565b611280565b611265565b6110e5565b6110cb565b610c41565b610b65565b6108fd565b610885565b610836565b610794565b61075d565b610697565b6103c3565b610392565b5f91031261038e57565b5f80fd5b3461038e575f36600319011261038e57602060cf5460801c604051908152f35b6001600160801b0381160361038e57565b3461038e57602036600319011261038e576004356103e0816103b2565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610562575f91610533575b50335f90815261016e6020526040902061045c90612909565b916001600160801b0361047684516001600160801b031690565b1615610521576104ca8361048c61051d956131f2565b6104b66104a9846104a484516001600160801b031690565b612942565b6001600160801b03168252565b335f90815261016e6020526040902061295b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610555915060203d60201161055b575b61054d818361061c565b8101906128ef565b5f610443565b503d610543565b6128fe565b90600182811c92168015610595575b602083101461058157565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610576565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176105ce57604052565b61059f565b6001600160401b0381116105ce57604052565b60a081019081106001600160401b038211176105ce57604052565b608081019081106001600160401b038211176105ce57604052565b90601f801991011681019081106001600160401b038211176105ce57604052565b5f5b83811061064e5750505f910152565b818101518382015260200161063f565b906020916106778151809281855285808601910161063d565b601f01601f1916010190565b90602061069492818152019061065e565b90565b3461038e575f36600319011261038e576040515f80546106b681610567565b8084529060209060019081811690811561073357506001146106ef575b61051d856106e38187038261061c565b60405191829182610683565b5f80805293505f80516020615c128339815191525b838510610720575050505081016020016106e38261051d6106d3565b8054868601840152938201938101610704565b86955061051d969350602092506106e394915060ff191682840152151560051b82010192936106d3565b3461038e57602036600319011261038e57602061077b600435612984565b604051908152f35b6001600160a01b0381160361038e57565b3461038e57604036600319011261038e576004356107b181610783565b6001600160a01b03811690602435908215610824576107ec8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b3461038e575f36600319011261038e5761026a546040516001600160a01b039091168152602090f35b3461038e575f36600319011261038e5760206001600160801b0360cf5416604051908152f35b3461038e5760031960203682011261038e57600435906001600160401b03821161038e57608090823603011261038e576108c46108cb91600401613575565b919061370b565b6108d157005b6108d9615578565b806108e057005b5f906040519081525f80516020615c5283398151915260203092a3005b3461038e57606036600319011261038e5760043561091a81610783565b602435906044359061092b82610783565b61093433613890565b61093c614c96565b6109446142c2565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af1948515610562575f95610b46575b50335f90815261016e602052604090206109bf90612909565b926001600160801b036109d985516001600160801b031690565b1615610ae25750506109ea826131f2565b610a16610a096109f9876149d4565b84516001600160801b03166138b1565b6001600160801b03168352565b335f90815260d360205260409020610a3890610a33905b54612984565b614d22565b610a58610a4c84516001600160801b031690565b6001600160801b031690565b11610ad057335f90815261016e6020526040902061051d957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610a9e919061295b565b604080516001600160a01b0395861681526020810187905290810191909152921660608301523391806080810161050a565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561056257610b2492610b15915f91610b29575b506149d4565b6001600160801b031690840152565b6109ea565b610b409150833d851161055b5761054d818361061c565b5f610b0f565b610b5e919550833d851161055b5761054d818361061c565b935f6109a6565b3461038e57606036600319011261038e57600435610b8281610783565b60243590610b8f82610783565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610bdf575b610bd384610bce858883614e2c565b6138cc565b60405160018152602090f35b919093818503948511610c13575f928352600260209081526040808520338652909152909220939093559180610bd3610bbf565b61292e565b606090600319011261038e5760043590602435610c3481610783565b9060443561069481610783565b3461038e57610c4f36610c18565b906001600160a01b038083161561082457610c686142c2565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561038e5760408051631d8557d760e01b815260049491905f81878183875af18015610562576110b2575b506001600160a01b0383165f90815261016e60205260409020610cdb90612909565b6001600160801b039283610cf683516001600160801b031690565b16156110a257610d05826131f2565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610562575f98611071575b50602097888101956001600160401b03918280610d7e8a516001600160401b031690565b161461106157908c92918751918c8380610daa6303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561056257610dd6938e5f9461103c575b5050516001600160801b03165b1690613321565b96610df4610a2d8a60018060a01b03165f5260d360205260405f2090565b92838911801561102c575b61101c57908b610e3d9392610e1b89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561056257670de0b6b3a764000094610e8c948e5f95610fef575b5050610e7e610e70610e8492612e2e565b93516001600160401b031690565b93612e2e565b92169061341a565b1015610fe1578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610562577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610fbe95610f3693610fc3575b5050610f196104a9610f098c6149d4565b83516001600160801b0316612942565b6001600160a01b0386165f90815261016e6020526040902061295b565b610f3f82614b20565b90610f7d610f62610f4f856149d4565b60cf5460801c036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610f8782866156a8565b610f918389614a07565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610fd992903d1061055b5761054d818361061c565b505f80610ef8565b835163185cfc6d60e11b8152fd5b610e84929550611012610e7e9282610e7093903d1061055b5761054d818361061c565b959250508e610e5f565b875163efda1a2760e01b81528590fd5b506110356129aa565b8911610dff565b610dcf929450908161105992903d1061055b5761054d818361061c565b92908e610dc2565b8651630709133160e01b81528490fd5b61109491985060603d60601161109b575b61108c818361061c565b810190613960565b965f610d5a565b503d611082565b825163673f032f60e11b81528790fd5b806110bf6110c5926105d3565b80610384565b5f610cb9565b3461038e575f36600319011261038e57602061077b6129aa565b3461038e576110f336610c18565b916110fd33613890565b61110682613890565b61110e614af1565b60409261116884516323b872dd60e01b602082015233602482015230604482015283606482015260648152611142816105e6565b7f0000000000000000000000000000000000000000000000000000000000000000615713565b6111706142c2565b6001600160a01b0383169283156112545782156112435782611197610a4c60cf5460801c90565b01906111a1612b35565b821161123257611218610f6295936111f286947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c946111ed6111e560209c9a614ba6565b9a8b936149d4565b615510565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020615c928339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b3461038e575f36600319011261038e57602060405160128152f35b3461038e575f36600319011261038e57602061129a6129e7565b6040516001600160a01b039091168152f35b3461038e575f36600319011261038e5760206040517fc77e768dab534fa678edc458b42a344df0e260a0905ed4b4c3727a271a465cd08152f35b3461038e575f36600319011261038e57602061077b612a22565b9181601f8401121561038e578235916001600160401b03831161038e576020838186019501011161038e57565b602060031982011261038e57600435906001600160401b03821161038e5761135791600401611300565b9091565b3461038e576113693661132d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1680156114ea575b6114d85768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa928315610562575f936114b9575b50604051636f4fa30f60e01b8152938285600481335afa9081156105625761142695611421945f93611486575b505061141a9192810190612a96565b9083613ee7565b613fa7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b61141a935090816114ab92903d106114b2575b6114a3818361061c565b810190612a57565b915f61140b565b503d611499565b6114d1919350823d84116114b2576114a3818361061c565b915f6113de565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101561139a565b3461038e5761150c36610c18565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105625782915f916115dc575b501633036115ca5781610fbe61159786867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966139ba565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6115f5915060203d6020116114b2576114a3818361061c565b5f61155f565b3461038e575f36600319011261038e57609c546040516001600160a01b039091168152602090f35b3461038e57602036600319011261038e5760043561164081610783565b60018060a01b03165f5261016e602052602060405f2060405190611663826105b3565b54906001600160801b03918281169081835260801c8483015261168b575b5116604051908152f35b611694816131f2565b611681565b604051906116a6826105e6565b565b604051906116a6826105b3565b6001600160401b0381116105ce57601f01601f191660200190565b9291926116dc826116b5565b916116ea604051938461061c565b82948184528183011161038e578281602093845f960137010152565b60408060031936011261038e57600490813561172181610783565b6024356001600160401b03811161038e573660238201121561038e5761175090369060248187013591016116d0565b91611759613fb3565b8051926117908461178260209363439fab9160e01b85840152846024840152604483019061065e565b03601f19810186528561061c565b611798613fb3565b6117a0614093565b6001600160a01b03838116801592919087908415611957575b84156118e9575b8415611885575b505082156117ef575b50506117e0576100188383615245565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610562575f92611858575b5050155f806117d0565b6118779250803d1061187e575b61186f818361061c565b810190612c1d565b5f8061184e565b503d611865565b855163054fd4d560e41b81529294508391839182905afa9081156105625760039160ff915f916118bc575b5016141591865f6117c7565b6118dc9150843d86116118e2575b6118d4818361061c565b810190615230565b5f6118b0565b503d6118ca565b935050835163198ca60560e11b815282818981875afa9081156105625788917fc77e768dab534fa678edc458b42a344df0e260a0905ed4b4c3727a271a465cd0915f9161193a575b501415936117c0565b6119519150853d871161055b5761054d818361061c565b5f611931565b5f80516020615c32833981519152549094508490611985906001600160a01b03165b6001600160a01b031690565b14936117b9565b3461038e575f36600319011261038e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036119e35760206040515f80516020615c328339815191528152f35b60405163703e46dd60e11b8152600490fd5b3461038e575f36600319011261038e57602060405160028152f35b3461038e575f36600319011261038e575f80516020615c32833981519152546040516001600160a01b039091168152602090f35b3461038e575f36600319011261038e57602061077b612b35565b3461038e57602036600319011261038e57602061077b600435612b5e565b3461038e57602036600319011261038e57600435611a9981610783565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461038e575f36600319011261038e57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610562576020915f91611b27575b506040519015158152f35b611b3e9150823d841161187e5761186f818361061c565b5f611b1c565b3461038e57602036600319011261038e57600435611b6181610783565b611b69614093565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461038e57608036600319011261038e5761051d611be4600435611bd381610783565b606435906044359060243590612c3f565b604080519384526020840192909252908201529081906060820190565b3461038e57602036600319011261038e57600435611c1e81610783565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461038e575f36600319011261038e57602061ffff609c5460a01c16604051908152f35b3461038e5760031960403682011261038e5760049081356001600160401b0380821161038e5760a082850193833603011261038e5760243590811161038e57611cac9036908501611300565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561038e5760405163837d444160e01b8152905f908290818381611cff8c828f01612d43565b03925af1801561056257611e1d575b50611d176142c2565b611d1f613123565b9081163314159182611dee575b50509050611ddd576044019160b0611d448484612dc1565b90500480158015611dc5575b611db557611d65611d5f6129aa565b91612e16565b11611da6575060b0611d778383612dc1565b9050145f14611d935761001891611d8d91612dc1565b90614875565b61001891611da091612dc1565b90614645565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611dd08484612dc1565b905060b082021415611d50565b604051634ca8886760e01b81528390fd5b611e119250611e0b611e1594611e038861434d565b9236916116d0565b91614428565b1590565b805f80611d2c565b806110bf611e2a926105d3565b5f611d0e565b3461038e57606036600319011261038e57600435602435611e55604435828433612c3f565b9192611e817f000000000000000000000000000000000000000000000000000000000000000082612b51565b42108015612088575b8015612080575b61206e577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611ed586611ed0610a4c60d0546001600160801b031690565b61400c565b15611fdc57611f0f611ef4611ee9866149d4565b60d05460801c612942565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611f539190611f4260808261061c565b5190205f5260d260205260405f2090565b555f9360018311611f8c575b50505050611f6d8233614a07565b604080519485526020850191909152830152339180606081015b0390a2005b611fd292939450611f9d9088612b51565b60408051336020820190815291810193909352606083018290529094909190611f429082608081015b0390810183528261061c565b555f808080611f5f565b611fe46142c2565b612020612004611ff3866149d4565b60d5546001600160801b0316612942565b6001600160801b03166001600160801b031960d554161760d555565b61205561203a61202f856149d4565b60d55460801c612942565b6001600160801b0360d5549181199060801b1691161760d555565b6120696120648460d654612b51565b60d655565b611f0f565b604051630e3d8e8d60e11b8152600490fd5b508215611e91565b508115611e8a565b3461038e5760408060031936011261038e57602435906004356120b283610783565b6120ba6142c2565b8015612268576001600160a01b038316908115612257576120da81612984565b908115612246576120ea82615344565b6120f3836149d4565b60cf5460801c9061210391612942565b612122906001600160801b0360cf549181199060801b1691161760cf55565b61212c82336156a8565b60d554958660801c828160d6549061214391612b51565b9861214d876149d4565b61215f916001600160801b03166138b1565b61217f906001600160801b03166001600160801b031960d554161760d555565b61218891612b51565b612191906149d4565b6121b0906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906121e160808261061c565b5190206121f6905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a361223d336138cc565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461038e575f36600319011261038e576040515f6001805461229a81610567565b808552916020916001811690811561073357506001146122c45761051d856106e38187038261061c565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b83851061230a575050505081016020016106e38261051d6106d3565b80548686018401529382019381016122ee565b3461038e57611f877f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61234f3661132d565b9290612359614093565b6040519182916020835233956020840191612d23565b3461038e57604036600319011261038e5761239960043561238f81610783565b6024359033614e2c565b6123a2336138cc565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106123e25750505050505090565b9091929394958480612400600193603f198682030187528a5161065e565b98019301930191949392906123d2565b3461038e57602036600319011261038e576001600160401b0360043581811161038e573660238201121561038e57806004013591821161038e573660248360051b8301011161038e5761051d9160246124699201612f89565b604051918291826123ad565b3461038e575f36600319011261038e5761051d604051612494816105b3565b60058152640352e302e360dc1b602082015260405191829160208352602083019061065e565b3461038e575f36600319011261038e576124d2614af1565b6124da613036565b60015f80516020615c9283398151915255005b3461038e575f36600319011261038e57602061129a613123565b8015150361038e57565b3461038e57604036600319011261038e5761001860043561253181610783565b6024359061253e82612507565b61315a565b3461038e57602036600319011261038e57602061077b600435614b20565b3461038e57602036600319011261038e5761001860043561258181610783565b612589614093565b614bed565b60ff81160361038e57565b3461038e5760e036600319011261038e576004356125b681610783565b6024356125c281610783565b6044359060643592608435906125d78261258e565b6001600160a01b038381169590929086156108245742811061279c576020915f91611fc66126ca89878a61268d61260c612a22565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b03916126a1601f199384810183528261061c565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610562575f5192828416801590811561278f575b5061277d5761276a85916127557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610fbe565b6040516323389ba560e21b8152600490fd5b905083831614155f612710565b604051631ab7da6b60e01b8152600490fd5b3461038e575f36600319011261038e5760206001600160801b0360d05416604051908152f35b3461038e57604036600319011261038e57602061282a6004356127f681610783565b6024359061280382610783565b60018060a01b03165f526002835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461038e57602036600319011261038e5761001860043561285381610783565b61285b614093565b614c34565b3461038e575f36600319011261038e5760206001600160801b0360d55416604051908152f35b3461038e57602036600319011261038e576004356128a381610783565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b3461038e575f36600319011261038e576037546040516001600160a01b039091168152602090f35b9081602091031261038e575190565b6040513d5f823e3d90fd5b90604051612916816105b3565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039182169082160391908211610c1357565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161299c57505090565b916106949260801c9061341a565b6129b2613cd3565b60d0546001600160801b036129c8818316612984565b9060d55416019060801c01908181115f146129e1570390565b50505f90565b6101a1546001600160a01b031680156129fd5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003612a4f5760045490565b610694613dc1565b9081602091031261038e575161069481610783565b359061ffff8216820361038e57565b9080601f8301121561038e57816020610694933591016116d0565b9060208282031261038e5781356001600160401b039283821161038e57019060a08282031261038e57612ac7611699565b9282358452612ad860208401612a6c565b6020850152604083013581811161038e5782612af5918501612a7b565b6040850152606083013581811161038e5782612b12918501612a7b565b6060850152608083013590811161038e57612b2d9201612a7b565b608082015290565b60d4548061069457505f1990565b9060b08201809211610c1357565b91908201809211610c1357565b6001600160801b0360d05416612b726152f0565b908101809111610c13578110612ba557612b9660d654612b90614023565b90612b51565b1115612ba0575f90565b5f1990565b60d19060d1549182915f905b848210612bcb57505050811015612bc55790565b505f1990565b909193808316906001818518811c8301809311610c13575f8790525f80516020615c728339815191528301546001600160a01b0316841015612c12575050935b9190612bb1565b909591019250612c0b565b9081602091031261038e575161069481612507565b91908203918211610c1357565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612c7d81608081015b03601f19810183528261061c565b5190205f5260d260205260405f2054918215612ce7576001600160801b0360d0541690612ca86152f0565b918201809211610c13578391831015612cd55791612cc592614127565b90915b828103908111610c135792565b5090612ce0916140a7565b9091612cc8565b5050505f905f905f90565b9035601e198236030181121561038e5701602081359101916001600160401b03821161038e57813603831361038e57565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061069492602081528235602082015260208301356040820152612d7f612d6f6040850185612cf2565b84606085015260c0840191612d23565b90612db2612da7612d936060870187612cf2565b601f19858703810160808701529591612d23565b946080810190612cf2565b93909282860301910152612d23565b903590601e198136030182121561038e57018035906001600160401b03821161038e5760200191813603831361038e57565b634e487b7160e01b5f52601260045260245ffd5b8115612e11570490565b612df3565b90670de0b6b3a76400009180830292830403610c1357565b90670de0b6b3a764000091828102928184041490151715610c1357565b6001600160401b0381116105ce5760051b60200190565b90612e6c82612e4b565b612e79604051918261061c565b8281528092612e8a601f1991612e4b565b01905f5b828110612e9a57505050565b806060602080938501015201612e8e565b634e487b7160e01b5f52603260045260245ffd5b90821015612ed6576113579160051b810190612dc1565b612eab565b908092918237015f815290565b3d15612f12573d90612ef9826116b5565b91612f07604051938461061c565b82523d5f602084013e565b606090565b60208183031261038e578051906001600160401b03821161038e570181601f8201121561038e578051612f49816116b5565b92612f57604051948561061c565b8184526020828401011161038e57610694916020808501910161063d565b8051821015612ed65760209160051b010190565b919091612f9583612e62565b925f5b818110612fa457505050565b5f80612fb1838587612ebf565b60409391612fc3855180938193612edb565b0390305af490612fd1612ee8565b9115612ff8575090600191612fe68288612f75565b52612ff18187612f75565b5001612f98565b90604481511061038e5761303261301d60049283810151602480918301019101612f17565b925162461bcd60e51b81529283928301610683565b0390fd5b47633b9aca00811061312057604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610562575f926130ff575b506001600160ff1b0382116130e657907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db916130cc8261370b565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b61311991925060203d60201161055b5761054d818361061c565b905f613091565b50565b610109546001600160a01b03168061069457507f000000000000000000000000000000000000000000000000000000000000000090565b61026a546001600160a01b039190821633036115ca576001600160a01b0381165f90815261026b60205260409020549215159260ff16151583146131ed576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91613288575b5060208201916001600160801b03918284511691828214613281578361327461326f61327c95858486511661341a565b6149d4565b1690526149d4565b169052565b5050505050565b6132a1915060203d60201161055b5761054d818361061c565b5f61323f565b90808202905f1981840990828083109203918083039214613316576127109082821115613304577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461338457670de0b6b3a76400009082821115613304577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106949250612e07565b9091828202915f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b9081606091031261038e578051916040602083015192015161069481612507565b81835290916001600160fb1b03831161038e5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361038e576040830152604081013561350181610783565b6001600160a01b031660608381019190915281013536829003601e190181121561038e5701602081359101906001600160401b03811161038e578060051b3603821361038e5760a08360808061069496015201916134ae565b9190915f8382019384129112908015821691151617610c1357565b6040516325f56f1160e01b81526001600160a01b039291606090829081906135a090600483016134d2565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610562575f915f905f956136c6575b50841561367357816135ea6129e7565b16917f000000000000000000000000000000000000000000000000000000000000000016821461366c57509060205f92600460405180958193634641257d60e01b83525af190811561056257613647925f9261364b575b5061355a565b9190565b61366591925060203d60201161055b5761054d818361061c565b905f613641565b9081613679575b50509190565b803b1561038e57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015610562576136b3575b80613673565b806110bf6136c0926105d3565b5f6136ad565b919450506136ec915060603d6060116136f4575b6136e4818361061c565b81019061348d565b93905f6135da565b503d6136da565b600160ff1b8114610c13575f0390565b801561312057613720610a4c60cf5460801c90565b5f82126137ed578161373191612b51565b9061373e610f62836149d4565b613753609c549161ffff8360a01c16906132a7565b80156131ed57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613791610a4c60cf546001600160801b031690565b806137d75750506130e190925b6001600160a01b0316916137b28484615510565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b6130e1926137e79203908461341a565b9261379e565b906137f7906136fb565b61380c610a4c60d5546001600160801b031690565b8061382c575b508061381c575050565b61326f610f62916116a693612c32565b906138877f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161387761200461386c6138658888612b51565b878561341a565b8080940396036149d4565b6040519081529081906020820190565b0390a15f613812565b6001600160a01b03165f90815261026b602052604090205460ff166115ca57565b9190916001600160801b0380809416911601918211610c1357565b60018060a01b0381165f5261016e60205260405f2090604051916138ef836105b3565b54906001600160801b03918281169081855260801c6020850152156131ed57610a33610a2d613942926139206142c2565b613929866131f2565b6001600160a01b03165f90815260d36020526040902090565b91511611610ad057565b51906001600160401b038216820361038e57565b9081606091031261038e5760405190606082018281106001600160401b038211176105ce576139b29160409182528051613999816103b2565b84526139a76020820161394c565b60208501520161394c565b604082015290565b92906001600160a01b039081811615610824576139d56142c2565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561038e57604094855193631d8557d760e01b85526004945f81878183895af1801561056257613cc0575b506001600160a01b0388165f90815261016e60205260409020613a4890612909565b906001600160801b03613a6283516001600160801b031690565b1615613cb057613a71826131f2565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561056257613c91575b508651936303d1689d60e11b97888652602091828780613aeb888c83019190602083019252565b0381845afa968715610562575f97613c72575b508699613b1e610a2d8d60018060a01b03165f5260d360205260405f2090565b88118015613c62575b613c52579083613b6492613b4287516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610562575f85948894613ba99c613c35575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561056257610f09613bf094613bd3936104a9936116a69a613c17575b50506149d4565b6001600160a01b0388165f90815261016e6020526040902061295b565b613c12613bfc83614b20565b8097613c0d610f62610f4f876149d4565b6156a8565b614a07565b81613c2d92903d1061055b5761054d818361061c565b505f80613bcc565b613c4b90873d891161055b5761054d818361061c565b505f613b7e565b825163efda1a2760e01b81528990fd5b50613c6b6129aa565b8811613b27565b613c8a919750833d851161055b5761054d818361061c565b955f613afe565b613ca99060603d60601161109b5761108c818361061c565b505f613ac4565b875163673f032f60e11b81528690fd5b806110bf613ccd926105d3565b5f613a26565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610562575f91613da4575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561056257610694935f93613d85575b5050612b51565b613d9c929350803d1061055b5761054d818361061c565b905f80613d7e565b613dbb9150833d851161055b5761054d818361061c565b5f613d2a565b6040515f905f5490613dd282610567565b9283825260209384830193600190866001821691825f14613ec7575050600114613e84575b50509181613e0d613e7e93612c6f95038261061c565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020615c128339815191525b828410613eb25750505082010181613e0d613df7565b80548685018601528794909301928101613e9c565b60ff1916875292151560051b85019092019250839150613e0d9050613df7565b9190613ef1614f00565b608082015190613eff614f00565b6001600160a01b038416801561082457613f9f94613f8f93613f78926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613f663394602083019061065e565b0390a2602085015161ffff1690614f41565b613f828351614f92565b613f8a614fc2565b614fee565b606060408201519101519061501d565b6116a661514a565b6116a690612589614f00565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613ff1575b50506119e357565b5f80516020615c328339815191525416141590505f80613fe9565b906140156152f0565b918201809211610c13571090565b61402b613cd3565b60d0548060801c8203918211610c13578161404f6001600160801b03809316612984565b9081614075575b505081156129e157610694916140709160d5541690615332565b615344565b919250908181111561408b57035b905f80614056565b50505f614083565b6037546001600160a01b031633036115ca57565b6140af614023565b9160d654928301809311610c1357808311156140f9576140d0920390615332565b9060d5548060801c80155f146140e65750508190565b6001600160801b0361069492168461341a565b5050505f905f90565b9060405161410f816105b3565b91546001600160a01b038116835260a01c6020830152565b60d1545f9485949390918084108015906142ba575b6142ad5783614277575f5b60d15f526001600160a01b031661416c5f80516020615c728339815191528601614102565b8051909790614183906001600160a01b0316611979565b986141a861419c6020809b01516001600160601b031690565b6001600160601b031690565b94838110801561426d575b61425b5791600193979a956141d26141de939488035b838c0390615332565b8092019887039161341a565b01970193808611801590614251575b6142465760d15f52829061420f5f80516020615c728339815191528701614102565b805190890151969992966001600160a01b0390911694600193926141de9290916001600160601b03909116906141d29088036141c9565b945050509250509190565b50818510156141ed565b60405163e8722f8f60e01b8152600490fd5b50808b11156141b3565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316614147565b505093505050505f905f90565b50841561413c565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f9161432e575b5061431c57565b60405163e775715160e01b8152600490fd5b614347915060203d60201161187e5761186f818361061c565b5f614315565b604290467f0000000000000000000000000000000000000000000000000000000000000000036143fc5761010a54905b61439461438d6040830183612dc1565b36916116d0565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526143df81610601565b5190206040519161190160f01b8352600283015260228201522090565b61440461537b565b9061437d565b6004111561441457565b634e487b7160e01b5f52602160045260245ffd5b6144328383615448565b5061443f8195929561440a565b1593846144db575b508315614455575b50505090565b5f92935090829160405161448d81612c6f6020820194630b135d3f60e11b998a8752602484015260406044840152606483019061065e565b51915afa9061449a612ee8565b826144cd575b826144b0575b50505f808061444f565b6144c5919250602080825183010191016128ef565b145f806144a6565b9150602082511015916144a0565b6001600160a01b0383811691161493505f614447565b906144fb82612e4b565b614508604051918261061c565b8281528092614519601f1991612e4b565b0190602036910137565b9060301161038e5790603090565b9060901161038e5760300190606090565b9060b01161038e5760900190602090565b9093929384831161038e57841161038e578101920390565b602090836116a693959495604051968361458e899551809288808901910161063d565b84019185830137015f8382015203808552018361061c565b3590602081106145b4575090565b5f199060200360031b1b1690565b916020610694938181520191612d23565b91926145fd6145ed61460b9360808652608086019061065e565b602095858203602087015261065e565b90838203604085015261065e565b906060818303910152602080845192838152019301915f5b828110614631575050505090565b835185529381019392810192600101614623565b61464d615482565b6060906060905f809460b0810492614664846144f1565b965f905b85821061478357506001600160a01b03947f000000000000000000000000000000000000000000000000000000000000000094506146df9350602092506146af9150612e16565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561056257614764575b501661471c6154e7565b813b1561038e575f80946147466040519788968795869463c82655b760e01b8652600486016145d3565b03925af18015610562576147575750565b806110bf6116a6926105d3565b61477c9060203d60201161187e5761186f818361061c565b505f614712565b6148086147d86147e36147c56147bc7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612b43565b80998989614553565b92909a6147d2848d614523565b9161456b565b9a6147d2838c614531565b988b614802866147fc6147f68686614542565b906145a6565b92612f75565b52614523565b90614818604051928392836145c2565b0390a160010183614668565b929461485d670de0b6b3a76400009661484f6080979461486b969b9a9b60a0895260a0890191612d23565b90868203602088015261065e565b918483036040860152612d23565b9460608201520152565b9061487e615482565b6148888183614523565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af18015610562576149b5575b50169061491a6154e7565b916149336147f661492b8489614531565b949098614542565b95813b1561038e575f8094614960604051998a9687958694630cac9f3160e01b86528c8c60048801614824565b03925af1928315610562577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936149a2575b506130e1604051928392836145c2565b806110bf6149af926105d3565b5f614992565b6149cd9060203d60201161187e5761186f818361061c565b505f61490f565b6001600160801b03908181116149e8571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b90614a10614af1565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561056257614aaf94614aaa925f91614ad2575b508411614ac5575b60405163a9059cbb60e01b60208201526001600160a01b0391909116602482015260448082019490945292835260648361061c565b615713565b6116a660015f80516020615c9283398151915255565b614acd615482565b614a75565b614aeb915060203d60201161055b5761054d818361061c565b5f614a6d565b5f80516020615c928339815191526002815414614b0e5760029055565b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614b4f575b15614b425750905090565b6106949260801c9161341a565b508015614b37565b60cf546001600160801b0381169081614b74575050633b9aca0090565b60801c614b818183613395565b918115612e1157633b9aca0009614b955790565b60018101809111156106945761292e565b60cf546001600160801b0381169082158015614be5575b15614bc757505090565b60801c90614bd682828561341a565b928215612e115709614b955790565b508115614bbd565b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b614c3c6142c2565b6001600160a01b03168015614c8457609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91614d03575b5015614cf157565b604051630a62fbdb60e11b8152600490fd5b614d1c915060203d60201161187e5761186f818361061c565b5f614ce9565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561056257614dbd936001600160401b03610dcf6040614d9c946020975f91614e0d575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610562575f91614df4575090565b610694915060203d60201161055b5761054d818361061c565b614e26915060603d60601161109b5761108c818361061c565b5f614d8d565b90614e3682613890565b614e3f81613890565b6001600160a01b039182169182158015614eb0575b61082457825f5260d360205260405f2090815492858403938411610c13575f80516020615c528339815191529360209355614e9f8160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614e54565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca0060648083019190915281526116a691614aaa826105e6565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614f2f57565b604051631afcd79f60e31b8152600490fd5b614f49614f00565b61271061ffff831611614f8057614f5f90614c34565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614f9a614f00565b8015614fb05760018101614fab5750565b60d455565b6040516331278a8760e01b8152600490fd5b614fca614f00565b670de0b6b3a7640000614fdb612b35565b10614fb057614fe861537b565b61010a55565b614ff6614f00565b6001600160a01b0316806150075750565b6101a180546001600160a01b0319169091179055565b615025614f00565b601e815111801561513f575b61512d5761503d614f00565b8051906001600160401b0382116105ce576150618261505c5f54610567565b615784565b602090816001601f8511146150b9575091806150979261509e95945f926150ae575b50508160011b915f199060031b1c19161790565b5f5561584e565b6116a66150a9613dc1565b600455565b015190505f80615083565b5f80529190601f1984165f80516020615c12833981519152935f905b82821061511557505091600193918561509e979694106150fd575b505050811b015f5561584e565b01515f1960f88460031b161c191690555f80806150f0565b806001869782949787015181550196019401906150d5565b604051632d3f993760e21b8152600490fd5b50600a825111615031565b615152614f00565b61515a614f00565b615162614f00565b60015f80516020615c928339815191525561517b6142c2565b301561082457633b9aca008060cf5460801c01615196612b35565b811161521e576151b0610f626151aa614b57565b926149d4565b6151ba8130615510565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36116a630337f0000000000000000000000000000000000000000000000000000000000000000614eba565b6040516304ffa0ff60e51b8152600490fd5b9081602091031261038e57516106948161258e565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816152cf575b5061529557604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020615c3283398151915284036152b6576116a692935061592c565b604051632a87526960e21b815260048101859052602490fd5b6152e991955060203d60201161055b5761054d818361061c565b935f61526f565b60d154806152fd57505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316611979565b908082101561533f575090565b905090565b60d554908160801c81158015615373575b156153605750905090565b6001600160801b0361069493169161341a565b508015615355565b6e5661756c7456616c696461746f727360881b602060405161539c816105b3565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176105ce5760405251902090565b8151919060418303615478576154719250602082015190606060408401519301515f1a906159ce565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561038e575f809160246040518094819363a3066aab60e01b83523060048401525af18015610562576154de5750565b6116a6906105d3565b604051600160f81b60208201525f60218201523060601b602c82015260208152610694816105b3565b5f80516020615c5283398151915260205f9261552b856149d4565b60cf54906155436001600160801b03918284166138b1565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b0382169182156156a25760801c6155b36155a48261559f613cd3565b612c32565b6155ad85612984565b90615332565b90811561569b576155c382614b20565b9384156156935782615610611ef461326f6116a696610f629661560b6155ef61326f8d6156889a612c32565b6001600160801b03166001600160801b031960d054161760d055565b612b51565b61561a8187615ac0565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a161326f61566c61565b886149d4565b60cf546001600160801b0316612942565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c612942565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f81815260d360205260409020805483810391908211610c13575f935f80516020615c5283398151915292602092556156e9816149d4565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b5f8061573b9260018060a01b03169360208151910182865af1615734612ee8565b9083615bae565b8051908115159182615769575b50506157515750565b60249060405190635274afe760e01b82526004820152fd5b61577c9250602080918301019101612c1d565b155f80615748565b601f8111615790575050565b5f80525f80516020615c12833981519152906020601f840160051c830193106157d3575b601f0160051c01905b8181106157c8575050565b5f81556001016157bd565b90915081906157b4565b90601f82116157ea575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c83019310615844575b601f0160051c01905b81811061583a57505050565b5f8155820161582e565b9091508190615825565b9081516001600160401b0381116105ce57600190615875816158708454610567565b6157dd565b602080601f83116001146158aa575081906158a69394955f926150ae5750508160011b915f199060031b1c19161790565b9055565b90601f198316956158dc60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061591557505083859697106158fd575b505050811b019055565b01515f1960f88460031b161c191690555f80806158f3565b8087859682949686015181550195019301906158e0565b90813b156159ad575f80516020615c3283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28051156159925761312091615b95565b50503461599b57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615a575790615a276020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15610562575f516001600160a01b03811615615a4d57905f905f90565b505f906001905f90565b5050505f9160039190565b60d15490680100000000000000008210156105ce57600182018060d155821015612ed65760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020615c7283398151915290910155565b91909180158015615b8d575b615b7b57615ad86152f0565b908101809111610c13576001600160a01b03808211615b5b576001600160601b0390818511615b3b57906116a69394615b25615b3693615b166116a8565b95166001600160a01b03168552565b166001600160601b03166020830152565b615a62565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b508215615acc565b5f8061069493602081519101845af4615bac612ee8565b915b90615bd55750805115615bc357805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580615c08575b615be6575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15615bde56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212205e2a7bcdb163f7625bee491bdb92ae01286deff225a066cb7a56792c0826578364736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoBlocklistVault.json b/test/shared/artifacts/GnoBlocklistVault.json deleted file mode 100644 index b1e017f8..00000000 --- a/test/shared/artifacts/GnoBlocklistVault.json +++ /dev/null @@ -1,1631 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoBlocklistVault", - "sourceName": "contracts/vaults/gnosis/GnoBlocklistVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "blocklistManager", - "type": "address" - } - ], - "name": "BlocklistManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "BlocklistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "blockedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blocklistManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_blocklistManager", - "type": "address" - } - ], - "name": "setBlocklistManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBlocked", - "type": "bool" - } - ], - "name": "updateBlocklist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61020034620002af5762005316601f38829003908101601f19168301906001600160401b039081831185841017620002b3578085946040948552853961014094859181010312620002af576200005583620002c7565b906200006460208501620002c7565b9262000072818601620002c7565b956200008160608701620002c7565b906200009060808801620002c7565b926200009f60a08901620002c7565b94620000ae60c08a01620002c7565b96620000bd60e08b01620002c7565b976101009b620000cf8d8d01620002c7565b9a610120809d01519360805260a05260c0523060e0528b52468a52835260018060a01b03806101609516855280610180961686526101a09687526101c0971687526101e09788527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166200029e57808083160362000259575b50505051966150399889620002dd8a3960805189818161170e015281816118a601528181612e4f01528181613b1d0152614681015260a05189611485015260c05189818161368901528181613eba015281816140d60152614c86015260e05189818161160501526137fe015251886129e101525187613b9301525186611a4c01525185818161035d015281816105d70152818161082301528181612ab00152818161331701526147910152518481816108e2015281816110e8015281816133d601526147150152518381816123290152612e97015251828181610d0e0152818161363801528181613f2401528181614120015281816142640152614a0a015251816129030152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f808062000151565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002af5756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d114146102c9578063066055e0146102c457806307a2d13a146102bf57806314c4184b146102ba5780631a7ff553146102b5578063201b9eb5146102b05780632999ad3f146102ab5780632cdf7401146102a65780632e2d2984146102a15780633229fa951461029c57806333194c0a146102975780633a98ef3914610292578063439fab911461028d57806343e82a791461028857806346904840146102835780634ec96b221461027e5780634f1ef2861461027957806352d1902d1461027457806354fd4d501461026f5780635c60da1b1461026a5780635cfc1a511461026557806360d60e6e1461026057806372b410a81461025b578063754c38881461025657806376b58b90146102515780637fd6f15c1461024c57806383d430d5146102475780638697d2c2146102425780638ceab9aa1461023d578063a49a1e7d14610238578063ac9650d814610233578063ad3cb1cc1461022e578063b0d1130214610229578063b1f0e7c714610224578063b45a1eb51461021f578063c6e6f5921461021a578063d0a64ddc14610215578063d83ad00c14610210578063e74b981b1461020b578063ee3bd5df14610206578063f04da65b14610201578063f45bf3d2146101fc5763f851a4400361000e576121e3565b6121a2565b612167565b612141565b612114565b6120ee565b6120c1565b6120a3565b612071565b61204d565b61201a565b611fd5565b611f5f565b611e64565b611c7b565b611a20565b611850565b61182c565b6117db565b611770565b6116e3565b6116c5565b6116ab565b611677565b61165c565b6115f3565b61136d565b6111de565b6111b6565b6110b9565b610f16565b610e95565b610e5b565b610e2f565b610caf565b610c95565b6107f9565b610565565b610500565b6104d7565b6104b1565b61030d565b6102dc565b5f9103126102d857565b5f80fd5b346102d8575f3660031901126102d857602060985460801c604051908152f35b6001600160801b038116036102d857565b346102d85760203660031901126102d85760043561032a816102fc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156104ac575f9161047d575b50335f908152610137602052604090206103a690612224565b916001600160801b036103c084516001600160801b031690565b161561046b57610414836103d661046795612a9b565b6104006103f3846103ee84516001600160801b031690565b61225d565b6001600160801b03168252565b335f9081526101376020526040902061227b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61049f915060203d6020116104a5575b61049781836112ec565b81019061220a565b5f61038d565b503d61048d565b612219565b346102d85760203660031901126102d85760206104cf6004356122ad565b604051908152f35b346102d8575f3660031901126102d857610201546040516001600160a01b039091168152602090f35b346102d8576003196020368201126102d857600435906001600160401b0382116102d85760809082360301126102d85761053f61054691600401612e1e565b9190612fb4565b61054c57005b610018613139565b6001600160a01b038116036102d857565b346102d85760603660031901126102d85760043561058281610554565b602435906044359061059382610554565b61059c33613269565b6105a4614666565b6105ac613b02565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af19485156104ac575f956107ae575b50335f9081526101376020526040902061062790612224565b926001600160801b0361064185516001600160801b031690565b161561074a57505061065282612a9b565b61067e61067161066187614213565b84516001600160801b031661328a565b6001600160801b03168352565b335f908152609c602052604090206106a09061069b905b546122ad565b6146f2565b6106c06106b484516001600160801b031690565b6001600160801b031690565b1161073857335f90815261013760205260409020610467957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610706919061227b565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610454565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa9182156104ac5761078c9261077d915f91610791575b50614213565b6001600160801b031690840152565b610652565b6107a89150833d85116104a55761049781836112ec565b5f610777565b6107c6919550833d85116104a55761049781836112ec565b935f61060e565b60609060031901126102d857600435906024356107e981610554565b906044356107f681610554565b90565b346102d857610807366107cd565b906001600160a01b0380831615610c8357610820613b02565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102d85760408051631d8557d760e01b815260049491905f81878183875af180156104ac57610c6a575b506001600160a01b0383165f9081526101376020526040902061089390612224565b6001600160801b0392836108ae83516001600160801b031690565b1615610c5a576108bd82612a9b565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa9788156104ac575f98610c29575b50602097888101956001600160401b039182806109368a516001600160401b031690565b1614610c1957908c92918751918c83806109626303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156104ac5761098e938e5f94610bf4575b5050516001600160801b03165b1690612bca565b966109ac6106958a60018060a01b03165f52609c60205260405f2090565b928389118015610be4575b610bd457908b6109f593926109d389516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa9182156104ac57670de0b6b3a764000094610a44948e5f95610ba7575b5050610a36610a28610a3c926126d8565b93516001600160401b031690565b936126d8565b921690612cc3565b1015610b99578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156104ac577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610b7695610aee93610b7b575b5050610ad16103f3610ac18c614213565b83516001600160801b031661225d565b6001600160a01b0386165f9081526101376020526040902061227b565b610af78261435f565b90610b35610b1a610b0785614213565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610b3f82866147fc565b610b498389614246565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610b9192903d106104a55761049781836112ec565b505f80610ab0565b835163185cfc6d60e11b8152fd5b610a3c929550610bca610a369282610a2893903d106104a55761049781836112ec565b959250508e610a17565b875163efda1a2760e01b81528590fd5b50610bed6122d3565b89116109b7565b6109879294509081610c1192903d106104a55761049781836112ec565b92908e61097a565b8651630709133160e01b81528490fd5b610c4c91985060603d606011610c53575b610c4481836112ec565b8101906132b9565b965f610912565b503d610c3a565b825163673f032f60e11b81528790fd5b80610c77610c7d92611288565b806102ce565b5f610871565b60405163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d85760206104cf6122d3565b346102d857610cbd366107cd565b91610cc733613269565b610cd082613269565b610cd8614330565b604092610d3284516323b872dd60e01b602082015233602482015230604482015283606482015260648152610d0c816112b6565b7f0000000000000000000000000000000000000000000000000000000000000000614d92565b610d3a613b02565b6001600160a01b038316928315610e1e578215610e0d5782610d616106b460985460801c90565b0190610d6b6123df565b8211610dfc57610de2610b1a9593610dbc86947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610db7610daf60209c9a6143e5565b9a8b93614213565b6144d5565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020614fe48339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d8576020610e49612310565b6040516001600160a01b039091168152f35b346102d8575f3660031901126102d85760206040517f6c3152ed991a2a6ec7359c31f742e79dd206dc9d7378f631119a96bee15f8b868152f35b346102d8575f3660031901126102d85760206001600160801b0360985416604051908152f35b9181601f840112156102d8578235916001600160401b0383116102d857602083818601950101116102d857565b60206003198201126102d857600435906001600160401b0382116102d857610f1291600401610ebb565b9091565b346102d857610f2436610ee8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1680156110a5575b6110935768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156104ac575f93611074575b50604051636f4fa30f60e01b8152938285600481335afa9081156104ac57610fe195610fdc945f93611041575b5050610fd59192810190612360565b9083613700565b6137e8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b610fd59350908161106692903d1061106d575b61105e81836112ec565b81019061234b565b915f610fc6565b503d611054565b61108c919350823d841161106d5761105e81836112ec565b915f610f99565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015610f55565b346102d8576110c7366107cd565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156104ac5782915f91611197575b501633036111855781610b7661115286867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966132f9565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6111b0915060203d60201161106d5761105e81836112ec565b5f61111a565b346102d8575f3660031901126102d8576065546040516001600160a01b039091168152602090f35b346102d85760203660031901126102d8576004356111fb81610554565b60018060a01b03165f52610137602052602060405f206040519061121e82611268565b54906001600160801b03918281169081835260801c84830152611246575b5116604051908152f35b61124f81612a9b565b61123c565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761128357604052565b611254565b6001600160401b03811161128357604052565b606081019081106001600160401b0382111761128357604052565b60a081019081106001600160401b0382111761128357604052565b608081019081106001600160401b0382111761128357604052565b90601f801991011681019081106001600160401b0382111761128357604052565b6040519061131a82611268565b565b6001600160401b03811161128357601f01601f191660200190565b9291926113438261131c565b9161135160405193846112ec565b8294818452818301116102d8578281602093845f960137010152565b6040806003193601126102d857600490813561138881610554565b6024356001600160401b0381116102d857366023820112156102d8576113b79036906024818701359101611337565b916113c06137f4565b8051926113f7846113e960209363439fab9160e01b858401528460248401526044830190611ed7565b03601f1981018652856112ec565b6113ff6137f4565b6114076138d4565b6001600160a01b038381168015929190879084156115be575b8415611550575b84156114ec575b50508215611456575b5050611447576100188383614a59565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac575f926114bf575b5050155f80611437565b6114de9250803d106114e5575b6114d681836112ec565b8101906124c7565b5f806114b5565b503d6114cc565b855163054fd4d560e41b81529294508391839182905afa9081156104ac5760039160ff915f91611523575b5016141591865f61142e565b6115439150843d8611611549575b61153b81836112ec565b810190614a40565b5f611517565b503d611531565b935050835163198ca60560e11b815282818981875afa9081156104ac5788917f6c3152ed991a2a6ec7359c31f742e79dd206dc9d7378f631119a96bee15f8b86915f916115a1575b50141593611427565b6115b89150853d87116104a55761049781836112ec565b5f611598565b5f80516020614fc48339815191525490945084906115ec906001600160a01b03165b6001600160a01b031690565b1493611420565b346102d8575f3660031901126102d8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361164a5760206040515f80516020614fc48339815191528152f35b60405163703e46dd60e11b8152600490fd5b346102d8575f3660031901126102d857602060405160028152f35b346102d8575f3660031901126102d8575f80516020614fc4833981519152546040516001600160a01b039091168152602090f35b346102d8575f3660031901126102d85760206104cf6123df565b346102d85760203660031901126102d85760206104cf600435612408565b346102d8575f3660031901126102d857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104ac576020915f91611753575b506040519015158152f35b61176a9150823d84116114e5576114d681836112ec565b5f611748565b346102d85760203660031901126102d85760043561178d81610554565b6117956138d4565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102d85760803660031901126102d85761046761180f6004356117fe81610554565b6064359060443590602435906124e9565b604080519384526020840192909252908201529081906060820190565b346102d8575f3660031901126102d857602061ffff60655460a01c16604051908152f35b346102d8576003196040368201126102d85760049081356001600160401b038082116102d85760a08285019383360301126102d8576024359081116102d85761189c9036908501610ebb565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102d85760405163837d444160e01b8152905f9082908183816118ef8c828f016125ed565b03925af180156104ac57611a0d575b50611907613b02565b61190f6129cd565b90811633141591826119de575b505090506119cd576044019160b0611934848461266b565b905004801580156119b5575b6119a55761195561194f6122d3565b916126c0565b11611996575060b0611967838361266b565b9050145f14611983576100189161197d9161266b565b906140b4565b610018916119909161266b565b90613e84565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506119c0848461266b565b905060b082021415611940565b604051634ca8886760e01b81528390fd5b611a0192506119fb611a05946119f388613b8d565b923691611337565b91613c67565b1590565b805f8061191c565b80610c77611a1a92611288565b5f6118fe565b346102d85760603660031901126102d857600435602435611a456044358284336124e9565b9192611a717f0000000000000000000000000000000000000000000000000000000000000000826123fb565b42108015611c73575b8015611c6b575b611c59577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611ac586611ac06106b46099546001600160801b031690565b61384d565b15611bc757611aff611ae4611ad986614213565b60995460801c61225d565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611b439190611b326080826112ec565b5190205f52609b60205260405f2090565b555f9360018311611b7c575b50505050611b5d8233614246565b604080519485526020850191909152830152339180606081015b0390a2005b611bbd92939450611b8d90886123fb565b6040805133602082019081529181019390935260608301829052608095860183529094909190611b3290826112ec565b555f808080611b4f565b611bcf613b02565b611c0b611bef611bde86614213565b609e546001600160801b031661225d565b6001600160801b03166001600160801b0319609e541617609e55565b611c40611c25611c1a85614213565b609e5460801c61225d565b6001600160801b03609e549181199060801b16911617609e55565b611c54611c4f84609f546123fb565b609f55565b611aff565b604051630e3d8e8d60e11b8152600490fd5b508215611a81565b508115611a7a565b346102d8576040806003193601126102d85760243590600435611c9d83610554565b611ca5613b02565b8015611e53576001600160a01b038316908115611e4257611cc5816122ad565b908115611e3157611cd582614b46565b611cde83614213565b60985460801c90611cee9161225d565b611d0d906001600160801b036098549181199060801b16911617609855565b611d1782336147fc565b609e54958660801c8281609f5490611d2e916123fb565b98611d3887614213565b611d4a916001600160801b031661328a565b611d6a906001600160801b03166001600160801b0319609e541617609e55565b611d73916123fb565b611d7c90614213565b611d9b906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611dcc6080826112ec565b519020611de1905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611e2833614d12565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346102d857611b777f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611e9636610ee8565b9290611ea06138d4565b60405191829160208352339560208401916125cd565b5f5b838110611ec75750505f910152565b8181015183820152602001611eb8565b90602091611ef081518092818552858086019101611eb6565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611f315750505050505090565b9091929394958480611f4f600193603f198682030187528a51611ed7565b9801930193019194939290611f21565b346102d85760203660031901126102d8576001600160401b036004358181116102d857366023820112156102d85780600401359182116102d8573660248360051b830101116102d857610467916024611fb89201612833565b60405191829182611efc565b9060206107f6928181520190611ed7565b346102d8575f3660031901126102d857610467604051611ff481611268565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611ed7565b346102d8575f3660031901126102d857612032614330565b61203a6128e0565b60015f80516020614fe483398151915255005b346102d8575f3660031901126102d8576020610e496129cd565b801515036102d857565b346102d85760403660031901126102d85761001860043561209181610554565b6024359061209e82612067565b612a03565b346102d85760203660031901126102d85760206104cf60043561435f565b346102d85760203660031901126102d8576100186004356120e181610554565b6120e96138d4565b61442c565b346102d8575f3660031901126102d85760206001600160801b0360995416604051908152f35b346102d85760203660031901126102d85761001860043561213481610554565b61213c6138d4565b614473565b346102d8575f3660031901126102d85760206001600160801b03609e5416604051908152f35b346102d85760203660031901126102d85760043561218481610554565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102d85760203660031901126102d8576004356121bf81610554565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b346102d8575f3660031901126102d8575f546040516001600160a01b039091168152602090f35b908160209103126102d8575190565b6040513d5f823e3d90fd5b9060405161223181611268565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161227657565b612249565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816122c557505090565b916107f69260801c90612cc3565b6122db613612565b6099546001600160801b036122f18183166122ad565b90609e5416019060801c01908181115f1461230a570390565b50505f90565b61016a546001600160a01b031680156123265790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102d857516107f681610554565b906020828203126102d85781356001600160401b03928382116102d85701916060838303126102d857604051926123968461129b565b80358452602081013561ffff811681036102d857602085015260408101359182116102d857019080601f830112156102d8578160206123d793359101611337565b604082015290565b609d54806107f657505f1990565b9060b0820180921161227657565b9190820180921161227657565b6001600160801b036099541661241c614b04565b90810180911161227657811061244f57612440609f5461243a613864565b906123fb565b111561244a575f90565b5f1990565b609a90609a549182915f905b8482106124755750505081101561246f5790565b505f1990565b909193808316906001818518811c8301809311612276575f8790525f80516020614fa48339815191528301546001600160a01b03168410156124bc575050935b919061245b565b9095910192506124b5565b908160209103126102d857516107f681612067565b9190820391821161227657565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061252781608081015b03601f1981018352826112ec565b5190205f52609b60205260405f2054918215612591576001600160801b036099541690612552614b04565b91820180921161227657839183101561257f579161256f92613967565b90915b8281039081116122765792565b509061258a916138e7565b9091612572565b5050505f905f905f90565b9035601e19823603018112156102d85701602081359101916001600160401b0382116102d85781360383136102d857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06107f692602081528235602082015260208301356040820152612629612619604085018561259c565b84606085015260c08401916125cd565b9061265c61265161263d606087018761259c565b601f198587038101608087015295916125cd565b94608081019061259c565b939092828603019101526125cd565b903590601e19813603018212156102d857018035906001600160401b0382116102d8576020019181360383136102d857565b634e487b7160e01b5f52601260045260245ffd5b81156126bb570490565b61269d565b90670de0b6b3a7640000918083029283040361227657565b90670de0b6b3a76400009182810292818404149015171561227657565b6001600160401b0381116112835760051b60200190565b90612716826126f5565b61272360405191826112ec565b8281528092612734601f19916126f5565b01905f5b82811061274457505050565b806060602080938501015201612738565b634e487b7160e01b5f52603260045260245ffd5b9082101561278057610f129160051b81019061266b565b612755565b908092918237015f815290565b3d156127bc573d906127a38261131c565b916127b160405193846112ec565b82523d5f602084013e565b606090565b6020818303126102d8578051906001600160401b0382116102d8570181601f820112156102d85780516127f38161131c565b9261280160405194856112ec565b818452602082840101116102d8576107f69160208085019101611eb6565b80518210156127805760209160051b010190565b91909161283f8361270c565b925f5b81811061284e57505050565b5f8061285b838587612769565b6040939161286d855180938193612785565b0390305af49061287b612792565b91156128a2575090600191612890828861281f565b5261289b818761281f565b5001612842565b9060448151106102d8576128dc6128c7600492838101516024809183010191016127c1565b925162461bcd60e51b81529283928301611fc4565b0390fd5b47633b9aca0081106129ca57604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19182156104ac575f926129a9575b506001600160ff1b03821161299057907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db9161297682612fb4565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b6129c391925060203d6020116104a55761049781836112ec565b905f61293b565b50565b60d2546001600160a01b0316806107f657507f000000000000000000000000000000000000000000000000000000000000000090565b610201546001600160a01b03919082163303611185576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612a96576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91612b31575b5060208201916001600160801b03918284511691828214612b2a5783612b1d612b18612b25958584865116612cc3565b614213565b169052614213565b169052565b5050505050565b612b4a915060203d6020116104a55761049781836112ec565b5f612ae8565b90808202905f1981840990828083109203918083039214612bbf576127109082821115612bad577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612c2d57670de0b6b3a76400009082821115612bad577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107f692506126b1565b9091828202915f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102d857805191604060208301519201516107f681612067565b81835290916001600160fb1b0383116102d85760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102d85760408301526040810135612daa81610554565b6001600160a01b031660608381019190915281013536829003601e19018112156102d85701602081359101906001600160401b0381116102d8578060051b360382136102d85760a0836080806107f69601520191612d57565b9190915f838201938412911290801582169115161761227657565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612e499060048301612d7b565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ac575f915f905f95612f6f575b508415612f1c5781612e93612310565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612f1557509060205f92600460405180958193634641257d60e01b83525af19081156104ac57612ef0925f92612ef4575b50612e03565b9190565b612f0e91925060203d6020116104a55761049781836112ec565b905f612eea565b9081612f22575b50509190565b803b156102d857604051636ee3193160e11b815260048101929092525f908290602490829084905af180156104ac57612f5c575b80612f1c565b80610c77612f6992611288565b5f612f56565b91945050612f95915060603d606011612f9d575b612f8d81836112ec565b810190612d36565b93905f612e83565b503d612f83565b600160ff1b8114612276575f0390565b80156129ca57612fc96106b460985460801c90565b5f82126130965781612fda916123fb565b90612fe7610b1a83614213565b612ffc6065549161ffff8360a01c1690612b50565b8015612a9657807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479361303a6106b46098546001600160801b031690565b8061308057505061298b90925b6001600160a01b03169161305b84846144d5565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b61298b9261309092039084612cc3565b92613047565b906130a090612fa4565b6130b56106b4609e546001600160801b031690565b806130d5575b50806130c5575050565b612b18610b1a9161131a936124dc565b906131307f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91613120611bef61311561310e88886123fb565b8785612cc3565b808094039603614213565b6040519081529081906020820190565b0390a15f6130bb565b609954906001600160801b0382169182156132635760801c61317461316582613160613612565b6124dc565b61316e856122ad565b90614521565b90811561325c576131848261435f565b93841561325457826131d1611ae4612b1861131a96610b1a966131cc6131b0612b188d6132499a6124dc565b6001600160801b03166001600160801b03196099541617609955565b6123fb565b6131db8187614591565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a1612b1861322d61321c88614213565b6098546001600160801b031661225d565b6001600160801b03166001600160801b03196098541617609855565b60985460801c61225d565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f908152610202602052604090205460ff1661118557565b9190916001600160801b038080941691160191821161227657565b51906001600160401b03821682036102d857565b908160609103126102d8576123d760408051926132d58461129b565b80516132e0816102fc565b84526132ee602082016132a5565b6020850152016132a5565b92906001600160a01b039081811615610c8357613314613b02565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102d857604094855193631d8557d760e01b85526004945f81878183895af180156104ac576135ff575b506001600160a01b0388165f9081526101376020526040902061338790612224565b906001600160801b036133a183516001600160801b031690565b16156135ef576133b082612a9b565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156104ac576135d0575b508651936303d1689d60e11b9788865260209182878061342a888c83019190602083019252565b0381845afa9687156104ac575f976135b1575b50869961345d6106958d60018060a01b03165f52609c60205260405f2090565b881180156135a1575b6135915790836134a39261348187516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa9889156104ac575f859488946134e89c613574575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156104ac57610ac161352f94613512936103f39361131a9a613556575b5050614213565b6001600160a01b0388165f9081526101376020526040902061227b565b61355161353b8361435f565b809761354c610b1a610b0787614213565b6147fc565b614246565b8161356c92903d106104a55761049781836112ec565b505f8061350b565b61358a90873d89116104a55761049781836112ec565b505f6134bd565b825163efda1a2760e01b81528990fd5b506135aa6122d3565b8811613466565b6135c9919750833d85116104a55761049781836112ec565b955f61343d565b6135e89060603d606011610c5357610c4481836112ec565b505f613403565b875163673f032f60e11b81528690fd5b80610c7761360c92611288565b5f613365565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa9081156104ac575f916136e3575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac576107f6935f936136c4575b50506123fb565b6136db929350803d106104a55761049781836112ec565b905f806136bd565b6136fa9150833d85116104a55761049781836112ec565b5f613669565b61370861488f565b604083015161371561488f565b6001600160a01b0382168015610c83576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061376e33946020830190611ed7565b0390a260208301519261377f61488f565b61271061ffff8516116137d6576137ce9361379c6137c193614473565b6065805461ffff60a01b191660a09290921b61ffff60a01b16919091179055516148d0565b6137c9614900565b61492b565b61131a61495a565b604051638a81d3b360e01b8152600490fd5b61131a906120e961488f565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613832575b505061164a57565b5f80516020614fc48339815191525416141590505f8061382a565b90613856614b04565b918201809211612276571090565b61386c613612565b6099548060801c820391821161227657816138906001600160801b038093166122ad565b90816138b6575b5050811561230a576107f6916138b191609e541690614521565b614b46565b91925090818111156138cc57035b905f80613897565b50505f6138c4565b5f546001600160a01b0316330361118557565b6138ef613864565b91609f54928301809311612276578083111561393957613910920390614521565b90609e548060801c80155f146139265750508190565b6001600160801b036107f6921684612cc3565b5050505f905f90565b9060405161394f81611268565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613afa575b613aed5783613ab7575f5b609a5f526001600160a01b03166139ac5f80516020614fa48339815191528601613942565b80519097906139c3906001600160a01b03166115e0565b986139e86139dc6020809b01516001600160601b031690565b6001600160601b031690565b948381108015613aad575b613a9b5791600193979a95613a12613a1e939488035b838c0390614521565b80920198870391612cc3565b01970193808611801590613a91575b613a8657609a5f528290613a4f5f80516020614fa48339815191528701613942565b805190890151969992966001600160a01b039091169460019392613a1e9290916001600160601b0390911690613a12908803613a09565b945050509250509190565b5081851015613a2d565b60405163e8722f8f60e01b8152600490fd5b50808b11156139f3565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613987565b505093505050505f905f90565b50841561397c565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91613b6e575b50613b5c57565b60405163e775715160e01b8152600490fd5b613b87915060203d6020116114e5576114d681836112ec565b5f613b55565b604290467f000000000000000000000000000000000000000000000000000000000000000003613c3b5760d354905b613bd3613bcc604083018361266b565b3691611337565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613c1e816112d1565b5190206040519161190160f01b8352600283015260228201522090565b613c43614b7d565b90613bbc565b60041115613c5357565b634e487b7160e01b5f52602160045260245ffd5b613c718383614c4a565b50613c7e81959295613c49565b159384613d1a575b508315613c94575b50505090565b5f929350908291604051613ccc816125196020820194630b135d3f60e11b998a87526024840152604060448401526064830190611ed7565b51915afa90613cd9612792565b82613d0c575b82613cef575b50505f8080613c8e565b613d049192506020808251830101910161220a565b145f80613ce5565b915060208251101591613cdf565b6001600160a01b0383811691161493505f613c86565b90613d3a826126f5565b613d4760405191826112ec565b8281528092613d58601f19916126f5565b0190602036910137565b906030116102d85790603090565b906090116102d85760300190606090565b9060b0116102d85760900190602090565b909392938483116102d85784116102d8578101920390565b6020908361131a939594956040519683613dcd8995518092888089019101611eb6565b84019185830137015f838201520380855201836112ec565b359060208110613df3575090565b5f199060200360031b1b1690565b9160206107f69381815201916125cd565b9192613e3c613e2c613e4a93608086526080860190611ed7565b6020958582036020870152611ed7565b908382036040850152611ed7565b906060818303910152602080845192838152019301915f5b828110613e70575050505090565b835185529381019392810192600101613e62565b613e8c614c84565b6060906060905f809460b0810492613ea384613d30565b965f905b858210613fc257506001600160a01b03947f00000000000000000000000000000000000000000000000000000000000000009450613f1e935060209250613eee91506126c0565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af180156104ac57613fa3575b5016613f5b614ce9565b813b156102d8575f8094613f856040519788968795869463c82655b760e01b865260048601613e12565b03925af180156104ac57613f965750565b80610c7761131a92611288565b613fbb9060203d6020116114e5576114d681836112ec565b505f613f51565b614047614017614022614004613ffb7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c6123ed565b80998989613d92565b92909a614011848d613d62565b91613daa565b9a614011838c613d70565b988b6140418661403b6140358686613d81565b90613de5565b9261281f565b52613d62565b9061405760405192839283613e01565b0390a160010183613ea7565b929461409c670de0b6b3a76400009661408e608097946140aa969b9a9b60a0895260a08901916125cd565b908682036020880152611ed7565b9184830360408601526125cd565b9460608201520152565b906140bd614c84565b6140c78183613d62565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af180156104ac576141f4575b501690614159614ce9565b9161417261403561416a8489613d70565b949098613d81565b95813b156102d8575f809461419f604051998a9687958694630cac9f3160e01b86528c8c60048801614063565b03925af19283156104ac577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936141e1575b5061298b60405192839283613e01565b80610c776141ee92611288565b5f6141d1565b61420c9060203d6020116114e5576114d681836112ec565b505f61414e565b6001600160801b0390818111614227571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b9061424f614330565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa9384156104ac576142ee946142e9925f91614311575b508411614304575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836112ec565b614d92565b61131a60015f80516020614fe483398151915255565b61430c614c84565b6142b4565b61432a915060203d6020116104a55761049781836112ec565b5f6142ac565b5f80516020614fe4833981519152600281541461434d5760029055565b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b0382168115801561438e575b156143815750905090565b6107f69260801c91612cc3565b508015614376565b6098546001600160801b03811690816143b3575050633b9aca0090565b60801c6143c08183612c3e565b9181156126bb57633b9aca00096143d45790565b60018101809111156107f657612249565b6098546001600160801b0381169082158015614424575b1561440657505090565b60801c90614415828285612cc3565b9282156126bb57096143d45790565b5081156143fc565b61020180546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b61447b613b02565b6001600160a01b031680156144c357606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6144de82614213565b609854906144f66001600160801b039182841661328a565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b908082101561452e575090565b905090565b609a549068010000000000000000821015611283576001820180609a5582101561278057609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614fa483398151915290910155565b9190918015801561465e575b61464c576145a9614b04565b908101809111612276576001600160a01b0380821161462c576001600160601b039081851161460c579061131a93946145f6614607936145e761130d565b95166001600160a01b03168552565b166001600160601b03166020830152565b614533565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561459d565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f916146d3575b50156146c157565b604051630a62fbdb60e11b8152600490fd5b6146ec915060203d6020116114e5576114d681836112ec565b5f6146b9565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156104ac5761478d936001600160401b03610987604061476c946020975f916147dd575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156104ac575f916147c4575090565b6107f6915060203d6020116104a55761049781836112ec565b6147f6915060603d606011610c5357610c4481836112ec565b5f61475d565b60018060a01b03165f52609c60205260405f20908154818103908111612276576148269255614213565b609854906001600160801b03908183160316906001600160801b03191617609855565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca00606480830191909152815261131a916142e9826112b6565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156148be57565b604051631afcd79f60e31b8152600490fd5b6148d861488f565b80156148ee57600181016148e95750565b609d55565b6040516331278a8760e01b8152600490fd5b61490861488f565b670de0b6b3a76400006149196123df565b106148ee57614926614b7d565b60d355565b61493361488f565b6001600160a01b0316806149445750565b61016a80546001600160a01b0319169091179055565b61496261488f565b61496a61488f565b61497261488f565b60015f80516020614fe48339815191525561498b613b02565b3015610c8357633b9aca008060985460801c016149a66123df565b8111614a2e576149c0610b1a6149ba614396565b92614213565b6149ca81306144d5565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a361131a30337f0000000000000000000000000000000000000000000000000000000000000000614849565b6040516304ffa0ff60e51b8152600490fd5b908160209103126102d8575160ff811681036102d85790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614ae3575b50614aa957604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614fc48339815191528403614aca5761131a929350614e03565b604051632a87526960e21b815260048101859052602490fd5b614afd91955060203d6020116104a55761049781836112ec565b935f614a83565b609a5480614b1157505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166115e0565b609e54908160801c81158015614b75575b15614b625750905090565b6001600160801b036107f6931691612cc3565b508015614b57565b6e5661756c7456616c696461746f727360881b6020604051614b9e81611268565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176112835760405251902090565b8151919060418303614c7a57614c739250602082015190606060408401519301515f1a90614ea5565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102d8575f809160246040518094819363a3066aab60e01b83523060048401525af180156104ac57614ce05750565b61131a90611288565b604051600160f81b60208201525f60218201523060601b602c820152602081526107f681611268565b60018060a01b0381165f5261013760205260405f209060405191614d3583611268565b54906001600160801b03918281169081855260801c602085015215612a965761069b610695614d8892614d66613b02565b614d6f86612a9b565b6001600160a01b03165f908152609c6020526040902090565b9151161161073857565b5f80614dba9260018060a01b03169360208151910182865af1614db3612792565b9083614f40565b8051908115159182614de8575b5050614dd05750565b60249060405190635274afe760e01b82526004820152fd5b614dfb92506020809183010191016124c7565b155f80614dc7565b90813b15614e84575f80516020614fc483398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614e69576129ca91614f27565b505034614e7257565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614f1c579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156104ac575f516001600160a01b03811615614f1257905f905f90565b505f906001905f90565b5050505f9160039190565b5f806107f693602081519101845af4614f3e612792565b915b90614f675750805115614f5557805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614f9a575b614f78575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614f7056fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220ec6f6df673d7dbf00de71fc227d5de317bb95b6881bb8bd514d8065c072c473964736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d114146102c9578063066055e0146102c457806307a2d13a146102bf57806314c4184b146102ba5780631a7ff553146102b5578063201b9eb5146102b05780632999ad3f146102ab5780632cdf7401146102a65780632e2d2984146102a15780633229fa951461029c57806333194c0a146102975780633a98ef3914610292578063439fab911461028d57806343e82a791461028857806346904840146102835780634ec96b221461027e5780634f1ef2861461027957806352d1902d1461027457806354fd4d501461026f5780635c60da1b1461026a5780635cfc1a511461026557806360d60e6e1461026057806372b410a81461025b578063754c38881461025657806376b58b90146102515780637fd6f15c1461024c57806383d430d5146102475780638697d2c2146102425780638ceab9aa1461023d578063a49a1e7d14610238578063ac9650d814610233578063ad3cb1cc1461022e578063b0d1130214610229578063b1f0e7c714610224578063b45a1eb51461021f578063c6e6f5921461021a578063d0a64ddc14610215578063d83ad00c14610210578063e74b981b1461020b578063ee3bd5df14610206578063f04da65b14610201578063f45bf3d2146101fc5763f851a4400361000e576121e3565b6121a2565b612167565b612141565b612114565b6120ee565b6120c1565b6120a3565b612071565b61204d565b61201a565b611fd5565b611f5f565b611e64565b611c7b565b611a20565b611850565b61182c565b6117db565b611770565b6116e3565b6116c5565b6116ab565b611677565b61165c565b6115f3565b61136d565b6111de565b6111b6565b6110b9565b610f16565b610e95565b610e5b565b610e2f565b610caf565b610c95565b6107f9565b610565565b610500565b6104d7565b6104b1565b61030d565b6102dc565b5f9103126102d857565b5f80fd5b346102d8575f3660031901126102d857602060985460801c604051908152f35b6001600160801b038116036102d857565b346102d85760203660031901126102d85760043561032a816102fc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156104ac575f9161047d575b50335f908152610137602052604090206103a690612224565b916001600160801b036103c084516001600160801b031690565b161561046b57610414836103d661046795612a9b565b6104006103f3846103ee84516001600160801b031690565b61225d565b6001600160801b03168252565b335f9081526101376020526040902061227b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61049f915060203d6020116104a5575b61049781836112ec565b81019061220a565b5f61038d565b503d61048d565b612219565b346102d85760203660031901126102d85760206104cf6004356122ad565b604051908152f35b346102d8575f3660031901126102d857610201546040516001600160a01b039091168152602090f35b346102d8576003196020368201126102d857600435906001600160401b0382116102d85760809082360301126102d85761053f61054691600401612e1e565b9190612fb4565b61054c57005b610018613139565b6001600160a01b038116036102d857565b346102d85760603660031901126102d85760043561058281610554565b602435906044359061059382610554565b61059c33613269565b6105a4614666565b6105ac613b02565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af19485156104ac575f956107ae575b50335f9081526101376020526040902061062790612224565b926001600160801b0361064185516001600160801b031690565b161561074a57505061065282612a9b565b61067e61067161066187614213565b84516001600160801b031661328a565b6001600160801b03168352565b335f908152609c602052604090206106a09061069b905b546122ad565b6146f2565b6106c06106b484516001600160801b031690565b6001600160801b031690565b1161073857335f90815261013760205260409020610467957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610706919061227b565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610454565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa9182156104ac5761078c9261077d915f91610791575b50614213565b6001600160801b031690840152565b610652565b6107a89150833d85116104a55761049781836112ec565b5f610777565b6107c6919550833d85116104a55761049781836112ec565b935f61060e565b60609060031901126102d857600435906024356107e981610554565b906044356107f681610554565b90565b346102d857610807366107cd565b906001600160a01b0380831615610c8357610820613b02565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102d85760408051631d8557d760e01b815260049491905f81878183875af180156104ac57610c6a575b506001600160a01b0383165f9081526101376020526040902061089390612224565b6001600160801b0392836108ae83516001600160801b031690565b1615610c5a576108bd82612a9b565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa9788156104ac575f98610c29575b50602097888101956001600160401b039182806109368a516001600160401b031690565b1614610c1957908c92918751918c83806109626303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156104ac5761098e938e5f94610bf4575b5050516001600160801b03165b1690612bca565b966109ac6106958a60018060a01b03165f52609c60205260405f2090565b928389118015610be4575b610bd457908b6109f593926109d389516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa9182156104ac57670de0b6b3a764000094610a44948e5f95610ba7575b5050610a36610a28610a3c926126d8565b93516001600160401b031690565b936126d8565b921690612cc3565b1015610b99578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156104ac577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610b7695610aee93610b7b575b5050610ad16103f3610ac18c614213565b83516001600160801b031661225d565b6001600160a01b0386165f9081526101376020526040902061227b565b610af78261435f565b90610b35610b1a610b0785614213565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610b3f82866147fc565b610b498389614246565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610b9192903d106104a55761049781836112ec565b505f80610ab0565b835163185cfc6d60e11b8152fd5b610a3c929550610bca610a369282610a2893903d106104a55761049781836112ec565b959250508e610a17565b875163efda1a2760e01b81528590fd5b50610bed6122d3565b89116109b7565b6109879294509081610c1192903d106104a55761049781836112ec565b92908e61097a565b8651630709133160e01b81528490fd5b610c4c91985060603d606011610c53575b610c4481836112ec565b8101906132b9565b965f610912565b503d610c3a565b825163673f032f60e11b81528790fd5b80610c77610c7d92611288565b806102ce565b5f610871565b60405163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d85760206104cf6122d3565b346102d857610cbd366107cd565b91610cc733613269565b610cd082613269565b610cd8614330565b604092610d3284516323b872dd60e01b602082015233602482015230604482015283606482015260648152610d0c816112b6565b7f0000000000000000000000000000000000000000000000000000000000000000614d92565b610d3a613b02565b6001600160a01b038316928315610e1e578215610e0d5782610d616106b460985460801c90565b0190610d6b6123df565b8211610dfc57610de2610b1a9593610dbc86947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610db7610daf60209c9a6143e5565b9a8b93614213565b6144d5565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020614fe48339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d8576020610e49612310565b6040516001600160a01b039091168152f35b346102d8575f3660031901126102d85760206040517f6c3152ed991a2a6ec7359c31f742e79dd206dc9d7378f631119a96bee15f8b868152f35b346102d8575f3660031901126102d85760206001600160801b0360985416604051908152f35b9181601f840112156102d8578235916001600160401b0383116102d857602083818601950101116102d857565b60206003198201126102d857600435906001600160401b0382116102d857610f1291600401610ebb565b9091565b346102d857610f2436610ee8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1680156110a5575b6110935768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156104ac575f93611074575b50604051636f4fa30f60e01b8152938285600481335afa9081156104ac57610fe195610fdc945f93611041575b5050610fd59192810190612360565b9083613700565b6137e8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b610fd59350908161106692903d1061106d575b61105e81836112ec565b81019061234b565b915f610fc6565b503d611054565b61108c919350823d841161106d5761105e81836112ec565b915f610f99565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015610f55565b346102d8576110c7366107cd565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156104ac5782915f91611197575b501633036111855781610b7661115286867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966132f9565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6111b0915060203d60201161106d5761105e81836112ec565b5f61111a565b346102d8575f3660031901126102d8576065546040516001600160a01b039091168152602090f35b346102d85760203660031901126102d8576004356111fb81610554565b60018060a01b03165f52610137602052602060405f206040519061121e82611268565b54906001600160801b03918281169081835260801c84830152611246575b5116604051908152f35b61124f81612a9b565b61123c565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761128357604052565b611254565b6001600160401b03811161128357604052565b606081019081106001600160401b0382111761128357604052565b60a081019081106001600160401b0382111761128357604052565b608081019081106001600160401b0382111761128357604052565b90601f801991011681019081106001600160401b0382111761128357604052565b6040519061131a82611268565b565b6001600160401b03811161128357601f01601f191660200190565b9291926113438261131c565b9161135160405193846112ec565b8294818452818301116102d8578281602093845f960137010152565b6040806003193601126102d857600490813561138881610554565b6024356001600160401b0381116102d857366023820112156102d8576113b79036906024818701359101611337565b916113c06137f4565b8051926113f7846113e960209363439fab9160e01b858401528460248401526044830190611ed7565b03601f1981018652856112ec565b6113ff6137f4565b6114076138d4565b6001600160a01b038381168015929190879084156115be575b8415611550575b84156114ec575b50508215611456575b5050611447576100188383614a59565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac575f926114bf575b5050155f80611437565b6114de9250803d106114e5575b6114d681836112ec565b8101906124c7565b5f806114b5565b503d6114cc565b855163054fd4d560e41b81529294508391839182905afa9081156104ac5760039160ff915f91611523575b5016141591865f61142e565b6115439150843d8611611549575b61153b81836112ec565b810190614a40565b5f611517565b503d611531565b935050835163198ca60560e11b815282818981875afa9081156104ac5788917f6c3152ed991a2a6ec7359c31f742e79dd206dc9d7378f631119a96bee15f8b86915f916115a1575b50141593611427565b6115b89150853d87116104a55761049781836112ec565b5f611598565b5f80516020614fc48339815191525490945084906115ec906001600160a01b03165b6001600160a01b031690565b1493611420565b346102d8575f3660031901126102d8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361164a5760206040515f80516020614fc48339815191528152f35b60405163703e46dd60e11b8152600490fd5b346102d8575f3660031901126102d857602060405160028152f35b346102d8575f3660031901126102d8575f80516020614fc4833981519152546040516001600160a01b039091168152602090f35b346102d8575f3660031901126102d85760206104cf6123df565b346102d85760203660031901126102d85760206104cf600435612408565b346102d8575f3660031901126102d857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104ac576020915f91611753575b506040519015158152f35b61176a9150823d84116114e5576114d681836112ec565b5f611748565b346102d85760203660031901126102d85760043561178d81610554565b6117956138d4565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102d85760803660031901126102d85761046761180f6004356117fe81610554565b6064359060443590602435906124e9565b604080519384526020840192909252908201529081906060820190565b346102d8575f3660031901126102d857602061ffff60655460a01c16604051908152f35b346102d8576003196040368201126102d85760049081356001600160401b038082116102d85760a08285019383360301126102d8576024359081116102d85761189c9036908501610ebb565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102d85760405163837d444160e01b8152905f9082908183816118ef8c828f016125ed565b03925af180156104ac57611a0d575b50611907613b02565b61190f6129cd565b90811633141591826119de575b505090506119cd576044019160b0611934848461266b565b905004801580156119b5575b6119a55761195561194f6122d3565b916126c0565b11611996575060b0611967838361266b565b9050145f14611983576100189161197d9161266b565b906140b4565b610018916119909161266b565b90613e84565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506119c0848461266b565b905060b082021415611940565b604051634ca8886760e01b81528390fd5b611a0192506119fb611a05946119f388613b8d565b923691611337565b91613c67565b1590565b805f8061191c565b80610c77611a1a92611288565b5f6118fe565b346102d85760603660031901126102d857600435602435611a456044358284336124e9565b9192611a717f0000000000000000000000000000000000000000000000000000000000000000826123fb565b42108015611c73575b8015611c6b575b611c59577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611ac586611ac06106b46099546001600160801b031690565b61384d565b15611bc757611aff611ae4611ad986614213565b60995460801c61225d565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611b439190611b326080826112ec565b5190205f52609b60205260405f2090565b555f9360018311611b7c575b50505050611b5d8233614246565b604080519485526020850191909152830152339180606081015b0390a2005b611bbd92939450611b8d90886123fb565b6040805133602082019081529181019390935260608301829052608095860183529094909190611b3290826112ec565b555f808080611b4f565b611bcf613b02565b611c0b611bef611bde86614213565b609e546001600160801b031661225d565b6001600160801b03166001600160801b0319609e541617609e55565b611c40611c25611c1a85614213565b609e5460801c61225d565b6001600160801b03609e549181199060801b16911617609e55565b611c54611c4f84609f546123fb565b609f55565b611aff565b604051630e3d8e8d60e11b8152600490fd5b508215611a81565b508115611a7a565b346102d8576040806003193601126102d85760243590600435611c9d83610554565b611ca5613b02565b8015611e53576001600160a01b038316908115611e4257611cc5816122ad565b908115611e3157611cd582614b46565b611cde83614213565b60985460801c90611cee9161225d565b611d0d906001600160801b036098549181199060801b16911617609855565b611d1782336147fc565b609e54958660801c8281609f5490611d2e916123fb565b98611d3887614213565b611d4a916001600160801b031661328a565b611d6a906001600160801b03166001600160801b0319609e541617609e55565b611d73916123fb565b611d7c90614213565b611d9b906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611dcc6080826112ec565b519020611de1905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611e2833614d12565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346102d857611b777f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611e9636610ee8565b9290611ea06138d4565b60405191829160208352339560208401916125cd565b5f5b838110611ec75750505f910152565b8181015183820152602001611eb8565b90602091611ef081518092818552858086019101611eb6565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611f315750505050505090565b9091929394958480611f4f600193603f198682030187528a51611ed7565b9801930193019194939290611f21565b346102d85760203660031901126102d8576001600160401b036004358181116102d857366023820112156102d85780600401359182116102d8573660248360051b830101116102d857610467916024611fb89201612833565b60405191829182611efc565b9060206107f6928181520190611ed7565b346102d8575f3660031901126102d857610467604051611ff481611268565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611ed7565b346102d8575f3660031901126102d857612032614330565b61203a6128e0565b60015f80516020614fe483398151915255005b346102d8575f3660031901126102d8576020610e496129cd565b801515036102d857565b346102d85760403660031901126102d85761001860043561209181610554565b6024359061209e82612067565b612a03565b346102d85760203660031901126102d85760206104cf60043561435f565b346102d85760203660031901126102d8576100186004356120e181610554565b6120e96138d4565b61442c565b346102d8575f3660031901126102d85760206001600160801b0360995416604051908152f35b346102d85760203660031901126102d85761001860043561213481610554565b61213c6138d4565b614473565b346102d8575f3660031901126102d85760206001600160801b03609e5416604051908152f35b346102d85760203660031901126102d85760043561218481610554565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102d85760203660031901126102d8576004356121bf81610554565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b346102d8575f3660031901126102d8575f546040516001600160a01b039091168152602090f35b908160209103126102d8575190565b6040513d5f823e3d90fd5b9060405161223181611268565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161227657565b612249565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816122c557505090565b916107f69260801c90612cc3565b6122db613612565b6099546001600160801b036122f18183166122ad565b90609e5416019060801c01908181115f1461230a570390565b50505f90565b61016a546001600160a01b031680156123265790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102d857516107f681610554565b906020828203126102d85781356001600160401b03928382116102d85701916060838303126102d857604051926123968461129b565b80358452602081013561ffff811681036102d857602085015260408101359182116102d857019080601f830112156102d8578160206123d793359101611337565b604082015290565b609d54806107f657505f1990565b9060b0820180921161227657565b9190820180921161227657565b6001600160801b036099541661241c614b04565b90810180911161227657811061244f57612440609f5461243a613864565b906123fb565b111561244a575f90565b5f1990565b609a90609a549182915f905b8482106124755750505081101561246f5790565b505f1990565b909193808316906001818518811c8301809311612276575f8790525f80516020614fa48339815191528301546001600160a01b03168410156124bc575050935b919061245b565b9095910192506124b5565b908160209103126102d857516107f681612067565b9190820391821161227657565b604080516001600160a01b0390921660208301908152908201939093526060810182905290919061252781608081015b03601f1981018352826112ec565b5190205f52609b60205260405f2054918215612591576001600160801b036099541690612552614b04565b91820180921161227657839183101561257f579161256f92613967565b90915b8281039081116122765792565b509061258a916138e7565b9091612572565b5050505f905f905f90565b9035601e19823603018112156102d85701602081359101916001600160401b0382116102d85781360383136102d857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06107f692602081528235602082015260208301356040820152612629612619604085018561259c565b84606085015260c08401916125cd565b9061265c61265161263d606087018761259c565b601f198587038101608087015295916125cd565b94608081019061259c565b939092828603019101526125cd565b903590601e19813603018212156102d857018035906001600160401b0382116102d8576020019181360383136102d857565b634e487b7160e01b5f52601260045260245ffd5b81156126bb570490565b61269d565b90670de0b6b3a7640000918083029283040361227657565b90670de0b6b3a76400009182810292818404149015171561227657565b6001600160401b0381116112835760051b60200190565b90612716826126f5565b61272360405191826112ec565b8281528092612734601f19916126f5565b01905f5b82811061274457505050565b806060602080938501015201612738565b634e487b7160e01b5f52603260045260245ffd5b9082101561278057610f129160051b81019061266b565b612755565b908092918237015f815290565b3d156127bc573d906127a38261131c565b916127b160405193846112ec565b82523d5f602084013e565b606090565b6020818303126102d8578051906001600160401b0382116102d8570181601f820112156102d85780516127f38161131c565b9261280160405194856112ec565b818452602082840101116102d8576107f69160208085019101611eb6565b80518210156127805760209160051b010190565b91909161283f8361270c565b925f5b81811061284e57505050565b5f8061285b838587612769565b6040939161286d855180938193612785565b0390305af49061287b612792565b91156128a2575090600191612890828861281f565b5261289b818761281f565b5001612842565b9060448151106102d8576128dc6128c7600492838101516024809183010191016127c1565b925162461bcd60e51b81529283928301611fc4565b0390fd5b47633b9aca0081106129ca57604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19182156104ac575f926129a9575b506001600160ff1b03821161299057907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db9161297682612fb4565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b6129c391925060203d6020116104a55761049781836112ec565b905f61293b565b50565b60d2546001600160a01b0316806107f657507f000000000000000000000000000000000000000000000000000000000000000090565b610201546001600160a01b03919082163303611185576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612a96576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fffe80d6d91bb72bd036e4be8badcf33d7c8e13b2a0aaab3dc3aef76f6b1f786a60203392a3565b505050565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91612b31575b5060208201916001600160801b03918284511691828214612b2a5783612b1d612b18612b25958584865116612cc3565b614213565b169052614213565b169052565b5050505050565b612b4a915060203d6020116104a55761049781836112ec565b5f612ae8565b90808202905f1981840990828083109203918083039214612bbf576127109082821115612bad577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612c2d57670de0b6b3a76400009082821115612bad577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107f692506126b1565b9091828202915f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102d857805191604060208301519201516107f681612067565b81835290916001600160fb1b0383116102d85760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102d85760408301526040810135612daa81610554565b6001600160a01b031660608381019190915281013536829003601e19018112156102d85701602081359101906001600160401b0381116102d8578060051b360382136102d85760a0836080806107f69601520191612d57565b9190915f838201938412911290801582169115161761227657565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612e499060048301612d7b565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ac575f915f905f95612f6f575b508415612f1c5781612e93612310565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612f1557509060205f92600460405180958193634641257d60e01b83525af19081156104ac57612ef0925f92612ef4575b50612e03565b9190565b612f0e91925060203d6020116104a55761049781836112ec565b905f612eea565b9081612f22575b50509190565b803b156102d857604051636ee3193160e11b815260048101929092525f908290602490829084905af180156104ac57612f5c575b80612f1c565b80610c77612f6992611288565b5f612f56565b91945050612f95915060603d606011612f9d575b612f8d81836112ec565b810190612d36565b93905f612e83565b503d612f83565b600160ff1b8114612276575f0390565b80156129ca57612fc96106b460985460801c90565b5f82126130965781612fda916123fb565b90612fe7610b1a83614213565b612ffc6065549161ffff8360a01c1690612b50565b8015612a9657807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479361303a6106b46098546001600160801b031690565b8061308057505061298b90925b6001600160a01b03169161305b84846144d5565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b61298b9261309092039084612cc3565b92613047565b906130a090612fa4565b6130b56106b4609e546001600160801b031690565b806130d5575b50806130c5575050565b612b18610b1a9161131a936124dc565b906131307f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91613120611bef61311561310e88886123fb565b8785612cc3565b808094039603614213565b6040519081529081906020820190565b0390a15f6130bb565b609954906001600160801b0382169182156132635760801c61317461316582613160613612565b6124dc565b61316e856122ad565b90614521565b90811561325c576131848261435f565b93841561325457826131d1611ae4612b1861131a96610b1a966131cc6131b0612b188d6132499a6124dc565b6001600160801b03166001600160801b03196099541617609955565b6123fb565b6131db8187614591565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a1612b1861322d61321c88614213565b6098546001600160801b031661225d565b6001600160801b03166001600160801b03196098541617609855565b60985460801c61225d565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f908152610202602052604090205460ff1661118557565b9190916001600160801b038080941691160191821161227657565b51906001600160401b03821682036102d857565b908160609103126102d8576123d760408051926132d58461129b565b80516132e0816102fc565b84526132ee602082016132a5565b6020850152016132a5565b92906001600160a01b039081811615610c8357613314613b02565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102d857604094855193631d8557d760e01b85526004945f81878183895af180156104ac576135ff575b506001600160a01b0388165f9081526101376020526040902061338790612224565b906001600160801b036133a183516001600160801b031690565b16156135ef576133b082612a9b565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156104ac576135d0575b508651936303d1689d60e11b9788865260209182878061342a888c83019190602083019252565b0381845afa9687156104ac575f976135b1575b50869961345d6106958d60018060a01b03165f52609c60205260405f2090565b881180156135a1575b6135915790836134a39261348187516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa9889156104ac575f859488946134e89c613574575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156104ac57610ac161352f94613512936103f39361131a9a613556575b5050614213565b6001600160a01b0388165f9081526101376020526040902061227b565b61355161353b8361435f565b809761354c610b1a610b0787614213565b6147fc565b614246565b8161356c92903d106104a55761049781836112ec565b505f8061350b565b61358a90873d89116104a55761049781836112ec565b505f6134bd565b825163efda1a2760e01b81528990fd5b506135aa6122d3565b8811613466565b6135c9919750833d85116104a55761049781836112ec565b955f61343d565b6135e89060603d606011610c5357610c4481836112ec565b505f613403565b875163673f032f60e11b81528690fd5b80610c7761360c92611288565b5f613365565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa9081156104ac575f916136e3575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac576107f6935f936136c4575b50506123fb565b6136db929350803d106104a55761049781836112ec565b905f806136bd565b6136fa9150833d85116104a55761049781836112ec565b5f613669565b61370861488f565b604083015161371561488f565b6001600160a01b0382168015610c83576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061376e33946020830190611ed7565b0390a260208301519261377f61488f565b61271061ffff8516116137d6576137ce9361379c6137c193614473565b6065805461ffff60a01b191660a09290921b61ffff60a01b16919091179055516148d0565b6137c9614900565b61492b565b61131a61495a565b604051638a81d3b360e01b8152600490fd5b61131a906120e961488f565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613832575b505061164a57565b5f80516020614fc48339815191525416141590505f8061382a565b90613856614b04565b918201809211612276571090565b61386c613612565b6099548060801c820391821161227657816138906001600160801b038093166122ad565b90816138b6575b5050811561230a576107f6916138b191609e541690614521565b614b46565b91925090818111156138cc57035b905f80613897565b50505f6138c4565b5f546001600160a01b0316330361118557565b6138ef613864565b91609f54928301809311612276578083111561393957613910920390614521565b90609e548060801c80155f146139265750508190565b6001600160801b036107f6921684612cc3565b5050505f905f90565b9060405161394f81611268565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613afa575b613aed5783613ab7575f5b609a5f526001600160a01b03166139ac5f80516020614fa48339815191528601613942565b80519097906139c3906001600160a01b03166115e0565b986139e86139dc6020809b01516001600160601b031690565b6001600160601b031690565b948381108015613aad575b613a9b5791600193979a95613a12613a1e939488035b838c0390614521565b80920198870391612cc3565b01970193808611801590613a91575b613a8657609a5f528290613a4f5f80516020614fa48339815191528701613942565b805190890151969992966001600160a01b039091169460019392613a1e9290916001600160601b0390911690613a12908803613a09565b945050509250509190565b5081851015613a2d565b60405163e8722f8f60e01b8152600490fd5b50808b11156139f3565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613987565b505093505050505f905f90565b50841561397c565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91613b6e575b50613b5c57565b60405163e775715160e01b8152600490fd5b613b87915060203d6020116114e5576114d681836112ec565b5f613b55565b604290467f000000000000000000000000000000000000000000000000000000000000000003613c3b5760d354905b613bd3613bcc604083018361266b565b3691611337565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613c1e816112d1565b5190206040519161190160f01b8352600283015260228201522090565b613c43614b7d565b90613bbc565b60041115613c5357565b634e487b7160e01b5f52602160045260245ffd5b613c718383614c4a565b50613c7e81959295613c49565b159384613d1a575b508315613c94575b50505090565b5f929350908291604051613ccc816125196020820194630b135d3f60e11b998a87526024840152604060448401526064830190611ed7565b51915afa90613cd9612792565b82613d0c575b82613cef575b50505f8080613c8e565b613d049192506020808251830101910161220a565b145f80613ce5565b915060208251101591613cdf565b6001600160a01b0383811691161493505f613c86565b90613d3a826126f5565b613d4760405191826112ec565b8281528092613d58601f19916126f5565b0190602036910137565b906030116102d85790603090565b906090116102d85760300190606090565b9060b0116102d85760900190602090565b909392938483116102d85784116102d8578101920390565b6020908361131a939594956040519683613dcd8995518092888089019101611eb6565b84019185830137015f838201520380855201836112ec565b359060208110613df3575090565b5f199060200360031b1b1690565b9160206107f69381815201916125cd565b9192613e3c613e2c613e4a93608086526080860190611ed7565b6020958582036020870152611ed7565b908382036040850152611ed7565b906060818303910152602080845192838152019301915f5b828110613e70575050505090565b835185529381019392810192600101613e62565b613e8c614c84565b6060906060905f809460b0810492613ea384613d30565b965f905b858210613fc257506001600160a01b03947f00000000000000000000000000000000000000000000000000000000000000009450613f1e935060209250613eee91506126c0565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af180156104ac57613fa3575b5016613f5b614ce9565b813b156102d8575f8094613f856040519788968795869463c82655b760e01b865260048601613e12565b03925af180156104ac57613f965750565b80610c7761131a92611288565b613fbb9060203d6020116114e5576114d681836112ec565b505f613f51565b614047614017614022614004613ffb7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c6123ed565b80998989613d92565b92909a614011848d613d62565b91613daa565b9a614011838c613d70565b988b6140418661403b6140358686613d81565b90613de5565b9261281f565b52613d62565b9061405760405192839283613e01565b0390a160010183613ea7565b929461409c670de0b6b3a76400009661408e608097946140aa969b9a9b60a0895260a08901916125cd565b908682036020880152611ed7565b9184830360408601526125cd565b9460608201520152565b906140bd614c84565b6140c78183613d62565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af180156104ac576141f4575b501690614159614ce9565b9161417261403561416a8489613d70565b949098613d81565b95813b156102d8575f809461419f604051998a9687958694630cac9f3160e01b86528c8c60048801614063565b03925af19283156104ac577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936141e1575b5061298b60405192839283613e01565b80610c776141ee92611288565b5f6141d1565b61420c9060203d6020116114e5576114d681836112ec565b505f61414e565b6001600160801b0390818111614227571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b9061424f614330565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa9384156104ac576142ee946142e9925f91614311575b508411614304575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836112ec565b614d92565b61131a60015f80516020614fe483398151915255565b61430c614c84565b6142b4565b61432a915060203d6020116104a55761049781836112ec565b5f6142ac565b5f80516020614fe4833981519152600281541461434d5760029055565b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b0382168115801561438e575b156143815750905090565b6107f69260801c91612cc3565b508015614376565b6098546001600160801b03811690816143b3575050633b9aca0090565b60801c6143c08183612c3e565b9181156126bb57633b9aca00096143d45790565b60018101809111156107f657612249565b6098546001600160801b0381169082158015614424575b1561440657505090565b60801c90614415828285612cc3565b9282156126bb57096143d45790565b5081156143fc565b61020180546001600160a01b0319166001600160a01b03929092169182179055337fdd44becc667b27d303085374b2760e783af69bbc9db209947ab811a6f1bbc58b5f80a3565b61447b613b02565b6001600160a01b031680156144c357606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6144de82614213565b609854906144f66001600160801b039182841661328a565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b908082101561452e575090565b905090565b609a549068010000000000000000821015611283576001820180609a5582101561278057609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614fa483398151915290910155565b9190918015801561465e575b61464c576145a9614b04565b908101809111612276576001600160a01b0380821161462c576001600160601b039081851161460c579061131a93946145f6614607936145e761130d565b95166001600160a01b03168552565b166001600160601b03166020830152565b614533565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561459d565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f916146d3575b50156146c157565b604051630a62fbdb60e11b8152600490fd5b6146ec915060203d6020116114e5576114d681836112ec565b5f6146b9565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156104ac5761478d936001600160401b03610987604061476c946020975f916147dd575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156104ac575f916147c4575090565b6107f6915060203d6020116104a55761049781836112ec565b6147f6915060603d606011610c5357610c4481836112ec565b5f61475d565b60018060a01b03165f52609c60205260405f20908154818103908111612276576148269255614213565b609854906001600160801b03908183160316906001600160801b03191617609855565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca00606480830191909152815261131a916142e9826112b6565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156148be57565b604051631afcd79f60e31b8152600490fd5b6148d861488f565b80156148ee57600181016148e95750565b609d55565b6040516331278a8760e01b8152600490fd5b61490861488f565b670de0b6b3a76400006149196123df565b106148ee57614926614b7d565b60d355565b61493361488f565b6001600160a01b0316806149445750565b61016a80546001600160a01b0319169091179055565b61496261488f565b61496a61488f565b61497261488f565b60015f80516020614fe48339815191525561498b613b02565b3015610c8357633b9aca008060985460801c016149a66123df565b8111614a2e576149c0610b1a6149ba614396565b92614213565b6149ca81306144d5565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a361131a30337f0000000000000000000000000000000000000000000000000000000000000000614849565b6040516304ffa0ff60e51b8152600490fd5b908160209103126102d8575160ff811681036102d85790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614ae3575b50614aa957604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614fc48339815191528403614aca5761131a929350614e03565b604051632a87526960e21b815260048101859052602490fd5b614afd91955060203d6020116104a55761049781836112ec565b935f614a83565b609a5480614b1157505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166115e0565b609e54908160801c81158015614b75575b15614b625750905090565b6001600160801b036107f6931691612cc3565b508015614b57565b6e5661756c7456616c696461746f727360881b6020604051614b9e81611268565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176112835760405251902090565b8151919060418303614c7a57614c739250602082015190606060408401519301515f1a90614ea5565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102d8575f809160246040518094819363a3066aab60e01b83523060048401525af180156104ac57614ce05750565b61131a90611288565b604051600160f81b60208201525f60218201523060601b602c820152602081526107f681611268565b60018060a01b0381165f5261013760205260405f209060405191614d3583611268565b54906001600160801b03918281169081855260801c602085015215612a965761069b610695614d8892614d66613b02565b614d6f86612a9b565b6001600160a01b03165f908152609c6020526040902090565b9151161161073857565b5f80614dba9260018060a01b03169360208151910182865af1614db3612792565b9083614f40565b8051908115159182614de8575b5050614dd05750565b60249060405190635274afe760e01b82526004820152fd5b614dfb92506020809183010191016124c7565b155f80614dc7565b90813b15614e84575f80516020614fc483398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614e69576129ca91614f27565b505034614e7257565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614f1c579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156104ac575f516001600160a01b03811615614f1257905f905f90565b505f906001905f90565b5050505f9160039190565b5f806107f693602081519101845af4614f3e612792565b915b90614f675750805115614f5557805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614f9a575b614f78575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614f7056fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220ec6f6df673d7dbf00de71fc227d5de317bb95b6881bb8bd514d8065c072c473964736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoErc20Vault.json b/test/shared/artifacts/GnoErc20Vault.json deleted file mode 100644 index ede533e8..00000000 --- a/test/shared/artifacts/GnoErc20Vault.json +++ /dev/null @@ -1,1836 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoErc20Vault", - "sourceName": "contracts/vaults/gnosis/GnoErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x610220346200023a5762005d8d38819003601f8101601f191683016001600160401b038111848210176200023e57839282916040528339610140928391810103126200023a57620000508162000252565b916200005f6020830162000252565b906200006e6040840162000252565b936200007d6060850162000252565b6200008b6080860162000252565b906200009a60a0870162000252565b92620000a960c0880162000252565b94620000b860e0890162000252565b9561010099620000ca8b8b0162000252565b98610120809b01519460805260a05260c0523060e052620000ea62000267565b468a52885246815261016091825260018060a01b038061018094168452806101a0951685526101c09586526101e0961686526102009687526200012c62000267565b60405197615a86998a620003078b396080518a8181611ad901528181611cad015281816133e1015281816136eb0152613777015260a0518a611815015260c0518a8181613da2015281816146b6015281816148d20152615294015260e0518a818161199501526140830152518961298d0152518861300d0152518761438e01525186611e530152518581816103d3015281816108fd01528181610bf901528181613044015281816139270152613a30015251848181610cb801528181611524015281816138ab0152613aef01525183818161296801526134290152518281816110c001528181613d51015281816147200152818161491c01528181614a2d015261500a01525181612f2e0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200023a57565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620002f4576001600160401b036002600160401b031982821601620002b557505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d1141461033f578063066055e01461033a57806306fdde031461033557806307a2d13a14610330578063095ea7b31461032b57806318160ddd146102f45780631a7ff55314610326578063201b9eb51461032157806323b872dd1461031c5780632999ad3f146103175780632cdf7401146103125780632e2d29841461030d578063313ce567146103085780633229fa951461030357806333194c0a146102fe5780633644e515146102f95780633a98ef39146102f4578063439fab91146102ef57806343e82a79146102ea57806346904840146102e55780634ec96b22146102e05780634f1ef286146102db57806352d1902d146102d657806354fd4d50146102d15780635c60da1b146102cc5780635cfc1a51146102c757806360d60e6e146102c257806370a082311461025457806372b410a8146102bd578063754c3888146102b857806376b58b90146102b35780637ecebe00146102ae5780637fd6f15c146102a957806383d430d5146102a45780638697d2c21461029f5780638ceab9aa1461029a57806395d89b4114610295578063a49a1e7d14610290578063a9059cbb1461028b578063ac9650d814610286578063ad3cb1cc14610281578063b0d113021461027c578063b1f0e7c714610277578063c6e6f59214610272578063d505accf1461026d578063d83ad00c14610268578063dd62ed3e14610263578063e74b981b1461025e578063ee3bd5df14610259578063f04da65b146102545763f851a4400361000e57612814565b611a73565b6127ee565b6127c1565b612762565b61273c565b612527565b6124fe565b6124e4565b6124b1565b61246c565b612407565b612366565b612314565b612270565b612087565b611e27565b611c57565b611c33565b611bf8565b611ba7565b611b3b565b611aae565b611a55565b611a3b565b611a07565b6119ec565b611983565b6116fd565b61161a565b6115f2565b6114f5565b6112d7565b6107f6565b611262565b611228565b6111fc565b6111e1565b611073565b611059565b610bcf565b610af3565b610894565b61081c565b610754565b61071d565b610657565b610383565b610352565b5f91031261034e57565b5f80fd5b3461034e575f36600319011261034e57602060cf5460801c604051908152f35b6001600160801b0381160361034e57565b3461034e57602036600319011261034e576004356103a081610372565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610522575f916104f3575b50335f90815261016e6020526040902061041c90612856565b916001600160801b0361043684516001600160801b031690565b16156104e15761048a8361044c6104dd9561302f565b6104766104698461046484516001600160801b031690565b61288f565b6001600160801b03168252565b335f90815261016e602052604090206128a8565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610515915060203d60201161051b575b61050d81836105dc565b81019061283c565b5f610403565b503d610503565b61284b565b90600182811c92168015610555575b602083101461054157565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610536565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761058e57604052565b61055f565b6001600160401b03811161058e57604052565b60a081019081106001600160401b0382111761058e57604052565b608081019081106001600160401b0382111761058e57604052565b90601f801991011681019081106001600160401b0382111761058e57604052565b5f5b83811061060e5750505f910152565b81810151838201526020016105ff565b90602091610637815180928185528580860191016105fd565b601f01601f1916010190565b90602061065492818152019061061e565b90565b3461034e575f36600319011261034e576040515f805461067681610527565b808452906020906001908181169081156106f357506001146106af575b6104dd856106a3818703826105dc565b60405191829182610643565b5f80805293505f805160206159b18339815191525b8385106106e0575050505081016020016106a3826104dd610693565b80548686018401529382019381016106c4565b8695506104dd969350602092506106a394915060ff191682840152151560051b8201019293610693565b3461034e57602036600319011261034e57602061073b6004356128d1565b604051908152f35b6001600160a01b0381160361034e57565b3461034e57604036600319011261034e5760043561077181610743565b6001600160a01b038116906024359082156107e4576107ac8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b3461034e575f36600319011261034e5760206001600160801b0360cf5416604051908152f35b3461034e5760031960203682011261034e57600435906001600160401b03821161034e57608090823603011261034e5761085b610862916004016133b0565b9190613546565b61086857005b610870615388565b8061087757005b5f906040519081525f805160206159f183398151915260203092a3005b3461034e57606036600319011261034e576004356108b181610743565b60243590604435906108c282610743565b6108ca6136d0565b6108d261375c565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af1948515610522575f95610ad4575b50335f90815261016e6020526040902061094d90612856565b926001600160801b0361096785516001600160801b031690565b1615610a705750506109788261302f565b6109a4610997610987876137e7565b84516001600160801b03166128f7565b6001600160801b03168352565b335f90815260d3602052604090206109c6906109c1905b546128d1565b613888565b6109e66109da84516001600160801b031690565b6001600160801b031690565b11610a5e57335f90815261016e602052604090206104dd957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610a2c91906128a8565b604080516001600160a01b039586168152602081018790529081019190915292166060830152339180608081016104ca565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561052257610ab292610aa3915f91610ab7575b506137e7565b6001600160801b031690840152565b610978565b610ace9150833d851161051b5761050d81836105dc565b5f610a9d565b610aec919550833d851161051b5761050d81836105dc565b935f610934565b3461034e57606036600319011261034e57600435610b1081610743565b60243590610b1d82610743565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610b6d575b610b6184610b5c858883614c23565b613992565b60405160018152602090f35b919093818503948511610ba1575f928352600260209081526040808520338652909152909220939093559180610b61610b4d565b61287b565b606090600319011261034e5760043590602435610bc281610743565b9060443561065481610743565b3461034e57610bdd36610ba6565b906001600160a01b03808316156107e457610bf661375c565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561034e5760408051631d8557d760e01b815260049491905f81878183875af1801561052257611040575b506001600160a01b0383165f90815261016e60205260409020610c6990612856565b6001600160801b039283610c8483516001600160801b031690565b161561103057610c938261302f565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610522575f98610fff575b50602097888101956001600160401b03918280610d0c8a516001600160401b031690565b1614610fef57908c92918751918c8380610d386303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561052257610d64938e5f94610fca575b5050516001600160801b03165b169061315e565b96610d826109bb8a60018060a01b03165f5260d360205260405f2090565b928389118015610fba575b610faa57908b610dcb9392610da989516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561052257670de0b6b3a764000094610e1a948e5f95610f7d575b5050610e0c610dfe610e1292612d03565b93516001600160401b031690565b93612d03565b921690613257565b1015610f6f578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610522577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610f4c95610ec493610f51575b5050610ea7610469610e978c6137e7565b83516001600160801b031661288f565b6001600160a01b0386165f90815261016e602052604090206128a8565b610ecd82614af4565b90610f0b610ef0610edd856137e7565b60cf5460801c036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610f1582866154b8565b610f1f8389614a0f565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610f6792903d1061051b5761050d81836105dc565b505f80610e86565b835163185cfc6d60e11b8152fd5b610e12929550610fa0610e0c9282610dfe93903d1061051b5761050d81836105dc565b959250508e610ded565b875163efda1a2760e01b81528590fd5b50610fc3612912565b8911610d8d565b610d5d9294509081610fe792903d1061051b5761050d81836105dc565b92908e610d50565b8651630709133160e01b81528490fd5b61102291985060603d606011611029575b61101a81836105dc565b81019061382e565b965f610ce8565b503d611010565b825163673f032f60e11b81528790fd5b8061104d61105392610593565b80610344565b5f610c47565b3461034e575f36600319011261034e57602061073b612912565b3461034e5761108136610ba6565b9161108a613e19565b6040926110e484516323b872dd60e01b6020820152336024820152306044820152836064820152606481526110be816105a6565b7f0000000000000000000000000000000000000000000000000000000000000000614c9f565b6110ec61375c565b6001600160a01b0383169283156111d05782156111bf57826111136109da60cf5460801c90565b019061111d6129fe565b82116111ae57611194610ef0959361116e86947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461116961116160209c9a614b7a565b9a8b936137e7565b615320565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020615a318339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b3461034e575f36600319011261034e57602060405160128152f35b3461034e575f36600319011261034e57602061121661294f565b6040516001600160a01b039091168152f35b3461034e575f36600319011261034e5760206040517fd7358ee43135ceaf16fc3a6da49b8f2795ad16de0cf7f569aa7b9b1e67532fc48152f35b3461034e575f36600319011261034e57602061073b61298a565b9181601f8401121561034e578235916001600160401b03831161034e576020838186019501011161034e57565b602060031982011261034e57600435906001600160401b03821161034e576112d39160040161127c565b9091565b3461034e576112e5366112a9565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c1680156114e1575b6114d05768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020908185600481335afa948515610522575f956114b1575b508351636f4fa30f60e01b8152908282600481335afa918215610522575f92611482575b50830194828487031261034e5783356001600160401b039485821161034e570160a08188031261034e576113b4611690565b93813585526113c48183016129d4565b908501528581013585811161034e57876113df9183016129e3565b86850152606081013585811161034e57876113fb9183016129e3565b6060850152608081013594851161034e577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2966114469561143c92016129e3565b6080840152613fb9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff0000000000000000191690555160028152602090a1005b6114a3919250833d85116114aa575b61149b81836105dc565b8101906129bf565b905f611382565b503d611491565b6114c9919550823d84116114aa5761149b81836105dc565b935f61135e565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101561131b565b3461034e5761150336610ba6565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105225782915f916115d3575b501633036115c15781610f4c61158e86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613a12565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6115ec915060203d6020116114aa5761149b81836105dc565b5f611556565b3461034e575f36600319011261034e57609c546040516001600160a01b039091168152602090f35b3461034e57602036600319011261034e5760043561163781610743565b60018060a01b03165f5261016e602052602060405f206040519061165a82610573565b54906001600160801b03918281169081835260801c84830152611682575b5116604051908152f35b61168b8161302f565b611678565b6040519061169d826105a6565b565b6040519061169d82610573565b6001600160401b03811161058e57601f01601f191660200190565b9291926116d3826116ac565b916116e160405193846105dc565b82948184528183011161034e578281602093845f960137010152565b60408060031936011261034e57600490813561171881610743565b6024356001600160401b03811161034e573660238201121561034e5761174790369060248187013591016116c7565b91611750614079565b8051926117878461177960209363439fab9160e01b85840152846024840152604483019061061e565b03601f1981018652856105dc565b61178f614079565b611797614159565b6001600160a01b0383811680159291908790841561194e575b84156118e0575b841561187c575b505082156117e6575b50506117d7576100188383615055565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610522575f9261184f575b5050155f806117c7565b61186e9250803d10611875575b61186681836105dc565b810190612af3565b5f80611845565b503d61185c565b855163054fd4d560e41b81529294508391839182905afa9081156105225760039160ff915f916118b3575b5016141591865f6117be565b6118d39150843d86116118d9575b6118cb81836105dc565b810190615040565b5f6118a7565b503d6118c1565b935050835163198ca60560e11b815282818981875afa9081156105225788917fd7358ee43135ceaf16fc3a6da49b8f2795ad16de0cf7f569aa7b9b1e67532fc4915f91611931575b501415936117b7565b6119489150853d871161051b5761050d81836105dc565b5f611928565b5f805160206159d183398151915254909450849061197c906001600160a01b03165b6001600160a01b031690565b14936117b0565b3461034e575f36600319011261034e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036119da5760206040515f805160206159d18339815191528152f35b60405163703e46dd60e11b8152600490fd5b3461034e575f36600319011261034e57602060405160028152f35b3461034e575f36600319011261034e575f805160206159d1833981519152546040516001600160a01b039091168152602090f35b3461034e575f36600319011261034e57602061073b6129fe565b3461034e57602036600319011261034e57602061073b600435612a27565b3461034e57602036600319011261034e57600435611a9081610743565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461034e575f36600319011261034e57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610522576020915f91611b1e575b506040519015158152f35b611b359150823d84116118755761186681836105dc565b5f611b13565b3461034e57602036600319011261034e57600435611b5881610743565b611b60614159565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461034e57608036600319011261034e576104dd611bdb600435611bca81610743565b606435906044359060243590612b14565b604080519384526020840192909252908201529081906060820190565b3461034e57602036600319011261034e57600435611c1581610743565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461034e575f36600319011261034e57602061ffff609c5460a01c16604051908152f35b3461034e5760031960403682011261034e5760049081356001600160401b0380821161034e5760a082850193833603011261034e5760243590811161034e57611ca3903690850161127c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561034e5760405163837d444160e01b8152905f908290818381611cf68c828f01612c18565b03925af1801561052257611e14575b50611d0e61375c565b611d16612ff8565b9081163314159182611de5575b50509050611dd4576044019160b0611d3b8484612c96565b90500480158015611dbc575b611dac57611d5c611d56612912565b91612ceb565b11611d9d575060b0611d6e8383612c96565b9050145f14611d8a5761001891611d8491612c96565b906148b0565b61001891611d9791612c96565b90614680565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611dc78484612c96565b905060b082021415611d47565b604051634ca8886760e01b81528390fd5b611e089250611e02611e0c94611dfa88614388565b9236916116c7565b91614463565b1590565b805f80611d23565b8061104d611e2192610593565b5f611d05565b3461034e57606036600319011261034e57600435602435611e4c604435828433612b14565b9192611e787f000000000000000000000000000000000000000000000000000000000000000082612a1a565b4210801561207f575b8015612077575b612065577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611ecc86611ec76109da60d0546001600160801b031690565b6140d2565b15611fd357611f06611eeb611ee0866137e7565b60d05460801c61288f565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611f4a9190611f396080826105dc565b5190205f5260d260205260405f2090565b555f9360018311611f83575b50505050611f648233614a0f565b604080519485526020850191909152830152339180606081015b0390a2005b611fc992939450611f949088612a1a565b60408051336020820190815291810193909352606083018290529094909190611f399082608081015b039081018352826105dc565b555f808080611f56565b611fdb61375c565b612017611ffb611fea866137e7565b60d5546001600160801b031661288f565b6001600160801b03166001600160801b031960d554161760d555565b61204c612031612026856137e7565b60d55460801c61288f565b6001600160801b0360d5549181199060801b1691161760d555565b61206061205b8460d654612a1a565b60d655565b611f06565b604051630e3d8e8d60e11b8152600490fd5b508215611e88565b508115611e81565b3461034e5760408060031936011261034e57602435906004356120a983610743565b6120b161375c565b801561225f576001600160a01b03831690811561224e576120d1816128d1565b90811561223d576120e182615154565b6120ea836137e7565b60cf5460801c906120fa9161288f565b612119906001600160801b0360cf549181199060801b1691161760cf55565b61212382336154b8565b60d554958660801c828160d6549061213a91612a1a565b98612144876137e7565b612156916001600160801b03166128f7565b612176906001600160801b03166001600160801b031960d554161760d555565b61217f91612a1a565b612188906137e7565b6121a7906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906121d86080826105dc565b5190206121ed905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a361223433613992565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461034e575f36600319011261034e576040515f6001805461229181610527565b80855291602091600181169081156106f357506001146122bb576104dd856106a3818703826105dc565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510612301575050505081016020016106a3826104dd610693565b80548686018401529382019381016122e5565b3461034e57611f7e7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf612346366112a9565b9290612350614159565b6040519182916020835233956020840191612bf8565b3461034e57604036600319011261034e5761239060043561238681610743565b6024359033614c23565b61239933613992565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106123d95750505050505090565b90919293949584806123f7600193603f198682030187528a5161061e565b98019301930191949392906123c9565b3461034e57602036600319011261034e576001600160401b0360043581811161034e573660238201121561034e57806004013591821161034e573660248360051b8301011161034e576104dd9160246124609201612e5e565b604051918291826123a4565b3461034e575f36600319011261034e576104dd60405161248b81610573565b60058152640352e302e360dc1b602082015260405191829160208352602083019061061e565b3461034e575f36600319011261034e576124c9613e19565b6124d1612f0b565b60015f80516020615a3183398151915255005b3461034e575f36600319011261034e576020611216612ff8565b3461034e57602036600319011261034e57602061073b600435614af4565b60ff81160361034e57565b3461034e5760e036600319011261034e5760043561254481610743565b60243561255081610743565b6044359060643592608435906125658261251c565b6001600160a01b038381169590929086156107e45742811061272a576020915f91611fbd61265889878a61261b61259a61298a565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039161262f601f19938481018352826105dc565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610522575f5192828416801590811561271d575b5061270b576126f885916126e37f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610f4c565b6040516323389ba560e21b8152600490fd5b905083831614155f61269e565b604051631ab7da6b60e01b8152600490fd5b3461034e575f36600319011261034e5760206001600160801b0360d05416604051908152f35b3461034e57604036600319011261034e5760206127b860043561278481610743565b6024359061279182610743565b60018060a01b03165f526002835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461034e57602036600319011261034e576100186004356127e181610743565b6127e9614159565b614bc1565b3461034e575f36600319011261034e5760206001600160801b0360d55416604051908152f35b3461034e575f36600319011261034e576037546040516001600160a01b039091168152602090f35b9081602091031261034e575190565b6040513d5f823e3d90fd5b9060405161286381610573565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039182169082160391908211610ba157565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b03811690816128e957505090565b916106549260801c90613257565b9190916001600160801b0380809416911601918211610ba157565b61291a613d2b565b60d0546001600160801b036129308183166128d1565b9060d55416019060801c01908181115f14612949570390565b50505f90565b6101a1546001600160a01b031680156129655790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036129b75760045490565b610654613e93565b9081602091031261034e575161065481610743565b359061ffff8216820361034e57565b9080601f8301121561034e57816020610654933591016116c7565b60d4548061065457505f1990565b9060b08201809211610ba157565b91908201809211610ba157565b6001600160801b0360d05416612a3b615100565b908101809111610ba1578110612a6e57612a5f60d654612a596140e9565b90612a1a565b1115612a69575f90565b5f1990565b60d19060d1549182915f905b848210612a9457505050811015612a8e5790565b505f1990565b909193808316906001818518811c8301809311610ba1575f8790525f80516020615a118339815191528301546001600160a01b0316841015612adb575050935b9190612a7a565b909591019250612ad4565b5190811515820361034e57565b9081602091031261034e5761065490612ae6565b91908203918211610ba157565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612b5281608081015b03601f1981018352826105dc565b5190205f5260d260205260405f2054918215612bbc576001600160801b0360d0541690612b7d615100565b918201809211610ba1578391831015612baa5791612b9a926141ed565b90915b828103908111610ba15792565b5090612bb59161416d565b9091612b9d565b5050505f905f905f90565b9035601e198236030181121561034e5701602081359101916001600160401b03821161034e57813603831361034e57565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061065492602081528235602082015260208301356040820152612c54612c446040850185612bc7565b84606085015260c0840191612bf8565b90612c87612c7c612c686060870187612bc7565b601f19858703810160808701529591612bf8565b946080810190612bc7565b93909282860301910152612bf8565b903590601e198136030182121561034e57018035906001600160401b03821161034e5760200191813603831361034e57565b634e487b7160e01b5f52601260045260245ffd5b8115612ce6570490565b612cc8565b90670de0b6b3a76400009180830292830403610ba157565b90670de0b6b3a764000091828102928184041490151715610ba157565b6001600160401b03811161058e5760051b60200190565b90612d4182612d20565b612d4e60405191826105dc565b8281528092612d5f601f1991612d20565b01905f5b828110612d6f57505050565b806060602080938501015201612d63565b634e487b7160e01b5f52603260045260245ffd5b90821015612dab576112d39160051b810190612c96565b612d80565b908092918237015f815290565b3d15612de7573d90612dce826116ac565b91612ddc60405193846105dc565b82523d5f602084013e565b606090565b60208183031261034e578051906001600160401b03821161034e570181601f8201121561034e578051612e1e816116ac565b92612e2c60405194856105dc565b8184526020828401011161034e5761065491602080850191016105fd565b8051821015612dab5760209160051b010190565b919091612e6a83612d37565b925f5b818110612e7957505050565b5f80612e86838587612d94565b60409391612e98855180938193612db0565b0390305af490612ea6612dbd565b9115612ecd575090600191612ebb8288612e4a565b52612ec68187612e4a565b5001612e6d565b90604481511061034e57612f07612ef260049283810151602480918301019101612dec565b925162461bcd60e51b81529283928301610643565b0390fd5b47633b9aca008110612ff557604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610522575f92612fd4575b506001600160ff1b038211612fbb57907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db91612fa182613546565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b612fee91925060203d60201161051b5761050d81836105dc565b905f612f66565b50565b610109546001600160a01b03168061065457507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610522575f916130c5575b5060208201916001600160801b039182845116918282146130be57836130b16130ac6130b9958584865116613257565b6137e7565b1690526137e7565b169052565b5050505050565b6130de915060203d60201161051b5761050d81836105dc565b5f61307c565b90808202905f1981840990828083109203918083039214613153576127109082821115613141577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f19818409908280831092039180830392146131c157670de0b6b3a76400009082821115613141577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f198482099383808610950394808603951461324a578483111561314157829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106549250612cdc565b9091828202915f198482099383808610950394808603951461324a578483111561314157829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b9081606091031261034e57805191610654604060208401519301612ae6565b81835290916001600160fb1b03831161034e5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361034e576040830152604081013561333c81610743565b6001600160a01b031660608381019190915281013536829003601e190181121561034e5701602081359101906001600160401b03811161034e578060051b3603821361034e5760a08360808061065496015201916132e9565b9190915f8382019384129112908015821691151617610ba157565b6040516325f56f1160e01b81526001600160a01b039291606090829081906133db906004830161330d565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610522575f915f905f95613501575b5084156134ae578161342561294f565b16917f00000000000000000000000000000000000000000000000000000000000000001682146134a757509060205f92600460405180958193634641257d60e01b83525af190811561052257613482925f92613486575b50613395565b9190565b6134a091925060203d60201161051b5761050d81836105dc565b905f61347c565b90816134b4575b50509190565b803b1561034e57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015610522576134ee575b806134ae565b8061104d6134fb92610593565b5f6134e8565b91945050613527915060603d60601161352f575b61351f81836105dc565b8101906132ca565b93905f613415565b503d613515565b600160ff1b8114610ba1575f0390565b8015612ff55761355b6109da60cf5460801c90565b5f821261362d578161356c91612a1a565b90613579610ef0836137e7565b61358e609c549161ffff8360a01c16906130e4565b801561362857807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936135cc6109da60cf546001600160801b031690565b80613612575050612fb690925b6001600160a01b0316916135ed8484615320565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b612fb69261362292039084613257565b926135d9565b505050565b9061363790613536565b61364c6109da60d5546001600160801b031690565b8061366c575b508061365c575050565b6130ac610ef09161169d93612b07565b906136c77f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916136b7611ffb6136ac6136a58888612a1a565b8785613257565b8080940396036137e7565b6040519081529081906020820190565b0390a15f613652565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610522575f9161373d575b501561372b57565b604051630a62fbdb60e11b8152600490fd5b613756915060203d6020116118755761186681836105dc565b5f613723565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610522575f916137c8575b506137b657565b60405163e775715160e01b8152600490fd5b6137e1915060203d6020116118755761186681836105dc565b5f6137af565b6001600160801b03908181116137fb571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b51906001600160401b038216820361034e57565b9081606091031261034e5760405190606082018281106001600160401b0382111761058e57613880916040918252805161386781610372565b84526138756020820161381a565b60208501520161381a565b604082015290565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561052257613923936001600160401b03610d5d6040613902946020975f91613973575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610522575f9161395a575090565b610654915060203d60201161051b5761050d81836105dc565b61398c915060603d6060116110295761101a81836105dc565b5f6138f3565b60018060a01b0381165f5261016e60205260405f2090604051916139b583610573565b54906001600160801b03918281169081855260801c602085015215613628576109c16109bb613a08926139e661375c565b6139ef8661302f565b6001600160a01b03165f90815260d36020526040902090565b91511611610a5e57565b92906001600160a01b0390818116156107e457613a2d61375c565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561034e57604094855193631d8557d760e01b85526004945f81878183895af1801561052257613d18575b506001600160a01b0388165f90815261016e60205260409020613aa090612856565b906001600160801b03613aba83516001600160801b031690565b1615613d0857613ac98261302f565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561052257613ce9575b508651936303d1689d60e11b97888652602091828780613b43888c83019190602083019252565b0381845afa968715610522575f97613cca575b508699613b766109bb8d60018060a01b03165f5260d360205260405f2090565b88118015613cba575b613caa579083613bbc92613b9a87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610522575f85948894613c019c613c8d575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561052257610e97613c4894613c2b936104699361169d9a613c6f575b50506137e7565b6001600160a01b0388165f90815261016e602052604090206128a8565b613c6a613c5483614af4565b8097613c65610ef0610edd876137e7565b6154b8565b614a0f565b81613c8592903d1061051b5761050d81836105dc565b505f80613c24565b613ca390873d891161051b5761050d81836105dc565b505f613bd6565b825163efda1a2760e01b81528990fd5b50613cc3612912565b8811613b7f565b613ce2919750833d851161051b5761050d81836105dc565b955f613b56565b613d019060603d6060116110295761101a81836105dc565b505f613b1c565b875163673f032f60e11b81528690fd5b8061104d613d2592610593565b5f613a7e565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610522575f91613dfc575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561052257610654935f93613ddd575b5050612a1a565b613df4929350803d1061051b5761050d81836105dc565b905f80613dd6565b613e139150833d851161051b5761050d81836105dc565b5f613d82565b5f80516020615a318339815191526002815414613e365760029055565b604051633ee5aeb560e01b8152600490fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca00606480830191909152815261169d91613e8e826105a6565b614c9f565b6040515f905f5490613ea482610527565b9283825260209384830193600190866001821691825f14613f99575050600114613f56575b50509181613edf613f5093612b449503826105dc565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f805160206159b18339815191525b828410613f845750505082010181613edf613ec9565b80548685018601528794909301928101613f6e565b60ff1916875292151560051b85019092019250839150613edf9050613ec9565b9190613fc3614d10565b608082015190613fd1614d10565b6001600160a01b03841680156107e457614071946140619361404a926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806140383394602083019061061e565b0390a2602085015161ffff1690614d51565b6140548351614da2565b61405c614dd2565b614dfe565b6060604082015191015190614e2d565b61169d614f5a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149182156140b7575b50506119da57565b5f805160206159d18339815191525416141590505f806140af565b906140db615100565b918201809211610ba1571090565b6140f1613d2b565b60d0548060801c8203918211610ba157816141156001600160801b038093166128d1565b908161413b575b5050811561294957610654916141369160d5541690615142565b615154565b919250908181111561415157035b905f8061411c565b50505f614149565b6037546001600160a01b031633036115c157565b6141756140e9565b9160d654928301809311610ba157808311156141bf57614196920390615142565b9060d5548060801c80155f146141ac5750508190565b6001600160801b03610654921684613257565b5050505f905f90565b906040516141d581610573565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590614380575b614373578361433d575f5b60d15f526001600160a01b03166142325f80516020615a1183398151915286016141c8565b8051909790614249906001600160a01b0316611970565b9861426e6142626020809b01516001600160601b031690565b6001600160601b031690565b948381108015614333575b6143215791600193979a956142986142a4939488035b838c0390615142565b80920198870391613257565b01970193808611801590614317575b61430c5760d15f5282906142d55f80516020615a1183398151915287016141c8565b805190890151969992966001600160a01b0390911694600193926142a49290916001600160601b039091169061429890880361428f565b945050509250509190565b50818510156142b3565b60405163e8722f8f60e01b8152600490fd5b50808b1115614279565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b031661420d565b505093505050505f905f90565b508415614202565b604290467f0000000000000000000000000000000000000000000000000000000000000000036144375761010a54905b6143cf6143c86040830183612c96565b36916116c7565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815261441a816105c1565b5190206040519161190160f01b8352600283015260228201522090565b61443f61518b565b906143b8565b6004111561444f57565b634e487b7160e01b5f52602160045260245ffd5b61446d8383615258565b5061447a81959295614445565b159384614516575b508315614490575b50505090565b5f9293509082916040516144c881612b446020820194630b135d3f60e11b998a8752602484015260406044840152606483019061061e565b51915afa906144d5612dbd565b82614508575b826144eb575b50505f808061448a565b6145009192506020808251830101910161283c565b145f806144e1565b9150602082511015916144db565b6001600160a01b0383811691161493505f614482565b9061453682612d20565b61454360405191826105dc565b8281528092614554601f1991612d20565b0190602036910137565b9060301161034e5790603090565b9060901161034e5760300190606090565b9060b01161034e5760900190602090565b9093929384831161034e57841161034e578101920390565b6020908361169d9395949560405196836145c989955180928880890191016105fd565b84019185830137015f838201520380855201836105dc565b3590602081106145ef575090565b5f199060200360031b1b1690565b916020610654938181520191612bf8565b91926146386146286146469360808652608086019061061e565b602095858203602087015261061e565b90838203604085015261061e565b906060818303910152602080845192838152019301915f5b82811061466c575050505090565b83518552938101939281019260010161465e565b614688615292565b6060906060905f809460b081049261469f8461452c565b965f905b8582106147be57506001600160a01b03947f0000000000000000000000000000000000000000000000000000000000000000945061471a9350602092506146ea9150612ceb565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af180156105225761479f575b50166147576152f7565b813b1561034e575f80946147816040519788968795869463c82655b760e01b86526004860161460e565b03925af18015610522576147925750565b8061104d61169d92610593565b6147b79060203d6020116118755761186681836105dc565b505f61474d565b61484361481361481e6148006147f77f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612a0c565b8099898961458e565b92909a61480d848d61455e565b916145a6565b9a61480d838c61456c565b988b61483d86614837614831868661457d565b906145e1565b92612e4a565b5261455e565b90614853604051928392836145fd565b0390a1600101836146a3565b9294614898670de0b6b3a76400009661488a608097946148a6969b9a9b60a0895260a0890191612bf8565b90868203602088015261061e565b918483036040860152612bf8565b9460608201520152565b906148b9615292565b6148c3818361455e565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af18015610522576149f0575b5016906149556152f7565b9161496e614831614966848961456c565b94909861457d565b95813b1561034e575f809461499b604051998a9687958694630cac9f3160e01b86528c8c6004880161485f565b03925af1928315610522577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936149dd575b50612fb6604051928392836145fd565b8061104d6149ea92610593565b5f6149cd565b614a089060203d6020116118755761186681836105dc565b505f61494a565b90614a18613e19565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561052257614ab294613e8e925f91614ad5575b508411614ac8575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836105dc565b61169d60015f80516020615a3183398151915255565b614ad0615292565b614a7d565b614aee915060203d60201161051b5761050d81836105dc565b5f614a75565b60cf54906001600160801b03821681158015614b23575b15614b165750905090565b6106549260801c91613257565b508015614b0b565b60cf546001600160801b0381169081614b48575050633b9aca0090565b60801c614b5581836131d2565b918115612ce657633b9aca0009614b695790565b60018101809111156106545761287b565b60cf546001600160801b0381169082158015614bb9575b15614b9b57505090565b60801c90614baa828285613257565b928215612ce65709614b695790565b508115614b91565b614bc961375c565b6001600160a01b03168015614c1157609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03908116919082158015614c95575b6107e457825f5260d360205260405f2090815492858403938411610ba1575f805160206159f18339815191529360209355614c848160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614c39565b5f80614cc79260018060a01b03169360208151910182865af1614cc0612dbd565b908361594d565b8051908115159182614cf5575b5050614cdd5750565b60249060405190635274afe760e01b82526004820152fd5b614d089250602080918301019101612af3565b155f80614cd4565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614d3f57565b604051631afcd79f60e31b8152600490fd5b614d59614d10565b61271061ffff831611614d9057614d6f90614bc1565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614daa614d10565b8015614dc05760018101614dbb5750565b60d455565b6040516331278a8760e01b8152600490fd5b614dda614d10565b670de0b6b3a7640000614deb6129fe565b10614dc057614df861518b565b61010a55565b614e06614d10565b6001600160a01b031680614e175750565b6101a180546001600160a01b0319169091179055565b614e35614d10565b601e8151118015614f4f575b614f3d57614e4d614d10565b8051906001600160401b03821161058e57614e7182614e6c5f54610527565b615523565b602090816001601f851114614ec957509180614ea792614eae95945f92614ebe575b50508160011b915f199060031b1c19161790565b5f556155ed565b61169d614eb9613e93565b600455565b015190505f80614e93565b5f80529190601f1984165f805160206159b1833981519152935f905b828210614f25575050916001939185614eae97969410614f0d575b505050811b015f556155ed565b01515f1960f88460031b161c191690555f8080614f00565b80600186978294978701518155019601940190614ee5565b604051632d3f993760e21b8152600490fd5b50600a825111614e41565b614f62614d10565b614f6a614d10565b614f72614d10565b60015f80516020615a3183398151915255614f8b61375c565b30156107e457633b9aca008060cf5460801c01614fa66129fe565b811161502e57614fc0610ef0614fba614b2b565b926137e7565b614fca8130615320565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a361169d30337f0000000000000000000000000000000000000000000000000000000000000000613e48565b6040516304ffa0ff60e51b8152600490fd5b9081602091031261034e57516106548161251c565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816150df575b506150a557604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206159d183398151915284036150c65761169d9293506156cb565b604051632a87526960e21b815260048101859052602490fd5b6150f991955060203d60201161051b5761050d81836105dc565b935f61507f565b60d1548061510d57505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316611970565b908082101561514f575090565b905090565b60d554908160801c81158015615183575b156151705750905090565b6001600160801b03610654931691613257565b508015615165565b6e5661756c7456616c696461746f727360881b60206040516151ac81610573565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b0382111761058e5760405251902090565b8151919060418303615288576152819250602082015190606060408401519301515f1a9061576d565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561034e575f809160246040518094819363a3066aab60e01b83523060048401525af18015610522576152ee5750565b61169d90610593565b604051600160f81b60208201525f60218201523060601b602c8201526020815261065481610573565b5f805160206159f183398151915260205f9261533b856137e7565b60cf54906153536001600160801b03918284166128f7565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b0382169182156154b25760801c6153c36153b4826153af613d2b565b612b07565b6153bd856128d1565b90615142565b9081156154ab576153d382614af4565b9384156154a35782615420611eeb6130ac61169d96610ef09661541b6153ff6130ac8d6154989a612b07565b6001600160801b03166001600160801b031960d054161760d055565b612a1a565b61542a818761585f565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a16130ac61547c61546b886137e7565b60cf546001600160801b031661288f565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c61288f565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f81815260d360205260409020805483810391908211610ba1575f935f805160206159f183398151915292602092556154f9816137e7565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b601f811161552f575050565b5f80525f805160206159b1833981519152906020601f840160051c83019310615572575b601f0160051c01905b818110615567575050565b5f815560010161555c565b9091508190615553565b90601f8211615589575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c830193106155e3575b601f0160051c01905b8181106155d957505050565b5f815582016155cd565b90915081906155c4565b9081516001600160401b03811161058e576001906156148161560f8454610527565b61557c565b602080601f8311600114615649575081906156459394955f92614ebe5750508160011b915f199060031b1c19161790565b9055565b90601f1983169561567b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b8882106156b4575050838596971061569c575b505050811b019055565b01515f1960f88460031b161c191690555f8080615692565b80878596829496860151815501950193019061567f565b90813b1561574c575f805160206159d183398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561573157612ff591615934565b50503461573a57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116157f657906157c66020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15610522575f516001600160a01b038116156157ec57905f905f90565b505f906001905f90565b5050505f9160039190565b60d154906801000000000000000082101561058e57600182018060d155821015612dab5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020615a1183398151915290910155565b9190918015801561592c575b61591a57615877615100565b908101809111610ba1576001600160a01b038082116158fa576001600160601b03908185116158da579061169d93946158c46158d5936158b561169f565b95166001600160a01b03168552565b166001600160601b03166020830152565b615801565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561586b565b5f8061065493602081519101845af461594b612dbd565b915b90615974575080511561596257805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806159a7575b615985575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561597d56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212208b01db5292bb89ece855b79c6de0cffe4d0ab4b183e773755cfcc0c4955317eb64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d1141461033f578063066055e01461033a57806306fdde031461033557806307a2d13a14610330578063095ea7b31461032b57806318160ddd146102f45780631a7ff55314610326578063201b9eb51461032157806323b872dd1461031c5780632999ad3f146103175780632cdf7401146103125780632e2d29841461030d578063313ce567146103085780633229fa951461030357806333194c0a146102fe5780633644e515146102f95780633a98ef39146102f4578063439fab91146102ef57806343e82a79146102ea57806346904840146102e55780634ec96b22146102e05780634f1ef286146102db57806352d1902d146102d657806354fd4d50146102d15780635c60da1b146102cc5780635cfc1a51146102c757806360d60e6e146102c257806370a082311461025457806372b410a8146102bd578063754c3888146102b857806376b58b90146102b35780637ecebe00146102ae5780637fd6f15c146102a957806383d430d5146102a45780638697d2c21461029f5780638ceab9aa1461029a57806395d89b4114610295578063a49a1e7d14610290578063a9059cbb1461028b578063ac9650d814610286578063ad3cb1cc14610281578063b0d113021461027c578063b1f0e7c714610277578063c6e6f59214610272578063d505accf1461026d578063d83ad00c14610268578063dd62ed3e14610263578063e74b981b1461025e578063ee3bd5df14610259578063f04da65b146102545763f851a4400361000e57612814565b611a73565b6127ee565b6127c1565b612762565b61273c565b612527565b6124fe565b6124e4565b6124b1565b61246c565b612407565b612366565b612314565b612270565b612087565b611e27565b611c57565b611c33565b611bf8565b611ba7565b611b3b565b611aae565b611a55565b611a3b565b611a07565b6119ec565b611983565b6116fd565b61161a565b6115f2565b6114f5565b6112d7565b6107f6565b611262565b611228565b6111fc565b6111e1565b611073565b611059565b610bcf565b610af3565b610894565b61081c565b610754565b61071d565b610657565b610383565b610352565b5f91031261034e57565b5f80fd5b3461034e575f36600319011261034e57602060cf5460801c604051908152f35b6001600160801b0381160361034e57565b3461034e57602036600319011261034e576004356103a081610372565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610522575f916104f3575b50335f90815261016e6020526040902061041c90612856565b916001600160801b0361043684516001600160801b031690565b16156104e15761048a8361044c6104dd9561302f565b6104766104698461046484516001600160801b031690565b61288f565b6001600160801b03168252565b335f90815261016e602052604090206128a8565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610515915060203d60201161051b575b61050d81836105dc565b81019061283c565b5f610403565b503d610503565b61284b565b90600182811c92168015610555575b602083101461054157565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610536565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761058e57604052565b61055f565b6001600160401b03811161058e57604052565b60a081019081106001600160401b0382111761058e57604052565b608081019081106001600160401b0382111761058e57604052565b90601f801991011681019081106001600160401b0382111761058e57604052565b5f5b83811061060e5750505f910152565b81810151838201526020016105ff565b90602091610637815180928185528580860191016105fd565b601f01601f1916010190565b90602061065492818152019061061e565b90565b3461034e575f36600319011261034e576040515f805461067681610527565b808452906020906001908181169081156106f357506001146106af575b6104dd856106a3818703826105dc565b60405191829182610643565b5f80805293505f805160206159b18339815191525b8385106106e0575050505081016020016106a3826104dd610693565b80548686018401529382019381016106c4565b8695506104dd969350602092506106a394915060ff191682840152151560051b8201019293610693565b3461034e57602036600319011261034e57602061073b6004356128d1565b604051908152f35b6001600160a01b0381160361034e57565b3461034e57604036600319011261034e5760043561077181610743565b6001600160a01b038116906024359082156107e4576107ac8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b3461034e575f36600319011261034e5760206001600160801b0360cf5416604051908152f35b3461034e5760031960203682011261034e57600435906001600160401b03821161034e57608090823603011261034e5761085b610862916004016133b0565b9190613546565b61086857005b610870615388565b8061087757005b5f906040519081525f805160206159f183398151915260203092a3005b3461034e57606036600319011261034e576004356108b181610743565b60243590604435906108c282610743565b6108ca6136d0565b6108d261375c565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af1948515610522575f95610ad4575b50335f90815261016e6020526040902061094d90612856565b926001600160801b0361096785516001600160801b031690565b1615610a705750506109788261302f565b6109a4610997610987876137e7565b84516001600160801b03166128f7565b6001600160801b03168352565b335f90815260d3602052604090206109c6906109c1905b546128d1565b613888565b6109e66109da84516001600160801b031690565b6001600160801b031690565b11610a5e57335f90815261016e602052604090206104dd957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610a2c91906128a8565b604080516001600160a01b039586168152602081018790529081019190915292166060830152339180608081016104ca565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561052257610ab292610aa3915f91610ab7575b506137e7565b6001600160801b031690840152565b610978565b610ace9150833d851161051b5761050d81836105dc565b5f610a9d565b610aec919550833d851161051b5761050d81836105dc565b935f610934565b3461034e57606036600319011261034e57600435610b1081610743565b60243590610b1d82610743565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610b6d575b610b6184610b5c858883614c23565b613992565b60405160018152602090f35b919093818503948511610ba1575f928352600260209081526040808520338652909152909220939093559180610b61610b4d565b61287b565b606090600319011261034e5760043590602435610bc281610743565b9060443561065481610743565b3461034e57610bdd36610ba6565b906001600160a01b03808316156107e457610bf661375c565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561034e5760408051631d8557d760e01b815260049491905f81878183875af1801561052257611040575b506001600160a01b0383165f90815261016e60205260409020610c6990612856565b6001600160801b039283610c8483516001600160801b031690565b161561103057610c938261302f565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610522575f98610fff575b50602097888101956001600160401b03918280610d0c8a516001600160401b031690565b1614610fef57908c92918751918c8380610d386303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561052257610d64938e5f94610fca575b5050516001600160801b03165b169061315e565b96610d826109bb8a60018060a01b03165f5260d360205260405f2090565b928389118015610fba575b610faa57908b610dcb9392610da989516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561052257670de0b6b3a764000094610e1a948e5f95610f7d575b5050610e0c610dfe610e1292612d03565b93516001600160401b031690565b93612d03565b921690613257565b1015610f6f578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610522577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610f4c95610ec493610f51575b5050610ea7610469610e978c6137e7565b83516001600160801b031661288f565b6001600160a01b0386165f90815261016e602052604090206128a8565b610ecd82614af4565b90610f0b610ef0610edd856137e7565b60cf5460801c036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610f1582866154b8565b610f1f8389614a0f565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610f6792903d1061051b5761050d81836105dc565b505f80610e86565b835163185cfc6d60e11b8152fd5b610e12929550610fa0610e0c9282610dfe93903d1061051b5761050d81836105dc565b959250508e610ded565b875163efda1a2760e01b81528590fd5b50610fc3612912565b8911610d8d565b610d5d9294509081610fe792903d1061051b5761050d81836105dc565b92908e610d50565b8651630709133160e01b81528490fd5b61102291985060603d606011611029575b61101a81836105dc565b81019061382e565b965f610ce8565b503d611010565b825163673f032f60e11b81528790fd5b8061104d61105392610593565b80610344565b5f610c47565b3461034e575f36600319011261034e57602061073b612912565b3461034e5761108136610ba6565b9161108a613e19565b6040926110e484516323b872dd60e01b6020820152336024820152306044820152836064820152606481526110be816105a6565b7f0000000000000000000000000000000000000000000000000000000000000000614c9f565b6110ec61375c565b6001600160a01b0383169283156111d05782156111bf57826111136109da60cf5460801c90565b019061111d6129fe565b82116111ae57611194610ef0959361116e86947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461116961116160209c9a614b7a565b9a8b936137e7565b615320565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020615a318339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b3461034e575f36600319011261034e57602060405160128152f35b3461034e575f36600319011261034e57602061121661294f565b6040516001600160a01b039091168152f35b3461034e575f36600319011261034e5760206040517fd7358ee43135ceaf16fc3a6da49b8f2795ad16de0cf7f569aa7b9b1e67532fc48152f35b3461034e575f36600319011261034e57602061073b61298a565b9181601f8401121561034e578235916001600160401b03831161034e576020838186019501011161034e57565b602060031982011261034e57600435906001600160401b03821161034e576112d39160040161127c565b9091565b3461034e576112e5366112a9565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c1680156114e1575b6114d05768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020908185600481335afa948515610522575f956114b1575b508351636f4fa30f60e01b8152908282600481335afa918215610522575f92611482575b50830194828487031261034e5783356001600160401b039485821161034e570160a08188031261034e576113b4611690565b93813585526113c48183016129d4565b908501528581013585811161034e57876113df9183016129e3565b86850152606081013585811161034e57876113fb9183016129e3565b6060850152608081013594851161034e577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2966114469561143c92016129e3565b6080840152613fb9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff0000000000000000191690555160028152602090a1005b6114a3919250833d85116114aa575b61149b81836105dc565b8101906129bf565b905f611382565b503d611491565b6114c9919550823d84116114aa5761149b81836105dc565b935f61135e565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b038216101561131b565b3461034e5761150336610ba6565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105225782915f916115d3575b501633036115c15781610f4c61158e86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613a12565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6115ec915060203d6020116114aa5761149b81836105dc565b5f611556565b3461034e575f36600319011261034e57609c546040516001600160a01b039091168152602090f35b3461034e57602036600319011261034e5760043561163781610743565b60018060a01b03165f5261016e602052602060405f206040519061165a82610573565b54906001600160801b03918281169081835260801c84830152611682575b5116604051908152f35b61168b8161302f565b611678565b6040519061169d826105a6565b565b6040519061169d82610573565b6001600160401b03811161058e57601f01601f191660200190565b9291926116d3826116ac565b916116e160405193846105dc565b82948184528183011161034e578281602093845f960137010152565b60408060031936011261034e57600490813561171881610743565b6024356001600160401b03811161034e573660238201121561034e5761174790369060248187013591016116c7565b91611750614079565b8051926117878461177960209363439fab9160e01b85840152846024840152604483019061061e565b03601f1981018652856105dc565b61178f614079565b611797614159565b6001600160a01b0383811680159291908790841561194e575b84156118e0575b841561187c575b505082156117e6575b50506117d7576100188383615055565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610522575f9261184f575b5050155f806117c7565b61186e9250803d10611875575b61186681836105dc565b810190612af3565b5f80611845565b503d61185c565b855163054fd4d560e41b81529294508391839182905afa9081156105225760039160ff915f916118b3575b5016141591865f6117be565b6118d39150843d86116118d9575b6118cb81836105dc565b810190615040565b5f6118a7565b503d6118c1565b935050835163198ca60560e11b815282818981875afa9081156105225788917fd7358ee43135ceaf16fc3a6da49b8f2795ad16de0cf7f569aa7b9b1e67532fc4915f91611931575b501415936117b7565b6119489150853d871161051b5761050d81836105dc565b5f611928565b5f805160206159d183398151915254909450849061197c906001600160a01b03165b6001600160a01b031690565b14936117b0565b3461034e575f36600319011261034e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036119da5760206040515f805160206159d18339815191528152f35b60405163703e46dd60e11b8152600490fd5b3461034e575f36600319011261034e57602060405160028152f35b3461034e575f36600319011261034e575f805160206159d1833981519152546040516001600160a01b039091168152602090f35b3461034e575f36600319011261034e57602061073b6129fe565b3461034e57602036600319011261034e57602061073b600435612a27565b3461034e57602036600319011261034e57600435611a9081610743565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461034e575f36600319011261034e57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610522576020915f91611b1e575b506040519015158152f35b611b359150823d84116118755761186681836105dc565b5f611b13565b3461034e57602036600319011261034e57600435611b5881610743565b611b60614159565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461034e57608036600319011261034e576104dd611bdb600435611bca81610743565b606435906044359060243590612b14565b604080519384526020840192909252908201529081906060820190565b3461034e57602036600319011261034e57600435611c1581610743565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461034e575f36600319011261034e57602061ffff609c5460a01c16604051908152f35b3461034e5760031960403682011261034e5760049081356001600160401b0380821161034e5760a082850193833603011261034e5760243590811161034e57611ca3903690850161127c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561034e5760405163837d444160e01b8152905f908290818381611cf68c828f01612c18565b03925af1801561052257611e14575b50611d0e61375c565b611d16612ff8565b9081163314159182611de5575b50509050611dd4576044019160b0611d3b8484612c96565b90500480158015611dbc575b611dac57611d5c611d56612912565b91612ceb565b11611d9d575060b0611d6e8383612c96565b9050145f14611d8a5761001891611d8491612c96565b906148b0565b61001891611d9791612c96565b90614680565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611dc78484612c96565b905060b082021415611d47565b604051634ca8886760e01b81528390fd5b611e089250611e02611e0c94611dfa88614388565b9236916116c7565b91614463565b1590565b805f80611d23565b8061104d611e2192610593565b5f611d05565b3461034e57606036600319011261034e57600435602435611e4c604435828433612b14565b9192611e787f000000000000000000000000000000000000000000000000000000000000000082612a1a565b4210801561207f575b8015612077575b612065577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611ecc86611ec76109da60d0546001600160801b031690565b6140d2565b15611fd357611f06611eeb611ee0866137e7565b60d05460801c61288f565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611f4a9190611f396080826105dc565b5190205f5260d260205260405f2090565b555f9360018311611f83575b50505050611f648233614a0f565b604080519485526020850191909152830152339180606081015b0390a2005b611fc992939450611f949088612a1a565b60408051336020820190815291810193909352606083018290529094909190611f399082608081015b039081018352826105dc565b555f808080611f56565b611fdb61375c565b612017611ffb611fea866137e7565b60d5546001600160801b031661288f565b6001600160801b03166001600160801b031960d554161760d555565b61204c612031612026856137e7565b60d55460801c61288f565b6001600160801b0360d5549181199060801b1691161760d555565b61206061205b8460d654612a1a565b60d655565b611f06565b604051630e3d8e8d60e11b8152600490fd5b508215611e88565b508115611e81565b3461034e5760408060031936011261034e57602435906004356120a983610743565b6120b161375c565b801561225f576001600160a01b03831690811561224e576120d1816128d1565b90811561223d576120e182615154565b6120ea836137e7565b60cf5460801c906120fa9161288f565b612119906001600160801b0360cf549181199060801b1691161760cf55565b61212382336154b8565b60d554958660801c828160d6549061213a91612a1a565b98612144876137e7565b612156916001600160801b03166128f7565b612176906001600160801b03166001600160801b031960d554161760d555565b61217f91612a1a565b612188906137e7565b6121a7906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b03919091166020820190815242604083015260608083018990528252906121d86080826105dc565b5190206121ed905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a361223433613992565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461034e575f36600319011261034e576040515f6001805461229181610527565b80855291602091600181169081156106f357506001146122bb576104dd856106a3818703826105dc565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510612301575050505081016020016106a3826104dd610693565b80548686018401529382019381016122e5565b3461034e57611f7e7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf612346366112a9565b9290612350614159565b6040519182916020835233956020840191612bf8565b3461034e57604036600319011261034e5761239060043561238681610743565b6024359033614c23565b61239933613992565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106123d95750505050505090565b90919293949584806123f7600193603f198682030187528a5161061e565b98019301930191949392906123c9565b3461034e57602036600319011261034e576001600160401b0360043581811161034e573660238201121561034e57806004013591821161034e573660248360051b8301011161034e576104dd9160246124609201612e5e565b604051918291826123a4565b3461034e575f36600319011261034e576104dd60405161248b81610573565b60058152640352e302e360dc1b602082015260405191829160208352602083019061061e565b3461034e575f36600319011261034e576124c9613e19565b6124d1612f0b565b60015f80516020615a3183398151915255005b3461034e575f36600319011261034e576020611216612ff8565b3461034e57602036600319011261034e57602061073b600435614af4565b60ff81160361034e57565b3461034e5760e036600319011261034e5760043561254481610743565b60243561255081610743565b6044359060643592608435906125658261251c565b6001600160a01b038381169590929086156107e45742811061272a576020915f91611fbd61265889878a61261b61259a61298a565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b039161262f601f19938481018352826105dc565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610522575f5192828416801590811561271d575b5061270b576126f885916126e37f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610f4c565b6040516323389ba560e21b8152600490fd5b905083831614155f61269e565b604051631ab7da6b60e01b8152600490fd5b3461034e575f36600319011261034e5760206001600160801b0360d05416604051908152f35b3461034e57604036600319011261034e5760206127b860043561278481610743565b6024359061279182610743565b60018060a01b03165f526002835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461034e57602036600319011261034e576100186004356127e181610743565b6127e9614159565b614bc1565b3461034e575f36600319011261034e5760206001600160801b0360d55416604051908152f35b3461034e575f36600319011261034e576037546040516001600160a01b039091168152602090f35b9081602091031261034e575190565b6040513d5f823e3d90fd5b9060405161286381610573565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039182169082160391908211610ba157565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b03811690816128e957505090565b916106549260801c90613257565b9190916001600160801b0380809416911601918211610ba157565b61291a613d2b565b60d0546001600160801b036129308183166128d1565b9060d55416019060801c01908181115f14612949570390565b50505f90565b6101a1546001600160a01b031680156129655790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f0000000000000000000000000000000000000000000000000000000000000000036129b75760045490565b610654613e93565b9081602091031261034e575161065481610743565b359061ffff8216820361034e57565b9080601f8301121561034e57816020610654933591016116c7565b60d4548061065457505f1990565b9060b08201809211610ba157565b91908201809211610ba157565b6001600160801b0360d05416612a3b615100565b908101809111610ba1578110612a6e57612a5f60d654612a596140e9565b90612a1a565b1115612a69575f90565b5f1990565b60d19060d1549182915f905b848210612a9457505050811015612a8e5790565b505f1990565b909193808316906001818518811c8301809311610ba1575f8790525f80516020615a118339815191528301546001600160a01b0316841015612adb575050935b9190612a7a565b909591019250612ad4565b5190811515820361034e57565b9081602091031261034e5761065490612ae6565b91908203918211610ba157565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612b5281608081015b03601f1981018352826105dc565b5190205f5260d260205260405f2054918215612bbc576001600160801b0360d0541690612b7d615100565b918201809211610ba1578391831015612baa5791612b9a926141ed565b90915b828103908111610ba15792565b5090612bb59161416d565b9091612b9d565b5050505f905f905f90565b9035601e198236030181121561034e5701602081359101916001600160401b03821161034e57813603831361034e57565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061065492602081528235602082015260208301356040820152612c54612c446040850185612bc7565b84606085015260c0840191612bf8565b90612c87612c7c612c686060870187612bc7565b601f19858703810160808701529591612bf8565b946080810190612bc7565b93909282860301910152612bf8565b903590601e198136030182121561034e57018035906001600160401b03821161034e5760200191813603831361034e57565b634e487b7160e01b5f52601260045260245ffd5b8115612ce6570490565b612cc8565b90670de0b6b3a76400009180830292830403610ba157565b90670de0b6b3a764000091828102928184041490151715610ba157565b6001600160401b03811161058e5760051b60200190565b90612d4182612d20565b612d4e60405191826105dc565b8281528092612d5f601f1991612d20565b01905f5b828110612d6f57505050565b806060602080938501015201612d63565b634e487b7160e01b5f52603260045260245ffd5b90821015612dab576112d39160051b810190612c96565b612d80565b908092918237015f815290565b3d15612de7573d90612dce826116ac565b91612ddc60405193846105dc565b82523d5f602084013e565b606090565b60208183031261034e578051906001600160401b03821161034e570181601f8201121561034e578051612e1e816116ac565b92612e2c60405194856105dc565b8184526020828401011161034e5761065491602080850191016105fd565b8051821015612dab5760209160051b010190565b919091612e6a83612d37565b925f5b818110612e7957505050565b5f80612e86838587612d94565b60409391612e98855180938193612db0565b0390305af490612ea6612dbd565b9115612ecd575090600191612ebb8288612e4a565b52612ec68187612e4a565b5001612e6d565b90604481511061034e57612f07612ef260049283810151602480918301019101612dec565b925162461bcd60e51b81529283928301610643565b0390fd5b47633b9aca008110612ff557604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610522575f92612fd4575b506001600160ff1b038211612fbb57907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db91612fa182613546565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b612fee91925060203d60201161051b5761050d81836105dc565b905f612f66565b50565b610109546001600160a01b03168061065457507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610522575f916130c5575b5060208201916001600160801b039182845116918282146130be57836130b16130ac6130b9958584865116613257565b6137e7565b1690526137e7565b169052565b5050505050565b6130de915060203d60201161051b5761050d81836105dc565b5f61307c565b90808202905f1981840990828083109203918083039214613153576127109082821115613141577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f19818409908280831092039180830392146131c157670de0b6b3a76400009082821115613141577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f198482099383808610950394808603951461324a578483111561314157829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106549250612cdc565b9091828202915f198482099383808610950394808603951461324a578483111561314157829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b9081606091031261034e57805191610654604060208401519301612ae6565b81835290916001600160fb1b03831161034e5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361034e576040830152604081013561333c81610743565b6001600160a01b031660608381019190915281013536829003601e190181121561034e5701602081359101906001600160401b03811161034e578060051b3603821361034e5760a08360808061065496015201916132e9565b9190915f8382019384129112908015821691151617610ba157565b6040516325f56f1160e01b81526001600160a01b039291606090829081906133db906004830161330d565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610522575f915f905f95613501575b5084156134ae578161342561294f565b16917f00000000000000000000000000000000000000000000000000000000000000001682146134a757509060205f92600460405180958193634641257d60e01b83525af190811561052257613482925f92613486575b50613395565b9190565b6134a091925060203d60201161051b5761050d81836105dc565b905f61347c565b90816134b4575b50509190565b803b1561034e57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015610522576134ee575b806134ae565b8061104d6134fb92610593565b5f6134e8565b91945050613527915060603d60601161352f575b61351f81836105dc565b8101906132ca565b93905f613415565b503d613515565b600160ff1b8114610ba1575f0390565b8015612ff55761355b6109da60cf5460801c90565b5f821261362d578161356c91612a1a565b90613579610ef0836137e7565b61358e609c549161ffff8360a01c16906130e4565b801561362857807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936135cc6109da60cf546001600160801b031690565b80613612575050612fb690925b6001600160a01b0316916135ed8484615320565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b612fb69261362292039084613257565b926135d9565b505050565b9061363790613536565b61364c6109da60d5546001600160801b031690565b8061366c575b508061365c575050565b6130ac610ef09161169d93612b07565b906136c77f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916136b7611ffb6136ac6136a58888612a1a565b8785613257565b8080940396036137e7565b6040519081529081906020820190565b0390a15f613652565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610522575f9161373d575b501561372b57565b604051630a62fbdb60e11b8152600490fd5b613756915060203d6020116118755761186681836105dc565b5f613723565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610522575f916137c8575b506137b657565b60405163e775715160e01b8152600490fd5b6137e1915060203d6020116118755761186681836105dc565b5f6137af565b6001600160801b03908181116137fb571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b51906001600160401b038216820361034e57565b9081606091031261034e5760405190606082018281106001600160401b0382111761058e57613880916040918252805161386781610372565b84526138756020820161381a565b60208501520161381a565b604082015290565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561052257613923936001600160401b03610d5d6040613902946020975f91613973575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610522575f9161395a575090565b610654915060203d60201161051b5761050d81836105dc565b61398c915060603d6060116110295761101a81836105dc565b5f6138f3565b60018060a01b0381165f5261016e60205260405f2090604051916139b583610573565b54906001600160801b03918281169081855260801c602085015215613628576109c16109bb613a08926139e661375c565b6139ef8661302f565b6001600160a01b03165f90815260d36020526040902090565b91511611610a5e57565b92906001600160a01b0390818116156107e457613a2d61375c565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561034e57604094855193631d8557d760e01b85526004945f81878183895af1801561052257613d18575b506001600160a01b0388165f90815261016e60205260409020613aa090612856565b906001600160801b03613aba83516001600160801b031690565b1615613d0857613ac98261302f565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561052257613ce9575b508651936303d1689d60e11b97888652602091828780613b43888c83019190602083019252565b0381845afa968715610522575f97613cca575b508699613b766109bb8d60018060a01b03165f5260d360205260405f2090565b88118015613cba575b613caa579083613bbc92613b9a87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610522575f85948894613c019c613c8d575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561052257610e97613c4894613c2b936104699361169d9a613c6f575b50506137e7565b6001600160a01b0388165f90815261016e602052604090206128a8565b613c6a613c5483614af4565b8097613c65610ef0610edd876137e7565b6154b8565b614a0f565b81613c8592903d1061051b5761050d81836105dc565b505f80613c24565b613ca390873d891161051b5761050d81836105dc565b505f613bd6565b825163efda1a2760e01b81528990fd5b50613cc3612912565b8811613b7f565b613ce2919750833d851161051b5761050d81836105dc565b955f613b56565b613d019060603d6060116110295761101a81836105dc565b505f613b1c565b875163673f032f60e11b81528690fd5b8061104d613d2592610593565b5f613a7e565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610522575f91613dfc575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561052257610654935f93613ddd575b5050612a1a565b613df4929350803d1061051b5761050d81836105dc565b905f80613dd6565b613e139150833d851161051b5761050d81836105dc565b5f613d82565b5f80516020615a318339815191526002815414613e365760029055565b604051633ee5aeb560e01b8152600490fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca00606480830191909152815261169d91613e8e826105a6565b614c9f565b6040515f905f5490613ea482610527565b9283825260209384830193600190866001821691825f14613f99575050600114613f56575b50509181613edf613f5093612b449503826105dc565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f805160206159b18339815191525b828410613f845750505082010181613edf613ec9565b80548685018601528794909301928101613f6e565b60ff1916875292151560051b85019092019250839150613edf9050613ec9565b9190613fc3614d10565b608082015190613fd1614d10565b6001600160a01b03841680156107e457614071946140619361404a926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf60405160208152806140383394602083019061061e565b0390a2602085015161ffff1690614d51565b6140548351614da2565b61405c614dd2565b614dfe565b6060604082015191015190614e2d565b61169d614f5a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149182156140b7575b50506119da57565b5f805160206159d18339815191525416141590505f806140af565b906140db615100565b918201809211610ba1571090565b6140f1613d2b565b60d0548060801c8203918211610ba157816141156001600160801b038093166128d1565b908161413b575b5050811561294957610654916141369160d5541690615142565b615154565b919250908181111561415157035b905f8061411c565b50505f614149565b6037546001600160a01b031633036115c157565b6141756140e9565b9160d654928301809311610ba157808311156141bf57614196920390615142565b9060d5548060801c80155f146141ac5750508190565b6001600160801b03610654921684613257565b5050505f905f90565b906040516141d581610573565b91546001600160a01b038116835260a01c6020830152565b60d1545f948594939091808410801590614380575b614373578361433d575f5b60d15f526001600160a01b03166142325f80516020615a1183398151915286016141c8565b8051909790614249906001600160a01b0316611970565b9861426e6142626020809b01516001600160601b031690565b6001600160601b031690565b948381108015614333575b6143215791600193979a956142986142a4939488035b838c0390615142565b80920198870391613257565b01970193808611801590614317575b61430c5760d15f5282906142d55f80516020615a1183398151915287016141c8565b805190890151969992966001600160a01b0390911694600193926142a49290916001600160601b039091169061429890880361428f565b945050509250509190565b50818510156142b3565b60405163e8722f8f60e01b8152600490fd5b50808b1115614279565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b031661420d565b505093505050505f905f90565b508415614202565b604290467f0000000000000000000000000000000000000000000000000000000000000000036144375761010a54905b6143cf6143c86040830183612c96565b36916116c7565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b0845235604083015260608201526060815261441a816105c1565b5190206040519161190160f01b8352600283015260228201522090565b61443f61518b565b906143b8565b6004111561444f57565b634e487b7160e01b5f52602160045260245ffd5b61446d8383615258565b5061447a81959295614445565b159384614516575b508315614490575b50505090565b5f9293509082916040516144c881612b446020820194630b135d3f60e11b998a8752602484015260406044840152606483019061061e565b51915afa906144d5612dbd565b82614508575b826144eb575b50505f808061448a565b6145009192506020808251830101910161283c565b145f806144e1565b9150602082511015916144db565b6001600160a01b0383811691161493505f614482565b9061453682612d20565b61454360405191826105dc565b8281528092614554601f1991612d20565b0190602036910137565b9060301161034e5790603090565b9060901161034e5760300190606090565b9060b01161034e5760900190602090565b9093929384831161034e57841161034e578101920390565b6020908361169d9395949560405196836145c989955180928880890191016105fd565b84019185830137015f838201520380855201836105dc565b3590602081106145ef575090565b5f199060200360031b1b1690565b916020610654938181520191612bf8565b91926146386146286146469360808652608086019061061e565b602095858203602087015261061e565b90838203604085015261061e565b906060818303910152602080845192838152019301915f5b82811061466c575050505090565b83518552938101939281019260010161465e565b614688615292565b6060906060905f809460b081049261469f8461452c565b965f905b8582106147be57506001600160a01b03947f0000000000000000000000000000000000000000000000000000000000000000945061471a9350602092506146ea9150612ceb565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af180156105225761479f575b50166147576152f7565b813b1561034e575f80946147816040519788968795869463c82655b760e01b86526004860161460e565b03925af18015610522576147925750565b8061104d61169d92610593565b6147b79060203d6020116118755761186681836105dc565b505f61474d565b61484361481361481e6148006147f77f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612a0c565b8099898961458e565b92909a61480d848d61455e565b916145a6565b9a61480d838c61456c565b988b61483d86614837614831868661457d565b906145e1565b92612e4a565b5261455e565b90614853604051928392836145fd565b0390a1600101836146a3565b9294614898670de0b6b3a76400009661488a608097946148a6969b9a9b60a0895260a0890191612bf8565b90868203602088015261061e565b918483036040860152612bf8565b9460608201520152565b906148b9615292565b6148c3818361455e565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af18015610522576149f0575b5016906149556152f7565b9161496e614831614966848961456c565b94909861457d565b95813b1561034e575f809461499b604051998a9687958694630cac9f3160e01b86528c8c6004880161485f565b03925af1928315610522577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936149dd575b50612fb6604051928392836145fd565b8061104d6149ea92610593565b5f6149cd565b614a089060203d6020116118755761186681836105dc565b505f61494a565b90614a18613e19565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561052257614ab294613e8e925f91614ad5575b508411614ac8575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836105dc565b61169d60015f80516020615a3183398151915255565b614ad0615292565b614a7d565b614aee915060203d60201161051b5761050d81836105dc565b5f614a75565b60cf54906001600160801b03821681158015614b23575b15614b165750905090565b6106549260801c91613257565b508015614b0b565b60cf546001600160801b0381169081614b48575050633b9aca0090565b60801c614b5581836131d2565b918115612ce657633b9aca0009614b695790565b60018101809111156106545761287b565b60cf546001600160801b0381169082158015614bb9575b15614b9b57505090565b60801c90614baa828285613257565b928215612ce65709614b695790565b508115614b91565b614bc961375c565b6001600160a01b03168015614c1157609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b6001600160a01b03908116919082158015614c95575b6107e457825f5260d360205260405f2090815492858403938411610ba1575f805160206159f18339815191529360209355614c848160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614c39565b5f80614cc79260018060a01b03169360208151910182865af1614cc0612dbd565b908361594d565b8051908115159182614cf5575b5050614cdd5750565b60249060405190635274afe760e01b82526004820152fd5b614d089250602080918301019101612af3565b155f80614cd4565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614d3f57565b604051631afcd79f60e31b8152600490fd5b614d59614d10565b61271061ffff831611614d9057614d6f90614bc1565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614daa614d10565b8015614dc05760018101614dbb5750565b60d455565b6040516331278a8760e01b8152600490fd5b614dda614d10565b670de0b6b3a7640000614deb6129fe565b10614dc057614df861518b565b61010a55565b614e06614d10565b6001600160a01b031680614e175750565b6101a180546001600160a01b0319169091179055565b614e35614d10565b601e8151118015614f4f575b614f3d57614e4d614d10565b8051906001600160401b03821161058e57614e7182614e6c5f54610527565b615523565b602090816001601f851114614ec957509180614ea792614eae95945f92614ebe575b50508160011b915f199060031b1c19161790565b5f556155ed565b61169d614eb9613e93565b600455565b015190505f80614e93565b5f80529190601f1984165f805160206159b1833981519152935f905b828210614f25575050916001939185614eae97969410614f0d575b505050811b015f556155ed565b01515f1960f88460031b161c191690555f8080614f00565b80600186978294978701518155019601940190614ee5565b604051632d3f993760e21b8152600490fd5b50600a825111614e41565b614f62614d10565b614f6a614d10565b614f72614d10565b60015f80516020615a3183398151915255614f8b61375c565b30156107e457633b9aca008060cf5460801c01614fa66129fe565b811161502e57614fc0610ef0614fba614b2b565b926137e7565b614fca8130615320565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a361169d30337f0000000000000000000000000000000000000000000000000000000000000000613e48565b6040516304ffa0ff60e51b8152600490fd5b9081602091031261034e57516106548161251c565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816150df575b506150a557604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206159d183398151915284036150c65761169d9293506156cb565b604051632a87526960e21b815260048101859052602490fd5b6150f991955060203d60201161051b5761050d81836105dc565b935f61507f565b60d1548061510d57505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b0316611970565b908082101561514f575090565b905090565b60d554908160801c81158015615183575b156151705750905090565b6001600160801b03610654931691613257565b508015615165565b6e5661756c7456616c696461746f727360881b60206040516151ac81610573565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b0382111761058e5760405251902090565b8151919060418303615288576152819250602082015190606060408401519301515f1a9061576d565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561034e575f809160246040518094819363a3066aab60e01b83523060048401525af18015610522576152ee5750565b61169d90610593565b604051600160f81b60208201525f60218201523060601b602c8201526020815261065481610573565b5f805160206159f183398151915260205f9261533b856137e7565b60cf54906153536001600160801b03918284166128f7565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b0382169182156154b25760801c6153c36153b4826153af613d2b565b612b07565b6153bd856128d1565b90615142565b9081156154ab576153d382614af4565b9384156154a35782615420611eeb6130ac61169d96610ef09661541b6153ff6130ac8d6154989a612b07565b6001600160801b03166001600160801b031960d054161760d055565b612a1a565b61542a818761585f565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a16130ac61547c61546b886137e7565b60cf546001600160801b031661288f565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c61288f565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f81815260d360205260409020805483810391908211610ba1575f935f805160206159f183398151915292602092556154f9816137e7565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b601f811161552f575050565b5f80525f805160206159b1833981519152906020601f840160051c83019310615572575b601f0160051c01905b818110615567575050565b5f815560010161555c565b9091508190615553565b90601f8211615589575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c830193106155e3575b601f0160051c01905b8181106155d957505050565b5f815582016155cd565b90915081906155c4565b9081516001600160401b03811161058e576001906156148161560f8454610527565b61557c565b602080601f8311600114615649575081906156459394955f92614ebe5750508160011b915f199060031b1c19161790565b9055565b90601f1983169561567b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b8882106156b4575050838596971061569c575b505050811b019055565b01515f1960f88460031b161c191690555f8080615692565b80878596829496860151815501950193019061567f565b90813b1561574c575f805160206159d183398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561573157612ff591615934565b50503461573a57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116157f657906157c66020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15610522575f516001600160a01b038116156157ec57905f905f90565b505f906001905f90565b5050505f9160039190565b60d154906801000000000000000082101561058e57600182018060d155821015612dab5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020615a1183398151915290910155565b9190918015801561592c575b61591a57615877615100565b908101809111610ba1576001600160a01b038082116158fa576001600160601b03908185116158da579061169d93946158c46158d5936158b561169f565b95166001600160a01b03168552565b166001600160601b03166020830152565b615801565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561586b565b5f8061065493602081519101845af461594b612dbd565b915b90615974575080511561596257805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806159a7575b615985575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561597d56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212208b01db5292bb89ece855b79c6de0cffe4d0ab4b183e773755cfcc0c4955317eb64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoGenesisVault.json b/test/shared/artifacts/GnoGenesisVault.json deleted file mode 100644 index 76133ec1..00000000 --- a/test/shared/artifacts/GnoGenesisVault.json +++ /dev/null @@ -1,1621 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoGenesisVault", - "sourceName": "contracts/vaults/gnosis/GnoGenesisVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "address", - "name": "poolEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "rewardGnoToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialHarvest", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "capacity", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint16", - "name": "feePercent", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "GenesisVaultCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Migrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "acceptPoolEscrowOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "migrate", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x610240346200033457620056e7601f38829003908101601f19168301906001600160401b039081831185841017620003385780859460409485528539610180938491810103126200033457620000e4926200005a856200034c565b9162000069602087016200034c565b93620000778188016200034c565b9262000086606089016200034c565b9762000095608082016200034c565b94620000a460a083016200034c565b93620000b360c084016200034c565b96620000c260e085016200034c565b966101009c8d9a620000d68c88016200034c565b9a6101209e8f89016200034c565b9c61014097620000f6898b016200034c565b9f610160809b01519460805260a05260c0523060e052528d469052855260018060a01b03928380921687521686526101a0968752816101c0981688526101e09889527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82861c1662000323578080831603620002de575b50505080610200991689526102209916895251986153859a8b620003628c396080518b8181610518015281816117e60152818161197e01528181613037015281816133ba0152613446015260a0518b61156e015260c0518b8181613a40015281816142bd015281816144d901528181614f220152615230015260e0518b81816116dd0152613c350152518a612c6301525189613f9601525188611b2401525187818161033d0152818161074c01528181610a1201528181612c9a015281816135e40152613680015251868181610ad1015281816111fb01528181613568015261373f015251858181612563015261307f015251848181610ef9015281816139cd01528181614327015281816145230152818161463401528181614a7301528181614ca20152614f9e01525183612bb10152518281816105e10152818161095d015281816122250152818161399a0152614efe01525181818161057f0152818161211e01526131d90152f35b6001600160401b0319909116811790915582519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f808062000173565b845163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620003345756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d114146102a9578063066055e0146102a457806307a2d13a1461029f5780631a7ff5531461029a578063201b9eb51461029557806323d18ed8146102905780632999ad3f1461028b5780632cdf7401146102865780632e2d2984146102815780633229fa951461027c57806333194c0a146102775780633a98ef3914610272578063439fab911461026d57806343e82a791461026857806346904840146102635780634ec96b221461025e5780634f1ef2861461025957806352d1902d1461025457806354fd4d501461024f5780635c60da1b1461024a5780635cfc1a511461024557806360d60e6e1461024057806372b410a81461023b578063754c38881461023657806376b58b90146102315780637fd6f15c1461022c57806383d430d5146102275780638697d2c2146102225780638ceab9aa1461021d578063a49a1e7d14610218578063ac9650d814610213578063ad3cb1cc1461020e578063ad68ebf714610209578063b0d1130214610204578063b1f0e7c7146101ff578063c6e6f592146101fa578063d83ad00c146101f5578063e74b981b146101f0578063ee3bd5df146101eb578063f04da65b146101e65763f851a4400361000e5761239f565b612364565b61233e565b612311565b6122eb565b6122cd565b6122b3565b612280565b6120f2565b6120ad565b612037565b611f3c565b611d53565b611af8565b611928565b611904565b6118b3565b611848565b6117bb565b61179d565b611783565b61174f565b611734565b6116cb565b611456565b6112f1565b6112c9565b6111cc565b611101565b611080565b611046565b61101a565b610e9e565b610e84565b6109e8565b610942565b6106e3565b6104b7565b610491565b6102ed565b6102bc565b5f9103126102b857565b5f80fd5b346102b8575f3660031901126102b857602060985460801c604051908152f35b6001600160801b038116036102b857565b346102b85760203660031901126102b85760043561030a816102dc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561048c575f9161045d575b50335f90815261013760205260409020610386906123e0565b916001600160801b036103a084516001600160801b031690565b161561044b576103f4836103b661044795612c85565b6103e06103d3846103ce84516001600160801b031690565b612419565b6001600160801b03168252565b335f90815261013760205260409020612437565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61047f915060203d602011610485575b61047781836113e4565b8101906123c6565b5f61036d565b503d61046d565b6123d5565b346102b85760203660031901126102b85760206104af600435612469565b604051908152f35b346102b857602060031981813601126102b8576004918235916001600160401b0383116102b85760809083360301126102b857604051630156a69560e11b81523084820190815290926001600160a01b0392918290859081906020010381867f0000000000000000000000000000000000000000000000000000000000000000165afa93841561048c575f9461069f575b50610554908501613006565b50809315610566575b610018846131c5565b60405163070aab0d60e11b8152929350909190828286817f000000000000000000000000000000000000000000000000000000000000000088165afa801561048c576001600160801b036105c6916105cc945f91610672575b501661318c565b906124c5565b91604051638da5cb5b60e01b815282818681857f0000000000000000000000000000000000000000000000000000000000000000165afa92831561048c575f93610643575b505016301480159061063a575b61062a5781808061055d565b5060405163c284f82560e01b8152fd5b505f811261061e565b610663929350803d1061066b575b61065b81836113e4565b8101906124dd565b905f80610611565b503d610651565b6106929150863d8811610698575b61068a81836113e4565b8101906124b0565b5f6105bf565b503d610680565b6105549194506106c490833d85116106cb575b6106bc81836113e4565b81019061249c565b9390610548565b503d6106b2565b6001600160a01b038116036102b857565b346102b85760603660031901126102b857600435610700816106d2565b6024359060443590610711826106d2565b61071961339f565b61072161342b565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af194851561048c575f95610923575b50335f9081526101376020526040902061079c906123e0565b926001600160801b036107b685516001600160801b031690565b16156108bf5750506107c782612c85565b6107f36107e66107d6876134b6565b84516001600160801b03166124f2565b6001600160801b03168352565b335f908152609c6020526040902061081590610810905b54612469565b613545565b61083561082984516001600160801b031690565b6001600160801b031690565b116108ad57335f90815261013760205260409020610447957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5893909161087b9190612437565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610434565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561048c57610901926108f2915f91610906575b506134b6565b6001600160801b031690840152565b6107c7565b61091d9150833d85116104855761047781836113e4565b5f6108ec565b61093b919550833d85116104855761047781836113e4565b935f610783565b346102b8575f806003193601126102b85761095b61364f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102b8575f809160046040518094819363b4b6d74f60e01b83525af1801561048c576109b2575080f35b610018915061137b565b60609060031901126102b857600435906024356109d8816106d2565b906044356109e5816106d2565b90565b346102b8576109f6366109bc565b906001600160a01b0380831615610e7257610a0f61342b565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102b85760408051631d8557d760e01b815260049491905f81878183875af1801561048c57610e59575b506001600160a01b0383165f90815261013760205260409020610a82906123e0565b6001600160801b039283610a9d83516001600160801b031690565b1615610e4957610aac82612c85565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561048c575f98610e18575b50602097888101956001600160401b03918280610b258a516001600160401b031690565b1614610e0857908c92918751918c8380610b516303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561048c57610b7d938e5f94610de3575b5050516001600160801b03165b1690612d3a565b96610b9b61080a8a60018060a01b03165f52609c60205260405f2090565b928389118015610dd3575b610dc357908b610be49392610bc289516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561048c57670de0b6b3a764000094610c33948e5f95610d96575b5050610c25610c17610c2b92612987565b93516001600160401b031690565b93612987565b921690612ead565b1015610d88578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561048c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610d6595610cdd93610d6a575b5050610cc06103d3610cb08c6134b6565b83516001600160801b0316612419565b6001600160a01b0386165f90815261013760205260409020612437565b610ce68261474c565b90610d24610d09610cf6856134b6565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610d2e8286614a00565b610d388389614616565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610d8092903d106104855761047781836113e4565b505f80610c9f565b835163185cfc6d60e11b8152fd5b610c2b929550610db9610c259282610c1793903d106104855761047781836113e4565b959250508e610c06565b875163efda1a2760e01b81528590fd5b50610ddc61250d565b8911610ba6565b610b769294509081610e0092903d106104855761047781836113e4565b92908e610b69565b8651630709133160e01b81528490fd5b610e3b91985060603d606011610e42575b610e3381836113e4565b8101906134fd565b965f610b01565b503d610e29565b825163673f032f60e11b81528790fd5b80610e66610e6c9261137b565b806102ae565b5f610a60565b60405163d92e233d60e01b8152600490fd5b346102b8575f3660031901126102b85760206104af61250d565b346102b857610eac366109bc565b91610eb5613ab9565b604080516323b872dd60e01b602082015233602482015230604482015260648101839052909390610f1d90610ef781608481015b03601f1981018352826113e4565b7f0000000000000000000000000000000000000000000000000000000000000000614ae5565b610f2561342b565b6001600160a01b038316928315611009578215610ff85782610f4c61082960985460801c90565b0190610f566126b1565b8211610fe757610fcd610d099593610fa786947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610fa2610f9a60209c9a6147d2565b9a8b936134b6565b614700565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f805160206153308339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b346102b8575f3660031901126102b857602061103461254a565b6040516001600160a01b039091168152f35b346102b8575f3660031901126102b85760206040517f017d4155da73718dbec8960abca1d9f85d2dc8a31aa06e2d8e4410b4b093144a8152f35b346102b8575f3660031901126102b85760206001600160801b0360985416604051908152f35b9181601f840112156102b8578235916001600160401b0383116102b857602083818601950101116102b857565b60206003198201126102b857600435906001600160401b0382116102b8576110fd916004016110a6565b9091565b346102b85761110f366110d3565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c1680156111b8575b6111a657680100000000000000036111699368ffffffffffffffffff19161784556125b4565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015611143565b346102b8576111da366109bc565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561048c5782915f916112aa575b501633036112985781610d6561126586867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613662565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6112c3915060203d60201161066b5761065b81836113e4565b5f61122d565b346102b8575f3660031901126102b8576065546040516001600160a01b039091168152602090f35b346102b85760203660031901126102b85760043561130e816106d2565b60018060a01b03165f52610137602052602060405f206040519061133182611393565b54906001600160801b03918281169081835260801c84830152611359575b5116604051908152f35b61136281612c85565b61134f565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161138e57604052565b611367565b604081019081106001600160401b0382111761138e57604052565b606081019081106001600160401b0382111761138e57604052565b608081019081106001600160401b0382111761138e57604052565b90601f801991011681019081106001600160401b0382111761138e57604052565b6001600160401b03811161138e57601f01601f191660200190565b92919261142c82611405565b9161143a60405193846113e4565b8294818452818301116102b8578281602093845f960137010152565b6040806003193601126102b8576004908135611471816106d2565b6024356001600160401b0381116102b857366023820112156102b8576114a09036906024818701359101611420565b916114a9613c2b565b8051926114e0846114d260209363439fab9160e01b858401528460248401526044830190611faf565b03601f1981018652856113e4565b6114e8613c2b565b6114f061364f565b6001600160a01b03838116801592919087908415611696575b8415611628575b84156115c5575b5050821561153f575b5050611530576100188383614cf1565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561048c575f926115a8575b5050155f80611520565b6115be9250803d106106cb576106bc81836113e4565b5f8061159e565b855163054fd4d560e41b81529294508391839182905afa90811561048c57879160ff915f916115fb575b5016141591865f611517565b61161b9150843d8611611621575b61161381836113e4565b810190614cd8565b5f6115ef565b503d611609565b935050835163198ca60560e11b815282818981875afa90811561048c5788917f017d4155da73718dbec8960abca1d9f85d2dc8a31aa06e2d8e4410b4b093144a915f91611679575b50141593611510565b6116909150853d87116104855761047781836113e4565b5f611670565b5f805160206153108339815191525490945084906116c4906001600160a01b03165b6001600160a01b031690565b1493611509565b346102b8575f3660031901126102b8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036117225760206040515f805160206153108339815191528152f35b60405163703e46dd60e11b8152600490fd5b346102b8575f3660031901126102b857602060405160038152f35b346102b8575f3660031901126102b8575f80516020615310833981519152546040516001600160a01b039091168152602090f35b346102b8575f3660031901126102b85760206104af6126b1565b346102b85760203660031901126102b85760206104af6004356126da565b346102b8575f3660031901126102b857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561048c576020915f9161182b575b506040519015158152f35b6118429150823d84116106cb576106bc81836113e4565b5f611820565b346102b85760203660031901126102b857600435611865816106d2565b61186d61364f565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102b85760803660031901126102b8576104476118e76004356118d6816106d2565b6064359060443590602435906127ae565b604080519384526020840192909252908201529081906060820190565b346102b8575f3660031901126102b857602061ffff60655460a01c16604051908152f35b346102b8576003196040368201126102b85760049081356001600160401b038082116102b85760a08285019383360301126102b8576024359081116102b85761197490369085016110a6565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102b85760405163837d444160e01b8152905f9082908183816119c78c828f0161289c565b03925af1801561048c57611ae5575b506119df61342b565b6119e7612c4f565b9081163314159182611ab6575b50509050611aa5576044019160b0611a0c848461291a565b90500480158015611a8d575b611a7d57611a2d611a2761250d565b9161296f565b11611a6e575060b0611a3f838361291a565b9050145f14611a5b5761001891611a559161291a565b906144b7565b61001891611a689161291a565b90614287565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611a98848461291a565b905060b082021415611a18565b604051634ca8886760e01b81528390fd5b611ad99250611ad3611add94611acb88613f90565b923691611420565b9161406a565b1590565b805f806119f4565b80610e66611af29261137b565b5f6119d6565b346102b85760603660031901126102b857600435602435611b1d6044358284336127ae565b9192611b497f0000000000000000000000000000000000000000000000000000000000000000826126cd565b42108015611d4b575b8015611d43575b611d31577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611b9d86611b986108296099546001600160801b031690565b613c84565b15611c9f57611bd7611bbc611bb1866134b6565b60995460801c612419565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611c1b9190611c0a6080826113e4565b5190205f52609b60205260405f2090565b555f9360018311611c54575b50505050611c358233614616565b604080519485526020850191909152830152339180606081015b0390a2005b611c9592939450611c6590886126cd565b6040805133602082019081529181019390935260608301829052608095860183529094909190611c0a90826113e4565b555f808080611c27565b611ca761342b565b611ce3611cc7611cb6866134b6565b609e546001600160801b0316612419565b6001600160801b03166001600160801b0319609e541617609e55565b611d18611cfd611cf2856134b6565b609e5460801c612419565b6001600160801b03609e549181199060801b16911617609e55565b611d2c611d2784609f546126cd565b609f55565b611bd7565b604051630e3d8e8d60e11b8152600490fd5b508215611b59565b508115611b52565b346102b8576040806003193601126102b85760243590600435611d75836106d2565b611d7d61342b565b8015611f2b576001600160a01b038316908115611f1a57611d9d81612469565b908115611f0957611dad82614dae565b611db6836134b6565b60985460801c90611dc691612419565b611de5906001600160801b036098549181199060801b16911617609855565b611def8233614a00565b609e54958660801c8281609f5490611e06916126cd565b98611e10876134b6565b611e22916001600160801b03166124f2565b611e42906001600160801b03166001600160801b0319609e541617609e55565b611e4b916126cd565b611e54906134b6565b611e73906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611ea46080826113e4565b519020611eb9905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611f003361508a565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346102b857611c4f7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611f6e366110d3565b9290611f7861364f565b604051918291602083523395602084019161287c565b5f5b838110611f9f5750505f910152565b8181015183820152602001611f90565b90602091611fc881518092818552858086019101611f8e565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120095750505050505090565b9091929394958480612027600193603f198682030187528a51611faf565b9801930193019194939290611ff9565b346102b85760203660031901126102b8576001600160401b036004358181116102b857366023820112156102b85780600401359182116102b8573660248360051b830101116102b8576104479160246120909201612ae2565b60405191829182611fd4565b9060206109e5928181520190611faf565b346102b8575f3660031901126102b8576104476040516120cc81611393565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611faf565b346102b8576040806003193601126102b857600435612110816106d2565b6024356001600160a01b03337f0000000000000000000000000000000000000000000000000000000000000000821614801590612210575b6121ff5761215461339f565b61215c61342b565b821615611f1a5780156121ee57917fd083678824038160bef3975359ab29f19c3f0e9bcf9d7ead540a492d4d678b63836121986104479561474c565b936121b3610d096121a8846134b6565b60985460801c6124f2565b6121bd8582614700565b83516001600160a01b03919091168152602081019190915260408101849052606090a1519081529081906020820190565b82516318374fd160e21b8152600490fd5b8351634ca8886760e01b8152600490fd5b508351638da5cb5b60e01b81526020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561048c575f91612261575b508116301415612148565b61227a915060203d60201161066b5761065b81836113e4565b5f612256565b346102b8575f3660031901126102b857612298613ab9565b6122a0612b8f565b60015f8051602061533083398151915255005b346102b8575f3660031901126102b8576020611034612c4f565b346102b85760203660031901126102b85760206104af60043561474c565b346102b8575f3660031901126102b85760206001600160801b0360995416604051908152f35b346102b85760203660031901126102b857610018600435612331816106d2565b61233961364f565b614819565b346102b8575f3660031901126102b85760206001600160801b03609e5416604051908152f35b346102b85760203660031901126102b857600435612381816106d2565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102b8575f3660031901126102b8575f546040516001600160a01b039091168152602090f35b908160209103126102b8575190565b6040513d5f823e3d90fd5b906040516123ed81611393565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161243257565b612405565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b038116908161248157505090565b916109e59260801c90612ead565b519081151582036102b857565b908160209103126102b8576109e59061248f565b908160209103126102b857516109e5816102dc565b81810392915f13801582851316918412161761243257565b908160209103126102b857516109e5816106d2565b9190916001600160801b038080941691160191821161243257565b61251561397b565b6099546001600160801b0361252b818316612469565b90609e5416019060801c01908181115f14612544570390565b50505f90565b61016a546001600160a01b031680156125605790565b507f000000000000000000000000000000000000000000000000000000000000000090565b906109e5949360809361ffff9260018060a01b0316845260208401521660408201528160608201520190611faf565b5f546001600160a01b03929083166126ac578101906040818303126102b8578035916125df836106d2565b60208201356001600160401b03928382116102b85701926060848303126102b8576040519261260d846113ae565b8435845260208501359461ffff861686036102b8576020850195865260408101359182116102b857019180601f840112156102b8577f6efc3c5ea2064c46840711aa5ff8d7f70826faa0cc04fcf0557a3863533aafad9561267a612698928560206126a797359101611420565b9260408601938452169361268e8186613b44565b51945161ffff1690565b90519060405194859485612585565b0390a1565b505050565b609d54806109e557505f1990565b9060b0820180921161243257565b9190820180921161243257565b6126ef816001600160801b0360995416613c84565b61271657612707609f54612701613cdf565b906126cd565b1115612711575f90565b5f1990565b609a90609a549182915f905b84821061273c575050508110156127365790565b505f1990565b909193808316906001818518811c8301809311612432575f8790527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be48301546001600160a01b0316841015612796575050935b9190612722565b90959101925061278f565b9190820391821161243257565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906127e28160808101610ee9565b5190205f52609b60205260405f205491821561284057829061280f836001600160801b0360995416613c84565b1561282e579161281e92613dcf565b90915b8281039081116124325792565b509061283991613d4f565b9091612821565b5050505f905f905f90565b9035601e19823603018112156102b85701602081359101916001600160401b0382116102b85781360383136102b857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06109e5926020815282356020820152602083013560408201526128d86128c8604085018561284b565b84606085015260c084019161287c565b9061290b6129006128ec606087018761284b565b601f1985870381016080870152959161287c565b94608081019061284b565b9390928286030191015261287c565b903590601e19813603018212156102b857018035906001600160401b0382116102b8576020019181360383136102b857565b634e487b7160e01b5f52601260045260245ffd5b811561296a570490565b61294c565b90670de0b6b3a7640000918083029283040361243257565b90670de0b6b3a76400009182810292818404149015171561243257565b6001600160401b03811161138e5760051b60200190565b906129c5826129a4565b6129d260405191826113e4565b82815280926129e3601f19916129a4565b01905f5b8281106129f357505050565b8060606020809385010152016129e7565b634e487b7160e01b5f52603260045260245ffd5b90821015612a2f576110fd9160051b81019061291a565b612a04565b908092918237015f815290565b3d15612a6b573d90612a5282611405565b91612a6060405193846113e4565b82523d5f602084013e565b606090565b6020818303126102b8578051906001600160401b0382116102b8570181601f820112156102b8578051612aa281611405565b92612ab060405194856113e4565b818452602082840101116102b8576109e59160208085019101611f8e565b8051821015612a2f5760209160051b010190565b919091612aee836129bb565b925f5b818110612afd57505050565b5f80612b0a838587612a18565b60409391612b1c855180938193612a34565b0390305af490612b2a612a41565b9115612b51575090600191612b3f8288612ace565b52612b4a8187612ace565b5001612af1565b9060448151106102b857612b8b612b7660049283810151602480918301019101612a70565b925162461bcd60e51b8152928392830161209c565b0390fd5b47633b9aca008110612c4c57604051638119c06560e01b8152602081600481857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af191821561048c577f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db926040925f91612c2d575b50612c20612c1b8261318c565b6131c5565b82519182526020820152a1565b612c46915060203d6020116104855761047781836113e4565b5f612c0e565b50565b60d2546001600160a01b0316806109e557507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561048c575f91612d1b575b5060208201916001600160801b03918284511691828214612d145783612d07612d02612d0f958584865116612ead565b6134b6565b1690526134b6565b169052565b5050505050565b612d34915060203d6020116104855761047781836113e4565b5f612cd2565b90808202905f1981840990828083109203918083039214612daf57670de0b6b3a76400009082821115612d9d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a764000091500490565b90808202905f1981840990828083109203918083039214612e1d576127109082821115612d9d577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b505061271091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612ea05784831115612d9d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906109e59250612960565b9091828202915f1984820993838086109503948086039514612ea05784831115612d9d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102b8578051916109e560406020840151930161248f565b81835290916001600160fb1b0383116102b85760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102b85760408301526040810135612f92816106d2565b6001600160a01b031660608381019190915281013536829003601e19018112156102b85701602081359101906001600160401b0381116102b8578060051b360382136102b85760a0836080806109e59601520191612f3f565b9190915f838201938412911290801582169115161761243257565b6040516325f56f1160e01b81526001600160a01b039291606090829081906130319060048301612f63565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561048c575f915f905f95613157575b508415613104578161307b61254a565b16917f00000000000000000000000000000000000000000000000000000000000000001682146130fd57509060205f92600460405180958193634641257d60e01b83525af190811561048c576130d8925f926130dc575b50612feb565b9190565b6130f691925060203d6020116104855761047781836113e4565b905f6130d2565b908161310a575b50509190565b803b156102b857604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561048c57613144575b80613104565b80610e666131519261137b565b5f61313e565b9194505061317d915060603d606011613185575b61317581836113e4565b810190612f20565b93905f61306b565b503d61316b565b6001600160ff1b03811161319d5790565b6024906040519063123baf0360e11b82526004820152fd5b600160ff1b8114612432575f0390565b8015612c4c576040516278744560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691906020908181600481875afa90811561048c575f91613382575b50604051631cd5ec3960e31b8152908282600481885afa91821561048c5761324c935f93613363575b50506127a1565b80156133585761326a8161326561082960985460801c90565b6126cd565b905f8312156132f45761328e9161328991613284856131b5565b612ead565b61318c565b613297816131b5565b92803b156102b85760405163304f0a6b60e21b815260048101949094525f908490602490829084905af191821561048c576132df936132da936132e15750612feb565b61487b565b565b80610e666132ee9261137b565b5f6130d2565b613302916132899184612ead565b823b156102b85760405163304f0a6b60e21b815260048101829052925f908490602490829084905af191821561048c576132df936132da93613345575b506124c5565b80610e666133529261137b565b5f61333f565b506132df915061487b565b61337a929350803d106104855761047781836113e4565b905f80613245565b6133999150823d84116104855761047781836113e4565b5f61321c565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561048c575f9161340c575b50156133fa57565b604051630a62fbdb60e11b8152600490fd5b613425915060203d6020116106cb576106bc81836113e4565b5f6133f2565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561048c575f91613497575b5061348557565b60405163e775715160e01b8152600490fd5b6134b0915060203d6020116106cb576106bc81836113e4565b5f61347e565b6001600160801b03908181116134ca571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b51906001600160401b03821682036102b857565b908160609103126102b85761353d6040805192613519846113ae565b8051613524816102dc565b8452613532602082016134e9565b6020850152016134e9565b604082015290565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561048c576135e0936001600160401b03610b7660406135bf946020975f91613630575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561048c575f91613617575090565b6109e5915060203d6020116104855761047781836113e4565b613649915060603d606011610e4257610e3381836113e4565b5f6135b0565b5f546001600160a01b0316330361129857565b92906001600160a01b039081811615610e725761367d61342b565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102b857604094855193631d8557d760e01b85526004945f81878183895af1801561048c57613968575b506001600160a01b0388165f908152610137602052604090206136f0906123e0565b906001600160801b0361370a83516001600160801b031690565b16156139585761371982612c85565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561048c57613939575b508651936303d1689d60e11b97888652602091828780613793888c83019190602083019252565b0381845afa96871561048c575f9761391a575b5086996137c661080a8d60018060a01b03165f52609c60205260405f2090565b8811801561390a575b6138fa57908361380c926137ea87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561048c575f859488946138519c6138dd575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561048c57610cb06138989461387b936103d3936132df9a6138bf575b50506134b6565b6001600160a01b0388165f90815261013760205260409020612437565b6138ba6138a48361474c565b80976138b5610d09610cf6876134b6565b614a00565b614616565b816138d592903d106104855761047781836113e4565b505f80613874565b6138f390873d89116104855761047781836113e4565b505f613826565b825163efda1a2760e01b81528990fd5b5061391361250d565b88116137cf565b613932919750833d85116104855761047781836113e4565b955f6137a6565b6139519060603d606011610e4257610e3381836113e4565b505f61376c565b875163673f032f60e11b81528690fd5b80610e666139759261137b565b5f6136ce565b613983614a4d565b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483018190526020939084846024817f000000000000000000000000000000000000000000000000000000000000000087165afa93841561048c57613a3c948693613a0e925f92613a9a575b506126cd565b60405163be7ab51b60e01b81526001600160a01b039092166004830152909390928491829081906024820190565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561048c576109e5935f93613a7b575b50506126cd565b613a92929350803d106104855761047781836113e4565b905f80613a74565b613ab2919250853d87116104855761047781836113e4565b905f613a08565b5f805160206153308339815191526002815414613ad65760029055565b604051633ee5aeb560e01b8152600490fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca00606480830191909152815260a08101916001600160401b0383118284101761138e576132df92604052614ae5565b90613b4d614b56565b6040810151613b5a614b56565b6001600160a01b0383168015610e72576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613bb333946020830190611faf565b0390a26020810151613bc3614b56565b61271061ffff821611613c1957613bdc613c0193614819565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614b97565b613c09614bc7565b613c11614b56565b6132df614bf2565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613c69575b505061172257565b5f805160206153108339815191525416141590505f80613c61565b90609a5480155f14613caa57505f5b6001600160a01b0316918201918210612432571090565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b0316613c93565b613ce761397b565b6099548060801c82039182116124325781613d0b6001600160801b03809316612469565b9081613d31575b50508115612544576109e591613d2c91609e541690614d9c565b614dae565b9192509081811115613d4757035b905f80613d12565b50505f613d3f565b613d57613cdf565b91609f549283018093116124325780831115613da157613d78920390614d9c565b90609e548060801c80155f14613d8e5750508190565b6001600160801b036109e5921684612ead565b5050505f905f90565b90604051613db781611393565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613f88575b613f7b5783613f45575f5b609a5f526001600160a01b0316613e277f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be48601613daa565b8051909790613e3e906001600160a01b03166116b8565b98613e63613e576020809b01516001600160601b031690565b6001600160601b031690565b948381108015613f3b575b613f295791600193979a95613e8d613e99939488035b838c0390614d9c565b80920198870391612ead565b01970193808611801590613f1f575b613f1457609a5f528290613edd7f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be48701613daa565b805190890151969992966001600160a01b039091169460019392613e999290916001600160601b0390911690613e8d908803613e84565b945050509250509190565b5081851015613ea8565b60405163e8722f8f60e01b8152600490fd5b50808b1115613e6e565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613def565b505093505050505f905f90565b508415613de4565b604290467f00000000000000000000000000000000000000000000000000000000000000000361403e5760d354905b613fd6613fcf604083018361291a565b3691611420565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152614021816113c9565b5190206040519161190160f01b8352600283015260228201522090565b614046614de5565b90613fbf565b6004111561405657565b634e487b7160e01b5f52602160045260245ffd5b6140748383614eb2565b506140818195929561404c565b15938461411d575b508315614097575b50505090565b5f9293509082916040516140cf81610ee96020820194630b135d3f60e11b998a87526024840152604060448401526064830190611faf565b51915afa906140dc612a41565b8261410f575b826140f2575b50505f8080614091565b614107919250602080825183010191016123c6565b145f806140e8565b9150602082511015916140e2565b6001600160a01b0383811691161493505f614089565b9061413d826129a4565b61414a60405191826113e4565b828152809261415b601f19916129a4565b0190602036910137565b906030116102b85790603090565b906090116102b85760300190606090565b9060b0116102b85760900190602090565b909392938483116102b85784116102b8578101920390565b602090836132df9395949560405196836141d08995518092888089019101611f8e565b84019185830137015f838201520380855201836113e4565b3590602081106141f6575090565b5f199060200360031b1b1690565b9160206109e593818152019161287c565b919261423f61422f61424d93608086526080860190611faf565b6020958582036020870152611faf565b908382036040850152611faf565b906060818303910152602080845192838152019301915f5b828110614273575050505090565b835185529381019392810192600101614265565b61428f614eec565b6060906060905f809460b08104926142a684614133565b965f905b8582106143c557506001600160a01b03947f000000000000000000000000000000000000000000000000000000000000000094506143219350602092506142f1915061296f565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561048c576143a6575b501661435e615061565b813b156102b8575f80946143886040519788968795869463c82655b760e01b865260048601614215565b03925af1801561048c576143995750565b80610e666132df9261137b565b6143be9060203d6020116106cb576106bc81836113e4565b505f614354565b61444a61441a6144256144076143fe7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c6126bf565b80998989614195565b92909a614414848d614165565b916141ad565b9a614414838c614173565b988b6144448661443e6144388686614184565b906141e8565b92612ace565b52614165565b9061445a60405192839283614204565b0390a1600101836142aa565b929461449f670de0b6b3a764000096614491608097946144ad969b9a9b60a0895260a089019161287c565b908682036020880152611faf565b91848303604086015261287c565b9460608201520152565b906144c0614eec565b6144ca8183614165565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af1801561048c576145f7575b50169061455c615061565b9161457561443861456d8489614173565b949098614184565b95813b156102b8575f80946145a2604051998a9687958694630cac9f3160e01b86528c8c60048801614466565b03925af192831561048c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936145e4575b506126a760405192839283614204565b80610e666145f19261137b565b5f6145d4565b61460f9060203d6020116106cb576106bc81836113e4565b505f614551565b9061461f613ab9565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561048c576146be946146b9925f916146e1575b5084116146d4575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836113e4565b614ae5565b6132df60015f8051602061533083398151915255565b6146dc614eec565b614684565b6146fa915060203d6020116104855761047781836113e4565b5f61467c565b614709826134b6565b609854906147216001600160801b03918284166124f2565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609854906001600160801b0382168115801561477b575b1561476e5750905090565b6109e59260801c91612ead565b508015614763565b6098546001600160801b03811690816147a0575050633b9aca0090565b60801c6147ad8183612e28565b91811561296a57633b9aca00096147c15790565b60018101809111156109e557612405565b6098546001600160801b0381169082158015614811575b156147f357505090565b60801c90614802828285612ead565b92821561296a57096147c15790565b5081156147e9565b61482161342b565b6001600160a01b0316801561486957606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b8015612c4c5761489061082960985460801c90565b5f821261495d57816148a1916126cd565b906148ae610d09836134b6565b6148c36065549161ffff8360a01c1690612dc0565b80156126ac57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936149016108296098546001600160801b031690565b806149475750506126a790925b6001600160a01b0316916149228484614700565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b6126a79261495792039084612ead565b9261490e565b90614967906131b5565b61497c610829609e546001600160801b031690565b8061499c575b508061498c575050565b612d02610d09916132df936127a1565b906149f77f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916149e7611cc76149dc6149d588886126cd565b8785612ead565b8080940396036134b6565b6040519081529081906020820190565b0390a15f614982565b60018060a01b03165f52609c60205260405f2090815481810390811161243257614a2a92556134b6565b609854906001600160801b03908183160316906001600160801b03191617609855565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561048c575f91614ac8575b5060405163be7ab51b60e01b81523060048201529183908390818060248101613a3c565b614adf9150833d85116104855761047781836113e4565b5f614aa4565b5f80614b0d9260018060a01b03169360208151910182865af1614b06612a41565b90836152ac565b8051908115159182614b3b575b5050614b235750565b60249060405190635274afe760e01b82526004820152fd5b614b4e925060208091830101910161249c565b155f80614b1a565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614b8557565b604051631afcd79f60e31b8152600490fd5b614b9f614b56565b8015614bb55760018101614bb05750565b609d55565b6040516331278a8760e01b8152600490fd5b614bcf614b56565b670de0b6b3a7640000614be06126b1565b10614bb557614bed614de5565b60d355565b614bfa614b56565b614c02614b56565b614c0a614b56565b60015f8051602061533083398151915255614c2361342b565b3015610e7257633b9aca008060985460801c01614c3e6126b1565b8111614cc657614c58610d09614c52614783565b926134b6565b614c628130614700565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36132df30337f0000000000000000000000000000000000000000000000000000000000000000613ae8565b6040516304ffa0ff60e51b8152600490fd5b908160209103126102b8575160ff811681036102b85790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614d7b575b50614d4157604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206153108339815191528403614d62576132df92935061510a565b604051632a87526960e21b815260048101859052602490fd5b614d9591955060203d6020116104855761047781836113e4565b935f614d1b565b9080821015614da9575090565b905090565b609e54908160801c81158015614ddd575b15614dca5750905090565b6001600160801b036109e5931691612ead565b508015614dbf565b6e5661756c7456616c696461746f727360881b6020604051614e0681611393565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b0382111761138e5760405251902090565b8151919060418303614ee257614edb9250602082015190606060408401519301515f1a906151ac565b9192909190565b50505f9160029190565b614ef461522e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116907f00000000000000000000000000000000000000000000000000000000000000008116803b156102b85760405163a3066aab60e01b81526001600160a01b0384166004820152905f908290602490829084905af1801561048c5761504e575b506040516370a0823160e01b81526001600160a01b03831660048201527f00000000000000000000000000000000000000000000000000000000000000009190911690602081602481855afa90811561048c575f9161502f575b5080614fe457505050565b823b156102b857604051632f1a9acf60e11b81526001600160a01b039290921660048301523060248301526044820152905f908290606490829084905af1801561048c576143995750565b615048915060203d6020116104855761047781836113e4565b5f614fd9565b80610e6661505b9261137b565b5f614f7f565b604051600160f81b60208201525f60218201523060601b602c820152602081526109e581611393565b60018060a01b0381165f5261013760205260405f2090604051916150ad83611393565b54906001600160801b03918281169081855260801c6020850152156126ac5761081061080a615100926150de61342b565b6150e786612c85565b6001600160a01b03165f908152609c6020526040902090565b915116116108ad57565b90813b1561518b575f8051602061531083398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561517057612c4c91615293565b50503461517957565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615223579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1561048c575f516001600160a01b0381161561521957905f905f90565b505f906001905f90565b5050505f9160039190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102b8575f809160246040518094819363a3066aab60e01b83523060048401525af1801561048c5761528a5750565b6132df9061137b565b5f806109e593602081519101845af46152aa612a41565b915b906152d357508051156152c157805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580615306575b6152e4575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156152dc56fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212202d53672be4072773fe6660fb7912327ba8f07de769ad300539ea0d8111dde69e64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d114146102a9578063066055e0146102a457806307a2d13a1461029f5780631a7ff5531461029a578063201b9eb51461029557806323d18ed8146102905780632999ad3f1461028b5780632cdf7401146102865780632e2d2984146102815780633229fa951461027c57806333194c0a146102775780633a98ef3914610272578063439fab911461026d57806343e82a791461026857806346904840146102635780634ec96b221461025e5780634f1ef2861461025957806352d1902d1461025457806354fd4d501461024f5780635c60da1b1461024a5780635cfc1a511461024557806360d60e6e1461024057806372b410a81461023b578063754c38881461023657806376b58b90146102315780637fd6f15c1461022c57806383d430d5146102275780638697d2c2146102225780638ceab9aa1461021d578063a49a1e7d14610218578063ac9650d814610213578063ad3cb1cc1461020e578063ad68ebf714610209578063b0d1130214610204578063b1f0e7c7146101ff578063c6e6f592146101fa578063d83ad00c146101f5578063e74b981b146101f0578063ee3bd5df146101eb578063f04da65b146101e65763f851a4400361000e5761239f565b612364565b61233e565b612311565b6122eb565b6122cd565b6122b3565b612280565b6120f2565b6120ad565b612037565b611f3c565b611d53565b611af8565b611928565b611904565b6118b3565b611848565b6117bb565b61179d565b611783565b61174f565b611734565b6116cb565b611456565b6112f1565b6112c9565b6111cc565b611101565b611080565b611046565b61101a565b610e9e565b610e84565b6109e8565b610942565b6106e3565b6104b7565b610491565b6102ed565b6102bc565b5f9103126102b857565b5f80fd5b346102b8575f3660031901126102b857602060985460801c604051908152f35b6001600160801b038116036102b857565b346102b85760203660031901126102b85760043561030a816102dc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561048c575f9161045d575b50335f90815261013760205260409020610386906123e0565b916001600160801b036103a084516001600160801b031690565b161561044b576103f4836103b661044795612c85565b6103e06103d3846103ce84516001600160801b031690565b612419565b6001600160801b03168252565b335f90815261013760205260409020612437565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61047f915060203d602011610485575b61047781836113e4565b8101906123c6565b5f61036d565b503d61046d565b6123d5565b346102b85760203660031901126102b85760206104af600435612469565b604051908152f35b346102b857602060031981813601126102b8576004918235916001600160401b0383116102b85760809083360301126102b857604051630156a69560e11b81523084820190815290926001600160a01b0392918290859081906020010381867f0000000000000000000000000000000000000000000000000000000000000000165afa93841561048c575f9461069f575b50610554908501613006565b50809315610566575b610018846131c5565b60405163070aab0d60e11b8152929350909190828286817f000000000000000000000000000000000000000000000000000000000000000088165afa801561048c576001600160801b036105c6916105cc945f91610672575b501661318c565b906124c5565b91604051638da5cb5b60e01b815282818681857f0000000000000000000000000000000000000000000000000000000000000000165afa92831561048c575f93610643575b505016301480159061063a575b61062a5781808061055d565b5060405163c284f82560e01b8152fd5b505f811261061e565b610663929350803d1061066b575b61065b81836113e4565b8101906124dd565b905f80610611565b503d610651565b6106929150863d8811610698575b61068a81836113e4565b8101906124b0565b5f6105bf565b503d610680565b6105549194506106c490833d85116106cb575b6106bc81836113e4565b81019061249c565b9390610548565b503d6106b2565b6001600160a01b038116036102b857565b346102b85760603660031901126102b857600435610700816106d2565b6024359060443590610711826106d2565b61071961339f565b61072161342b565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af194851561048c575f95610923575b50335f9081526101376020526040902061079c906123e0565b926001600160801b036107b685516001600160801b031690565b16156108bf5750506107c782612c85565b6107f36107e66107d6876134b6565b84516001600160801b03166124f2565b6001600160801b03168352565b335f908152609c6020526040902061081590610810905b54612469565b613545565b61083561082984516001600160801b031690565b6001600160801b031690565b116108ad57335f90815261013760205260409020610447957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5893909161087b9190612437565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610434565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561048c57610901926108f2915f91610906575b506134b6565b6001600160801b031690840152565b6107c7565b61091d9150833d85116104855761047781836113e4565b5f6108ec565b61093b919550833d85116104855761047781836113e4565b935f610783565b346102b8575f806003193601126102b85761095b61364f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102b8575f809160046040518094819363b4b6d74f60e01b83525af1801561048c576109b2575080f35b610018915061137b565b60609060031901126102b857600435906024356109d8816106d2565b906044356109e5816106d2565b90565b346102b8576109f6366109bc565b906001600160a01b0380831615610e7257610a0f61342b565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102b85760408051631d8557d760e01b815260049491905f81878183875af1801561048c57610e59575b506001600160a01b0383165f90815261013760205260409020610a82906123e0565b6001600160801b039283610a9d83516001600160801b031690565b1615610e4957610aac82612c85565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561048c575f98610e18575b50602097888101956001600160401b03918280610b258a516001600160401b031690565b1614610e0857908c92918751918c8380610b516303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561048c57610b7d938e5f94610de3575b5050516001600160801b03165b1690612d3a565b96610b9b61080a8a60018060a01b03165f52609c60205260405f2090565b928389118015610dd3575b610dc357908b610be49392610bc289516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561048c57670de0b6b3a764000094610c33948e5f95610d96575b5050610c25610c17610c2b92612987565b93516001600160401b031690565b93612987565b921690612ead565b1015610d88578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561048c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610d6595610cdd93610d6a575b5050610cc06103d3610cb08c6134b6565b83516001600160801b0316612419565b6001600160a01b0386165f90815261013760205260409020612437565b610ce68261474c565b90610d24610d09610cf6856134b6565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610d2e8286614a00565b610d388389614616565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610d8092903d106104855761047781836113e4565b505f80610c9f565b835163185cfc6d60e11b8152fd5b610c2b929550610db9610c259282610c1793903d106104855761047781836113e4565b959250508e610c06565b875163efda1a2760e01b81528590fd5b50610ddc61250d565b8911610ba6565b610b769294509081610e0092903d106104855761047781836113e4565b92908e610b69565b8651630709133160e01b81528490fd5b610e3b91985060603d606011610e42575b610e3381836113e4565b8101906134fd565b965f610b01565b503d610e29565b825163673f032f60e11b81528790fd5b80610e66610e6c9261137b565b806102ae565b5f610a60565b60405163d92e233d60e01b8152600490fd5b346102b8575f3660031901126102b85760206104af61250d565b346102b857610eac366109bc565b91610eb5613ab9565b604080516323b872dd60e01b602082015233602482015230604482015260648101839052909390610f1d90610ef781608481015b03601f1981018352826113e4565b7f0000000000000000000000000000000000000000000000000000000000000000614ae5565b610f2561342b565b6001600160a01b038316928315611009578215610ff85782610f4c61082960985460801c90565b0190610f566126b1565b8211610fe757610fcd610d099593610fa786947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610fa2610f9a60209c9a6147d2565b9a8b936134b6565b614700565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f805160206153308339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b346102b8575f3660031901126102b857602061103461254a565b6040516001600160a01b039091168152f35b346102b8575f3660031901126102b85760206040517f017d4155da73718dbec8960abca1d9f85d2dc8a31aa06e2d8e4410b4b093144a8152f35b346102b8575f3660031901126102b85760206001600160801b0360985416604051908152f35b9181601f840112156102b8578235916001600160401b0383116102b857602083818601950101116102b857565b60206003198201126102b857600435906001600160401b0382116102b8576110fd916004016110a6565b9091565b346102b85761110f366110d3565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549160ff8360401c1680156111b8575b6111a657680100000000000000036111699368ffffffffffffffffff19161784556125b4565b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160038152a1005b60405163f92ee8a960e01b8152600490fd5b5060036001600160401b0384161015611143565b346102b8576111da366109bc565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561048c5782915f916112aa575b501633036112985781610d6561126586867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613662565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6112c3915060203d60201161066b5761065b81836113e4565b5f61122d565b346102b8575f3660031901126102b8576065546040516001600160a01b039091168152602090f35b346102b85760203660031901126102b85760043561130e816106d2565b60018060a01b03165f52610137602052602060405f206040519061133182611393565b54906001600160801b03918281169081835260801c84830152611359575b5116604051908152f35b61136281612c85565b61134f565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161138e57604052565b611367565b604081019081106001600160401b0382111761138e57604052565b606081019081106001600160401b0382111761138e57604052565b608081019081106001600160401b0382111761138e57604052565b90601f801991011681019081106001600160401b0382111761138e57604052565b6001600160401b03811161138e57601f01601f191660200190565b92919261142c82611405565b9161143a60405193846113e4565b8294818452818301116102b8578281602093845f960137010152565b6040806003193601126102b8576004908135611471816106d2565b6024356001600160401b0381116102b857366023820112156102b8576114a09036906024818701359101611420565b916114a9613c2b565b8051926114e0846114d260209363439fab9160e01b858401528460248401526044830190611faf565b03601f1981018652856113e4565b6114e8613c2b565b6114f061364f565b6001600160a01b03838116801592919087908415611696575b8415611628575b84156115c5575b5050821561153f575b5050611530576100188383614cf1565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561048c575f926115a8575b5050155f80611520565b6115be9250803d106106cb576106bc81836113e4565b5f8061159e565b855163054fd4d560e41b81529294508391839182905afa90811561048c57879160ff915f916115fb575b5016141591865f611517565b61161b9150843d8611611621575b61161381836113e4565b810190614cd8565b5f6115ef565b503d611609565b935050835163198ca60560e11b815282818981875afa90811561048c5788917f017d4155da73718dbec8960abca1d9f85d2dc8a31aa06e2d8e4410b4b093144a915f91611679575b50141593611510565b6116909150853d87116104855761047781836113e4565b5f611670565b5f805160206153108339815191525490945084906116c4906001600160a01b03165b6001600160a01b031690565b1493611509565b346102b8575f3660031901126102b8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036117225760206040515f805160206153108339815191528152f35b60405163703e46dd60e11b8152600490fd5b346102b8575f3660031901126102b857602060405160038152f35b346102b8575f3660031901126102b8575f80516020615310833981519152546040516001600160a01b039091168152602090f35b346102b8575f3660031901126102b85760206104af6126b1565b346102b85760203660031901126102b85760206104af6004356126da565b346102b8575f3660031901126102b857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561048c576020915f9161182b575b506040519015158152f35b6118429150823d84116106cb576106bc81836113e4565b5f611820565b346102b85760203660031901126102b857600435611865816106d2565b61186d61364f565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102b85760803660031901126102b8576104476118e76004356118d6816106d2565b6064359060443590602435906127ae565b604080519384526020840192909252908201529081906060820190565b346102b8575f3660031901126102b857602061ffff60655460a01c16604051908152f35b346102b8576003196040368201126102b85760049081356001600160401b038082116102b85760a08285019383360301126102b8576024359081116102b85761197490369085016110a6565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102b85760405163837d444160e01b8152905f9082908183816119c78c828f0161289c565b03925af1801561048c57611ae5575b506119df61342b565b6119e7612c4f565b9081163314159182611ab6575b50509050611aa5576044019160b0611a0c848461291a565b90500480158015611a8d575b611a7d57611a2d611a2761250d565b9161296f565b11611a6e575060b0611a3f838361291a565b9050145f14611a5b5761001891611a559161291a565b906144b7565b61001891611a689161291a565b90614287565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611a98848461291a565b905060b082021415611a18565b604051634ca8886760e01b81528390fd5b611ad99250611ad3611add94611acb88613f90565b923691611420565b9161406a565b1590565b805f806119f4565b80610e66611af29261137b565b5f6119d6565b346102b85760603660031901126102b857600435602435611b1d6044358284336127ae565b9192611b497f0000000000000000000000000000000000000000000000000000000000000000826126cd565b42108015611d4b575b8015611d43575b611d31577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611b9d86611b986108296099546001600160801b031690565b613c84565b15611c9f57611bd7611bbc611bb1866134b6565b60995460801c612419565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611c1b9190611c0a6080826113e4565b5190205f52609b60205260405f2090565b555f9360018311611c54575b50505050611c358233614616565b604080519485526020850191909152830152339180606081015b0390a2005b611c9592939450611c6590886126cd565b6040805133602082019081529181019390935260608301829052608095860183529094909190611c0a90826113e4565b555f808080611c27565b611ca761342b565b611ce3611cc7611cb6866134b6565b609e546001600160801b0316612419565b6001600160801b03166001600160801b0319609e541617609e55565b611d18611cfd611cf2856134b6565b609e5460801c612419565b6001600160801b03609e549181199060801b16911617609e55565b611d2c611d2784609f546126cd565b609f55565b611bd7565b604051630e3d8e8d60e11b8152600490fd5b508215611b59565b508115611b52565b346102b8576040806003193601126102b85760243590600435611d75836106d2565b611d7d61342b565b8015611f2b576001600160a01b038316908115611f1a57611d9d81612469565b908115611f0957611dad82614dae565b611db6836134b6565b60985460801c90611dc691612419565b611de5906001600160801b036098549181199060801b16911617609855565b611def8233614a00565b609e54958660801c8281609f5490611e06916126cd565b98611e10876134b6565b611e22916001600160801b03166124f2565b611e42906001600160801b03166001600160801b0319609e541617609e55565b611e4b916126cd565b611e54906134b6565b611e73906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611ea46080826113e4565b519020611eb9905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611f003361508a565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346102b857611c4f7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611f6e366110d3565b9290611f7861364f565b604051918291602083523395602084019161287c565b5f5b838110611f9f5750505f910152565b8181015183820152602001611f90565b90602091611fc881518092818552858086019101611f8e565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106120095750505050505090565b9091929394958480612027600193603f198682030187528a51611faf565b9801930193019194939290611ff9565b346102b85760203660031901126102b8576001600160401b036004358181116102b857366023820112156102b85780600401359182116102b8573660248360051b830101116102b8576104479160246120909201612ae2565b60405191829182611fd4565b9060206109e5928181520190611faf565b346102b8575f3660031901126102b8576104476040516120cc81611393565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611faf565b346102b8576040806003193601126102b857600435612110816106d2565b6024356001600160a01b03337f0000000000000000000000000000000000000000000000000000000000000000821614801590612210575b6121ff5761215461339f565b61215c61342b565b821615611f1a5780156121ee57917fd083678824038160bef3975359ab29f19c3f0e9bcf9d7ead540a492d4d678b63836121986104479561474c565b936121b3610d096121a8846134b6565b60985460801c6124f2565b6121bd8582614700565b83516001600160a01b03919091168152602081019190915260408101849052606090a1519081529081906020820190565b82516318374fd160e21b8152600490fd5b8351634ca8886760e01b8152600490fd5b508351638da5cb5b60e01b81526020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561048c575f91612261575b508116301415612148565b61227a915060203d60201161066b5761065b81836113e4565b5f612256565b346102b8575f3660031901126102b857612298613ab9565b6122a0612b8f565b60015f8051602061533083398151915255005b346102b8575f3660031901126102b8576020611034612c4f565b346102b85760203660031901126102b85760206104af60043561474c565b346102b8575f3660031901126102b85760206001600160801b0360995416604051908152f35b346102b85760203660031901126102b857610018600435612331816106d2565b61233961364f565b614819565b346102b8575f3660031901126102b85760206001600160801b03609e5416604051908152f35b346102b85760203660031901126102b857600435612381816106d2565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102b8575f3660031901126102b8575f546040516001600160a01b039091168152602090f35b908160209103126102b8575190565b6040513d5f823e3d90fd5b906040516123ed81611393565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161243257565b612405565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b038116908161248157505090565b916109e59260801c90612ead565b519081151582036102b857565b908160209103126102b8576109e59061248f565b908160209103126102b857516109e5816102dc565b81810392915f13801582851316918412161761243257565b908160209103126102b857516109e5816106d2565b9190916001600160801b038080941691160191821161243257565b61251561397b565b6099546001600160801b0361252b818316612469565b90609e5416019060801c01908181115f14612544570390565b50505f90565b61016a546001600160a01b031680156125605790565b507f000000000000000000000000000000000000000000000000000000000000000090565b906109e5949360809361ffff9260018060a01b0316845260208401521660408201528160608201520190611faf565b5f546001600160a01b03929083166126ac578101906040818303126102b8578035916125df836106d2565b60208201356001600160401b03928382116102b85701926060848303126102b8576040519261260d846113ae565b8435845260208501359461ffff861686036102b8576020850195865260408101359182116102b857019180601f840112156102b8577f6efc3c5ea2064c46840711aa5ff8d7f70826faa0cc04fcf0557a3863533aafad9561267a612698928560206126a797359101611420565b9260408601938452169361268e8186613b44565b51945161ffff1690565b90519060405194859485612585565b0390a1565b505050565b609d54806109e557505f1990565b9060b0820180921161243257565b9190820180921161243257565b6126ef816001600160801b0360995416613c84565b61271657612707609f54612701613cdf565b906126cd565b1115612711575f90565b5f1990565b609a90609a549182915f905b84821061273c575050508110156127365790565b505f1990565b909193808316906001818518811c8301809311612432575f8790527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be48301546001600160a01b0316841015612796575050935b9190612722565b90959101925061278f565b9190820391821161243257565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906127e28160808101610ee9565b5190205f52609b60205260405f205491821561284057829061280f836001600160801b0360995416613c84565b1561282e579161281e92613dcf565b90915b8281039081116124325792565b509061283991613d4f565b9091612821565b5050505f905f905f90565b9035601e19823603018112156102b85701602081359101916001600160401b0382116102b85781360383136102b857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a06109e5926020815282356020820152602083013560408201526128d86128c8604085018561284b565b84606085015260c084019161287c565b9061290b6129006128ec606087018761284b565b601f1985870381016080870152959161287c565b94608081019061284b565b9390928286030191015261287c565b903590601e19813603018212156102b857018035906001600160401b0382116102b8576020019181360383136102b857565b634e487b7160e01b5f52601260045260245ffd5b811561296a570490565b61294c565b90670de0b6b3a7640000918083029283040361243257565b90670de0b6b3a76400009182810292818404149015171561243257565b6001600160401b03811161138e5760051b60200190565b906129c5826129a4565b6129d260405191826113e4565b82815280926129e3601f19916129a4565b01905f5b8281106129f357505050565b8060606020809385010152016129e7565b634e487b7160e01b5f52603260045260245ffd5b90821015612a2f576110fd9160051b81019061291a565b612a04565b908092918237015f815290565b3d15612a6b573d90612a5282611405565b91612a6060405193846113e4565b82523d5f602084013e565b606090565b6020818303126102b8578051906001600160401b0382116102b8570181601f820112156102b8578051612aa281611405565b92612ab060405194856113e4565b818452602082840101116102b8576109e59160208085019101611f8e565b8051821015612a2f5760209160051b010190565b919091612aee836129bb565b925f5b818110612afd57505050565b5f80612b0a838587612a18565b60409391612b1c855180938193612a34565b0390305af490612b2a612a41565b9115612b51575090600191612b3f8288612ace565b52612b4a8187612ace565b5001612af1565b9060448151106102b857612b8b612b7660049283810151602480918301019101612a70565b925162461bcd60e51b8152928392830161209c565b0390fd5b47633b9aca008110612c4c57604051638119c06560e01b8152602081600481857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af191821561048c577f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db926040925f91612c2d575b50612c20612c1b8261318c565b6131c5565b82519182526020820152a1565b612c46915060203d6020116104855761047781836113e4565b5f612c0e565b50565b60d2546001600160a01b0316806109e557507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561048c575f91612d1b575b5060208201916001600160801b03918284511691828214612d145783612d07612d02612d0f958584865116612ead565b6134b6565b1690526134b6565b169052565b5050505050565b612d34915060203d6020116104855761047781836113e4565b5f612cd2565b90808202905f1981840990828083109203918083039214612daf57670de0b6b3a76400009082821115612d9d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a764000091500490565b90808202905f1981840990828083109203918083039214612e1d576127109082821115612d9d577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b505061271091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612ea05784831115612d9d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906109e59250612960565b9091828202915f1984820993838086109503948086039514612ea05784831115612d9d57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102b8578051916109e560406020840151930161248f565b81835290916001600160fb1b0383116102b85760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102b85760408301526040810135612f92816106d2565b6001600160a01b031660608381019190915281013536829003601e19018112156102b85701602081359101906001600160401b0381116102b8578060051b360382136102b85760a0836080806109e59601520191612f3f565b9190915f838201938412911290801582169115161761243257565b6040516325f56f1160e01b81526001600160a01b039291606090829081906130319060048301612f63565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561048c575f915f905f95613157575b508415613104578161307b61254a565b16917f00000000000000000000000000000000000000000000000000000000000000001682146130fd57509060205f92600460405180958193634641257d60e01b83525af190811561048c576130d8925f926130dc575b50612feb565b9190565b6130f691925060203d6020116104855761047781836113e4565b905f6130d2565b908161310a575b50509190565b803b156102b857604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561048c57613144575b80613104565b80610e666131519261137b565b5f61313e565b9194505061317d915060603d606011613185575b61317581836113e4565b810190612f20565b93905f61306b565b503d61316b565b6001600160ff1b03811161319d5790565b6024906040519063123baf0360e11b82526004820152fd5b600160ff1b8114612432575f0390565b8015612c4c576040516278744560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691906020908181600481875afa90811561048c575f91613382575b50604051631cd5ec3960e31b8152908282600481885afa91821561048c5761324c935f93613363575b50506127a1565b80156133585761326a8161326561082960985460801c90565b6126cd565b905f8312156132f45761328e9161328991613284856131b5565b612ead565b61318c565b613297816131b5565b92803b156102b85760405163304f0a6b60e21b815260048101949094525f908490602490829084905af191821561048c576132df936132da936132e15750612feb565b61487b565b565b80610e666132ee9261137b565b5f6130d2565b613302916132899184612ead565b823b156102b85760405163304f0a6b60e21b815260048101829052925f908490602490829084905af191821561048c576132df936132da93613345575b506124c5565b80610e666133529261137b565b5f61333f565b506132df915061487b565b61337a929350803d106104855761047781836113e4565b905f80613245565b6133999150823d84116104855761047781836113e4565b5f61321c565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561048c575f9161340c575b50156133fa57565b604051630a62fbdb60e11b8152600490fd5b613425915060203d6020116106cb576106bc81836113e4565b5f6133f2565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561048c575f91613497575b5061348557565b60405163e775715160e01b8152600490fd5b6134b0915060203d6020116106cb576106bc81836113e4565b5f61347e565b6001600160801b03908181116134ca571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b51906001600160401b03821682036102b857565b908160609103126102b85761353d6040805192613519846113ae565b8051613524816102dc565b8452613532602082016134e9565b6020850152016134e9565b604082015290565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561048c576135e0936001600160401b03610b7660406135bf946020975f91613630575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561048c575f91613617575090565b6109e5915060203d6020116104855761047781836113e4565b613649915060603d606011610e4257610e3381836113e4565b5f6135b0565b5f546001600160a01b0316330361129857565b92906001600160a01b039081811615610e725761367d61342b565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102b857604094855193631d8557d760e01b85526004945f81878183895af1801561048c57613968575b506001600160a01b0388165f908152610137602052604090206136f0906123e0565b906001600160801b0361370a83516001600160801b031690565b16156139585761371982612c85565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561048c57613939575b508651936303d1689d60e11b97888652602091828780613793888c83019190602083019252565b0381845afa96871561048c575f9761391a575b5086996137c661080a8d60018060a01b03165f52609c60205260405f2090565b8811801561390a575b6138fa57908361380c926137ea87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561048c575f859488946138519c6138dd575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561048c57610cb06138989461387b936103d3936132df9a6138bf575b50506134b6565b6001600160a01b0388165f90815261013760205260409020612437565b6138ba6138a48361474c565b80976138b5610d09610cf6876134b6565b614a00565b614616565b816138d592903d106104855761047781836113e4565b505f80613874565b6138f390873d89116104855761047781836113e4565b505f613826565b825163efda1a2760e01b81528990fd5b5061391361250d565b88116137cf565b613932919750833d85116104855761047781836113e4565b955f6137a6565b6139519060603d606011610e4257610e3381836113e4565b505f61376c565b875163673f032f60e11b81528690fd5b80610e666139759261137b565b5f6136ce565b613983614a4d565b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483018190526020939084846024817f000000000000000000000000000000000000000000000000000000000000000087165afa93841561048c57613a3c948693613a0e925f92613a9a575b506126cd565b60405163be7ab51b60e01b81526001600160a01b039092166004830152909390928491829081906024820190565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561048c576109e5935f93613a7b575b50506126cd565b613a92929350803d106104855761047781836113e4565b905f80613a74565b613ab2919250853d87116104855761047781836113e4565b905f613a08565b5f805160206153308339815191526002815414613ad65760029055565b604051633ee5aeb560e01b8152600490fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca00606480830191909152815260a08101916001600160401b0383118284101761138e576132df92604052614ae5565b90613b4d614b56565b6040810151613b5a614b56565b6001600160a01b0383168015610e72576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613bb333946020830190611faf565b0390a26020810151613bc3614b56565b61271061ffff821611613c1957613bdc613c0193614819565b6065805461ffff60a01b191660a09290921b61ffff60a01b1691909117905551614b97565b613c09614bc7565b613c11614b56565b6132df614bf2565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613c69575b505061172257565b5f805160206153108339815191525416141590505f80613c61565b90609a5480155f14613caa57505f5b6001600160a01b0316918201918210612432571090565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b0316613c93565b613ce761397b565b6099548060801c82039182116124325781613d0b6001600160801b03809316612469565b9081613d31575b50508115612544576109e591613d2c91609e541690614d9c565b614dae565b9192509081811115613d4757035b905f80613d12565b50505f613d3f565b613d57613cdf565b91609f549283018093116124325780831115613da157613d78920390614d9c565b90609e548060801c80155f14613d8e5750508190565b6001600160801b036109e5921684612ead565b5050505f905f90565b90604051613db781611393565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613f88575b613f7b5783613f45575f5b609a5f526001600160a01b0316613e277f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be48601613daa565b8051909790613e3e906001600160a01b03166116b8565b98613e63613e576020809b01516001600160601b031690565b6001600160601b031690565b948381108015613f3b575b613f295791600193979a95613e8d613e99939488035b838c0390614d9c565b80920198870391612ead565b01970193808611801590613f1f575b613f1457609a5f528290613edd7f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be48701613daa565b805190890151969992966001600160a01b039091169460019392613e999290916001600160601b0390911690613e8d908803613e84565b945050509250509190565b5081851015613ea8565b60405163e8722f8f60e01b8152600490fd5b50808b1115613e6e565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613def565b505093505050505f905f90565b508415613de4565b604290467f00000000000000000000000000000000000000000000000000000000000000000361403e5760d354905b613fd6613fcf604083018361291a565b3691611420565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152614021816113c9565b5190206040519161190160f01b8352600283015260228201522090565b614046614de5565b90613fbf565b6004111561405657565b634e487b7160e01b5f52602160045260245ffd5b6140748383614eb2565b506140818195929561404c565b15938461411d575b508315614097575b50505090565b5f9293509082916040516140cf81610ee96020820194630b135d3f60e11b998a87526024840152604060448401526064830190611faf565b51915afa906140dc612a41565b8261410f575b826140f2575b50505f8080614091565b614107919250602080825183010191016123c6565b145f806140e8565b9150602082511015916140e2565b6001600160a01b0383811691161493505f614089565b9061413d826129a4565b61414a60405191826113e4565b828152809261415b601f19916129a4565b0190602036910137565b906030116102b85790603090565b906090116102b85760300190606090565b9060b0116102b85760900190602090565b909392938483116102b85784116102b8578101920390565b602090836132df9395949560405196836141d08995518092888089019101611f8e565b84019185830137015f838201520380855201836113e4565b3590602081106141f6575090565b5f199060200360031b1b1690565b9160206109e593818152019161287c565b919261423f61422f61424d93608086526080860190611faf565b6020958582036020870152611faf565b908382036040850152611faf565b906060818303910152602080845192838152019301915f5b828110614273575050505090565b835185529381019392810192600101614265565b61428f614eec565b6060906060905f809460b08104926142a684614133565b965f905b8582106143c557506001600160a01b03947f000000000000000000000000000000000000000000000000000000000000000094506143219350602092506142f1915061296f565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561048c576143a6575b501661435e615061565b813b156102b8575f80946143886040519788968795869463c82655b760e01b865260048601614215565b03925af1801561048c576143995750565b80610e666132df9261137b565b6143be9060203d6020116106cb576106bc81836113e4565b505f614354565b61444a61441a6144256144076143fe7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c6126bf565b80998989614195565b92909a614414848d614165565b916141ad565b9a614414838c614173565b988b6144448661443e6144388686614184565b906141e8565b92612ace565b52614165565b9061445a60405192839283614204565b0390a1600101836142aa565b929461449f670de0b6b3a764000096614491608097946144ad969b9a9b60a0895260a089019161287c565b908682036020880152611faf565b91848303604086015261287c565b9460608201520152565b906144c0614eec565b6144ca8183614165565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af1801561048c576145f7575b50169061455c615061565b9161457561443861456d8489614173565b949098614184565b95813b156102b8575f80946145a2604051998a9687958694630cac9f3160e01b86528c8c60048801614466565b03925af192831561048c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936145e4575b506126a760405192839283614204565b80610e666145f19261137b565b5f6145d4565b61460f9060203d6020116106cb576106bc81836113e4565b505f614551565b9061461f613ab9565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561048c576146be946146b9925f916146e1575b5084116146d4575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836113e4565b614ae5565b6132df60015f8051602061533083398151915255565b6146dc614eec565b614684565b6146fa915060203d6020116104855761047781836113e4565b5f61467c565b614709826134b6565b609854906147216001600160801b03918284166124f2565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b609854906001600160801b0382168115801561477b575b1561476e5750905090565b6109e59260801c91612ead565b508015614763565b6098546001600160801b03811690816147a0575050633b9aca0090565b60801c6147ad8183612e28565b91811561296a57633b9aca00096147c15790565b60018101809111156109e557612405565b6098546001600160801b0381169082158015614811575b156147f357505090565b60801c90614802828285612ead565b92821561296a57096147c15790565b5081156147e9565b61482161342b565b6001600160a01b0316801561486957606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b8015612c4c5761489061082960985460801c90565b5f821261495d57816148a1916126cd565b906148ae610d09836134b6565b6148c36065549161ffff8360a01c1690612dc0565b80156126ac57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc35318686547936149016108296098546001600160801b031690565b806149475750506126a790925b6001600160a01b0316916149228484614700565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b6126a79261495792039084612ead565b9261490e565b90614967906131b5565b61497c610829609e546001600160801b031690565b8061499c575b508061498c575050565b612d02610d09916132df936127a1565b906149f77f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a916149e7611cc76149dc6149d588886126cd565b8785612ead565b8080940396036134b6565b6040519081529081906020820190565b0390a15f614982565b60018060a01b03165f52609c60205260405f2090815481810390811161243257614a2a92556134b6565b609854906001600160801b03908183160316906001600160801b03191617609855565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561048c575f91614ac8575b5060405163be7ab51b60e01b81523060048201529183908390818060248101613a3c565b614adf9150833d85116104855761047781836113e4565b5f614aa4565b5f80614b0d9260018060a01b03169360208151910182865af1614b06612a41565b90836152ac565b8051908115159182614b3b575b5050614b235750565b60249060405190635274afe760e01b82526004820152fd5b614b4e925060208091830101910161249c565b155f80614b1a565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614b8557565b604051631afcd79f60e31b8152600490fd5b614b9f614b56565b8015614bb55760018101614bb05750565b609d55565b6040516331278a8760e01b8152600490fd5b614bcf614b56565b670de0b6b3a7640000614be06126b1565b10614bb557614bed614de5565b60d355565b614bfa614b56565b614c02614b56565b614c0a614b56565b60015f8051602061533083398151915255614c2361342b565b3015610e7257633b9aca008060985460801c01614c3e6126b1565b8111614cc657614c58610d09614c52614783565b926134b6565b614c628130614700565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36132df30337f0000000000000000000000000000000000000000000000000000000000000000613ae8565b6040516304ffa0ff60e51b8152600490fd5b908160209103126102b8575160ff811681036102b85790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614d7b575b50614d4157604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f805160206153108339815191528403614d62576132df92935061510a565b604051632a87526960e21b815260048101859052602490fd5b614d9591955060203d6020116104855761047781836113e4565b935f614d1b565b9080821015614da9575090565b905090565b609e54908160801c81158015614ddd575b15614dca5750905090565b6001600160801b036109e5931691612ead565b508015614dbf565b6e5661756c7456616c696461746f727360881b6020604051614e0681611393565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b0382111761138e5760405251902090565b8151919060418303614ee257614edb9250602082015190606060408401519301515f1a906151ac565b9192909190565b50505f9160029190565b614ef461522e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116907f00000000000000000000000000000000000000000000000000000000000000008116803b156102b85760405163a3066aab60e01b81526001600160a01b0384166004820152905f908290602490829084905af1801561048c5761504e575b506040516370a0823160e01b81526001600160a01b03831660048201527f00000000000000000000000000000000000000000000000000000000000000009190911690602081602481855afa90811561048c575f9161502f575b5080614fe457505050565b823b156102b857604051632f1a9acf60e11b81526001600160a01b039290921660048301523060248301526044820152905f908290606490829084905af1801561048c576143995750565b615048915060203d6020116104855761047781836113e4565b5f614fd9565b80610e6661505b9261137b565b5f614f7f565b604051600160f81b60208201525f60218201523060601b602c820152602081526109e581611393565b60018060a01b0381165f5261013760205260405f2090604051916150ad83611393565b54906001600160801b03918281169081855260801c6020850152156126ac5761081061080a615100926150de61342b565b6150e786612c85565b6001600160a01b03165f908152609c6020526040902090565b915116116108ad57565b90813b1561518b575f8051602061531083398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561517057612c4c91615293565b50503461517957565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615223579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1561048c575f516001600160a01b0381161561521957905f905f90565b505f906001905f90565b5050505f9160039190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102b8575f809160246040518094819363a3066aab60e01b83523060048401525af1801561048c5761528a5750565b6132df9061137b565b5f806109e593602081519101845af46152aa612a41565b915b906152d357508051156152c157805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580615306575b6152e4575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156152dc56fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212202d53672be4072773fe6660fb7912327ba8f07de769ad300539ea0d8111dde69e64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoPrivErc20Vault.json b/test/shared/artifacts/GnoPrivErc20Vault.json deleted file mode 100644 index 5a8fe613..00000000 --- a/test/shared/artifacts/GnoPrivErc20Vault.json +++ /dev/null @@ -1,1943 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoPrivErc20Vault", - "sourceName": "contracts/vaults/gnosis/GnoPrivErc20Vault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "DeadlineExpired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidTokenMeta", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "PermitInvalidSigner", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x610220346200023a5762005fef38819003601f8101601f191683016001600160401b038111848210176200023e57839282916040528339610140928391810103126200023a57620000508162000252565b916200005f6020830162000252565b906200006e6040840162000252565b936200007d6060850162000252565b6200008b6080860162000252565b906200009a60a0870162000252565b92620000a960c0880162000252565b94620000b860e0890162000252565b9561010099620000ca8b8b0162000252565b98610120809b01519460805260a05260c0523060e052620000ea62000267565b468a52885246815261016091825260018060a01b038061018094168452806101a0951685526101c09586526101e0961686526102009687526200012c62000267565b60405197615ce8998a620003078b396080518a8181611b1e01528181611cf2015281816135a6015281816142de0152614cb2015260a0518a61185a015260c0518a8181613d4b0152818161467c015281816148980152615485015260e0518a81816119da0152613fbe01525189612abd015251886131d00152518761435401525186611e980152518581816104130152818161098201528181610ca701528181613207015281816139d90152614dc2015251848181610d660152818161156901528181613a980152614d46015251838181612a9801526135ee01525182818161118001528181613cfa015281816146e6015281816148e201528181614a2601526151fb015251816130f10152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200023a57565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620002f4576001600160401b036002600160401b031982821601620002b557505050565b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d1141461037f578063066055e01461037a57806306fdde031461037557806307a2d13a14610370578063095ea7b31461036b5780630d392cd91461036657806318160ddd1461032a5780631a7ff55314610361578063201b9eb51461035c57806322758a4a1461035757806323b872dd146103525780632999ad3f1461034d5780632cdf7401146103485780632e2d298414610343578063313ce5671461033e5780633229fa951461033957806333194c0a146103345780633644e5151461032f5780633a98ef391461032a578063439fab911461032557806343e82a7914610320578063469048401461031b5780634ec96b22146103165780634f1ef2861461031157806352d1902d1461030c57806354fd4d50146103075780635c60da1b146103025780635cfc1a51146102fd57806360d60e6e146102f857806370a082311461028a57806372b410a8146102f3578063754c3888146102ee57806376b58b90146102e95780637ecebe00146102e45780637fd6f15c146102df57806383d430d5146102da5780638697d2c2146102d55780638ceab9aa146102d057806395d89b41146102cb578063a49a1e7d146102c6578063a9059cbb146102c1578063ac9650d8146102bc578063ad3cb1cc146102b7578063b0d11302146102b2578063b1f0e7c7146102ad578063c6e6f592146102a8578063d505accf146102a3578063d83ad00c1461029e578063dd62ed3e14610299578063e74b981b14610294578063ee3bd5df1461028f578063f04da65b1461028a578063f6a6830f14610285578063f851a440146102805763f98f5b920361000e576128c2565b61289a565b612859565b611ab8565b612833565b612806565b6127a7565b612781565b61256c565b612543565b612529565b6124f6565b6124b1565b61244c565b6123ab565b612359565b6122b5565b6120cc565b611e6c565b611c9c565b611c78565b611c3d565b611bec565b611b80565b611af3565b611a9a565b611a80565b611a4c565b611a31565b6119c8565b611742565b61165f565b611637565b61153a565b611397565b610872565b611322565b6112e8565b6112bc565b6112a1565b611121565b611107565b610c7d565b610ba1565b610b78565b610910565b610898565b610840565b610794565b61075d565b610697565b6103c3565b610392565b5f91031261038e57565b5f80fd5b3461038e575f36600319011261038e57602060cf5460801c604051908152f35b6001600160801b0381160361038e57565b3461038e57602036600319011261038e576004356103e0816103b2565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610562575f91610533575b50335f90815261016e6020526040902061045c90612909565b916001600160801b0361047684516001600160801b031690565b1615610521576104ca8361048c61051d956131f2565b6104b66104a9846104a484516001600160801b031690565b612942565b6001600160801b03168252565b335f90815261016e6020526040902061295b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610555915060203d60201161055b575b61054d818361061c565b8101906128ef565b5f610443565b503d610543565b6128fe565b90600182811c92168015610595575b602083101461058157565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610576565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176105ce57604052565b61059f565b6001600160401b0381116105ce57604052565b60a081019081106001600160401b038211176105ce57604052565b608081019081106001600160401b038211176105ce57604052565b90601f801991011681019081106001600160401b038211176105ce57604052565b5f5b83811061064e5750505f910152565b818101518382015260200161063f565b906020916106778151809281855285808601910161063d565b601f01601f1916010190565b90602061069492818152019061065e565b90565b3461038e575f36600319011261038e576040515f80546106b681610567565b8084529060209060019081811690811561073357506001146106ef575b61051d856106e38187038261061c565b60405191829182610683565b5f80805293505f80516020615c138339815191525b838510610720575050505081016020016106e38261051d6106d3565b8054868601840152938201938101610704565b86955061051d969350602092506106e394915060ff191682840152151560051b82010192936106d3565b3461038e57602036600319011261038e57602061077b600435612984565b604051908152f35b6001600160a01b0381160361038e57565b3461038e57604036600319011261038e576004356107b181610783565b6001600160a01b03811690602435908215610824576107ec8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b8015150361038e57565b3461038e57604036600319011261038e5761001860043561086081610783565b6024359061086d82610836565b6129aa565b3461038e575f36600319011261038e5760206001600160801b0360cf5416604051908152f35b3461038e5760031960203682011261038e57600435906001600160401b03821161038e57608090823603011261038e576108d76108de91600401613575565b919061370b565b6108e457005b6108ec615579565b806108f357005b5f906040519081525f80516020615c5383398151915260203092a3005b3461038e57606036600319011261038e5760043561092d81610783565b602435906044359061093e82610783565b61094733613890565b61094f614c97565b6109576142c3565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af1948515610562575f95610b59575b50335f90815261016e602052604090206109d290612909565b926001600160801b036109ec85516001600160801b031690565b1615610af55750506109fd826131f2565b610a29610a1c610a0c876149d5565b84516001600160801b03166138b2565b6001600160801b03168352565b335f90815260d360205260409020610a4b90610a46905b54612984565b614d23565b610a6b610a5f84516001600160801b031690565b6001600160801b031690565b11610ae357335f90815261016e6020526040902061051d957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610ab1919061295b565b604080516001600160a01b0395861681526020810187905290810191909152921660608301523391806080810161050a565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561056257610b3792610b28915f91610b3c575b506149d5565b6001600160801b031690840152565b6109fd565b610b539150833d851161055b5761054d818361061c565b5f610b22565b610b71919550833d851161055b5761054d818361061c565b935f6109b9565b3461038e575f36600319011261038e5761026a546040516001600160a01b039091168152602090f35b3461038e57606036600319011261038e57600435610bbe81610783565b60243590610bcb82610783565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610c1b575b610c0f84610c0a858883614e2d565b6138cd565b60405160018152602090f35b919093818503948511610c4f575f928352600260209081526040808520338652909152909220939093559180610c0f610bfb565b61292e565b606090600319011261038e5760043590602435610c7081610783565b9060443561069481610783565b3461038e57610c8b36610c54565b906001600160a01b038083161561082457610ca46142c3565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561038e5760408051631d8557d760e01b815260049491905f81878183875af18015610562576110ee575b506001600160a01b0383165f90815261016e60205260409020610d1790612909565b6001600160801b039283610d3283516001600160801b031690565b16156110de57610d41826131f2565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610562575f986110ad575b50602097888101956001600160401b03918280610dba8a516001600160401b031690565b161461109d57908c92918751918c8380610de66303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561056257610e12938e5f94611078575b5050516001600160801b03165b1690613321565b96610e30610a408a60018060a01b03165f5260d360205260405f2090565b928389118015611068575b61105857908b610e799392610e5789516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561056257670de0b6b3a764000094610ec8948e5f9561102b575b5050610eba610eac610ec092612ec6565b93516001600160401b031690565b93612ec6565b92169061341a565b101561101d578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610562577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610ffa95610f7293610fff575b5050610f556104a9610f458c6149d5565b83516001600160801b0316612942565b6001600160a01b0386165f90815261016e6020526040902061295b565b610f7b82614b21565b90610fb9610f9e610f8b856149d5565b60cf5460801c036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610fc382866156a9565b610fcd8389614a08565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b8161101592903d1061055b5761054d818361061c565b505f80610f34565b835163185cfc6d60e11b8152fd5b610ec092955061104e610eba9282610eac93903d1061055b5761054d818361061c565b959250508e610e9b565b875163efda1a2760e01b81528590fd5b50611071612a42565b8911610e3b565b610e0b929450908161109592903d1061055b5761054d818361061c565b92908e610dfe565b8651630709133160e01b81528490fd5b6110d091985060603d6060116110d7575b6110c8818361061c565b810190613961565b965f610d96565b503d6110be565b825163673f032f60e11b81528790fd5b806110fb611101926105d3565b80610384565b5f610cf5565b3461038e575f36600319011261038e57602061077b612a42565b3461038e5761112f36610c54565b9161113933613890565b61114282613890565b61114a614af2565b6040926111a484516323b872dd60e01b60208201523360248201523060448201528360648201526064815261117e816105e6565b7f0000000000000000000000000000000000000000000000000000000000000000615714565b6111ac6142c3565b6001600160a01b03831692831561129057821561127f57826111d3610a5f60cf5460801c90565b01906111dd612bcd565b821161126e57611254610f9e959361122e86947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461122961122160209c9a614ba7565b9a8b936149d5565b615511565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020615c938339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b3461038e575f36600319011261038e57602060405160128152f35b3461038e575f36600319011261038e5760206112d6612a7f565b6040516001600160a01b039091168152f35b3461038e575f36600319011261038e5760206040517f81812efbf43b69af38830f31dcb806af2764ff4398ba7ce084500c10160479b18152f35b3461038e575f36600319011261038e57602061077b612aba565b9181601f8401121561038e578235916001600160401b03831161038e576020838186019501011161038e57565b602060031982011261038e57600435906001600160401b03821161038e576113939160040161133c565b9091565b3461038e576113a536611369565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c168015611526575b6115145768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa928315610562575f936114f5575b50604051636f4fa30f60e01b8152938285600481335afa908115610562576114629561145d945f936114c2575b50506114569192810190612b2e565b9083613ee8565b613fa8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b611456935090816114e792903d106114ee575b6114df818361061c565b810190612aef565b915f611447565b503d6114d5565b61150d919350823d84116114ee576114df818361061c565b915f61141a565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b03821610156113d6565b3461038e5761154836610c54565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105625782915f91611618575b501633036116065781610ffa6115d386867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966139bb565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611631915060203d6020116114ee576114df818361061c565b5f61159b565b3461038e575f36600319011261038e57609c546040516001600160a01b039091168152602090f35b3461038e57602036600319011261038e5760043561167c81610783565b60018060a01b03165f5261016e602052602060405f206040519061169f826105b3565b54906001600160801b03918281169081835260801c848301526116c7575b5116604051908152f35b6116d0816131f2565b6116bd565b604051906116e2826105e6565b565b604051906116e2826105b3565b6001600160401b0381116105ce57601f01601f191660200190565b929192611718826116f1565b91611726604051938461061c565b82948184528183011161038e578281602093845f960137010152565b60408060031936011261038e57600490813561175d81610783565b6024356001600160401b03811161038e573660238201121561038e5761178c903690602481870135910161170c565b91611795613fb4565b8051926117cc846117be60209363439fab9160e01b85840152846024840152604483019061065e565b03601f19810186528561061c565b6117d4613fb4565b6117dc614094565b6001600160a01b03838116801592919087908415611993575b8415611925575b84156118c1575b5050821561182b575b505061181c576100188383615246565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610562575f92611894575b5050155f8061180c565b6118b39250803d106118ba575b6118ab818361061c565b810190612cb5565b5f8061188a565b503d6118a1565b855163054fd4d560e41b81529294508391839182905afa9081156105625760039160ff915f916118f8575b5016141591865f611803565b6119189150843d861161191e575b611910818361061c565b810190615231565b5f6118ec565b503d611906565b935050835163198ca60560e11b815282818981875afa9081156105625788917f81812efbf43b69af38830f31dcb806af2764ff4398ba7ce084500c10160479b1915f91611976575b501415936117fc565b61198d9150853d871161055b5761054d818361061c565b5f61196d565b5f80516020615c338339815191525490945084906119c1906001600160a01b03165b6001600160a01b031690565b14936117f5565b3461038e575f36600319011261038e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003611a1f5760206040515f80516020615c338339815191528152f35b60405163703e46dd60e11b8152600490fd5b3461038e575f36600319011261038e57602060405160028152f35b3461038e575f36600319011261038e575f80516020615c33833981519152546040516001600160a01b039091168152602090f35b3461038e575f36600319011261038e57602061077b612bcd565b3461038e57602036600319011261038e57602061077b600435612bf6565b3461038e57602036600319011261038e57600435611ad581610783565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461038e575f36600319011261038e57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610562576020915f91611b63575b506040519015158152f35b611b7a9150823d84116118ba576118ab818361061c565b5f611b58565b3461038e57602036600319011261038e57600435611b9d81610783565b611ba5614094565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461038e57608036600319011261038e5761051d611c20600435611c0f81610783565b606435906044359060243590612cd7565b604080519384526020840192909252908201529081906060820190565b3461038e57602036600319011261038e57600435611c5a81610783565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461038e575f36600319011261038e57602061ffff609c5460a01c16604051908152f35b3461038e5760031960403682011261038e5760049081356001600160401b0380821161038e5760a082850193833603011261038e5760243590811161038e57611ce8903690850161133c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561038e5760405163837d444160e01b8152905f908290818381611d3b8c828f01612ddb565b03925af1801561056257611e59575b50611d536142c3565b611d5b6131bb565b9081163314159182611e2a575b50509050611e19576044019160b0611d808484612e59565b90500480158015611e01575b611df157611da1611d9b612a42565b91612eae565b11611de2575060b0611db38383612e59565b9050145f14611dcf5761001891611dc991612e59565b90614876565b61001891611ddc91612e59565b90614646565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611e0c8484612e59565b905060b082021415611d8c565b604051634ca8886760e01b81528390fd5b611e4d9250611e47611e5194611e3f8861434e565b92369161170c565b91614429565b1590565b805f80611d68565b806110fb611e66926105d3565b5f611d4a565b3461038e57606036600319011261038e57600435602435611e91604435828433612cd7565b9192611ebd7f000000000000000000000000000000000000000000000000000000000000000082612be9565b421080156120c4575b80156120bc575b6120aa577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611f1186611f0c610a5f60d0546001600160801b031690565b61400d565b1561201857611f4b611f30611f25866149d5565b60d05460801c612942565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611f8f9190611f7e60808261061c565b5190205f5260d260205260405f2090565b555f9360018311611fc8575b50505050611fa98233614a08565b604080519485526020850191909152830152339180606081015b0390a2005b61200e92939450611fd99088612be9565b60408051336020820190815291810193909352606083018290529094909190611f7e9082608081015b0390810183528261061c565b555f808080611f9b565b6120206142c3565b61205c61204061202f866149d5565b60d5546001600160801b0316612942565b6001600160801b03166001600160801b031960d554161760d555565b61209161207661206b856149d5565b60d55460801c612942565b6001600160801b0360d5549181199060801b1691161760d555565b6120a56120a08460d654612be9565b60d655565b611f4b565b604051630e3d8e8d60e11b8152600490fd5b508215611ecd565b508115611ec6565b3461038e5760408060031936011261038e57602435906004356120ee83610783565b6120f66142c3565b80156122a4576001600160a01b0383169081156122935761211681612984565b9081156122825761212682615345565b61212f836149d5565b60cf5460801c9061213f91612942565b61215e906001600160801b0360cf549181199060801b1691161760cf55565b61216882336156a9565b60d554958660801c828160d6549061217f91612be9565b98612189876149d5565b61219b916001600160801b03166138b2565b6121bb906001600160801b03166001600160801b031960d554161760d555565b6121c491612be9565b6121cd906149d5565b6121ec906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529061221d60808261061c565b519020612232905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3612279336138cd565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461038e575f36600319011261038e576040515f600180546122d681610567565b808552916020916001811690811561073357506001146123005761051d856106e38187038261061c565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510612346575050505081016020016106e38261051d6106d3565b805486860184015293820193810161232a565b3461038e57611fc37f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61238b36611369565b9290612395614094565b6040519182916020835233956020840191612dbb565b3461038e57604036600319011261038e576123d56004356123cb81610783565b6024359033614e2d565b6123de336138cd565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831061241e5750505050505090565b909192939495848061243c600193603f198682030187528a5161065e565b980193019301919493929061240e565b3461038e57602036600319011261038e576001600160401b0360043581811161038e573660238201121561038e57806004013591821161038e573660248360051b8301011161038e5761051d9160246124a59201613021565b604051918291826123e9565b3461038e575f36600319011261038e5761051d6040516124d0816105b3565b60058152640352e302e360dc1b602082015260405191829160208352602083019061065e565b3461038e575f36600319011261038e5761250e614af2565b6125166130ce565b60015f80516020615c9383398151915255005b3461038e575f36600319011261038e5760206112d66131bb565b3461038e57602036600319011261038e57602061077b600435614b21565b60ff81160361038e57565b3461038e5760e036600319011261038e5760043561258981610783565b60243561259581610783565b6044359060643592608435906125aa82612561565b6001600160a01b038381169590929086156108245742811061276f576020915f9161200261269d89878a6126606125df612aba565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b0391612674601f199384810183528261061c565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610562575f51928284168015908115612762575b506127505761273d85916127287f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610ffa565b6040516323389ba560e21b8152600490fd5b905083831614155f6126e3565b604051631ab7da6b60e01b8152600490fd5b3461038e575f36600319011261038e5760206001600160801b0360d05416604051908152f35b3461038e57604036600319011261038e5760206127fd6004356127c981610783565b602435906127d682610783565b60018060a01b03165f526002835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461038e57602036600319011261038e5761001860043561282681610783565b61282e614094565b614bee565b3461038e575f36600319011261038e5760206001600160801b0360d55416604051908152f35b3461038e57602036600319011261038e5760043561287681610783565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b3461038e575f36600319011261038e576037546040516001600160a01b039091168152602090f35b3461038e57602036600319011261038e576100186004356128e281610783565b6128ea614094565b614c50565b9081602091031261038e575190565b6040513d5f823e3d90fd5b90604051612916816105b3565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039182169082160391908211610c4f57565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161299c57505090565b916106949260801c9061341a565b61026a546001600160a01b03919082163303611606576001600160a01b0381165f90815261026b60205260409020549215159260ff1615158314612a3d576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b612a4a613cd4565b60d0546001600160801b03612a60818316612984565b9060d55416019060801c01908181115f14612a79570390565b50505f90565b6101a1546001600160a01b03168015612a955790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003612ae75760045490565b610694613dc2565b9081602091031261038e575161069481610783565b359061ffff8216820361038e57565b9080601f8301121561038e578160206106949335910161170c565b9060208282031261038e5781356001600160401b039283821161038e57019060a08282031261038e57612b5f6116d5565b9282358452612b7060208401612b04565b6020850152604083013581811161038e5782612b8d918501612b13565b6040850152606083013581811161038e5782612baa918501612b13565b6060850152608083013590811161038e57612bc59201612b13565b608082015290565b60d4548061069457505f1990565b9060b08201809211610c4f57565b91908201809211610c4f57565b6001600160801b0360d05416612c0a6152f1565b908101809111610c4f578110612c3d57612c2e60d654612c28614024565b90612be9565b1115612c38575f90565b5f1990565b60d19060d1549182915f905b848210612c6357505050811015612c5d5790565b505f1990565b909193808316906001818518811c8301809311610c4f575f8790525f80516020615c738339815191528301546001600160a01b0316841015612caa575050935b9190612c49565b909591019250612ca3565b9081602091031261038e575161069481610836565b91908203918211610c4f57565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612d1581608081015b03601f19810183528261061c565b5190205f5260d260205260405f2054918215612d7f576001600160801b0360d0541690612d406152f1565b918201809211610c4f578391831015612d6d5791612d5d92614128565b90915b828103908111610c4f5792565b5090612d78916140a8565b9091612d60565b5050505f905f905f90565b9035601e198236030181121561038e5701602081359101916001600160401b03821161038e57813603831361038e57565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061069492602081528235602082015260208301356040820152612e17612e076040850185612d8a565b84606085015260c0840191612dbb565b90612e4a612e3f612e2b6060870187612d8a565b601f19858703810160808701529591612dbb565b946080810190612d8a565b93909282860301910152612dbb565b903590601e198136030182121561038e57018035906001600160401b03821161038e5760200191813603831361038e57565b634e487b7160e01b5f52601260045260245ffd5b8115612ea9570490565b612e8b565b90670de0b6b3a76400009180830292830403610c4f57565b90670de0b6b3a764000091828102928184041490151715610c4f57565b6001600160401b0381116105ce5760051b60200190565b90612f0482612ee3565b612f11604051918261061c565b8281528092612f22601f1991612ee3565b01905f5b828110612f3257505050565b806060602080938501015201612f26565b634e487b7160e01b5f52603260045260245ffd5b90821015612f6e576113939160051b810190612e59565b612f43565b908092918237015f815290565b3d15612faa573d90612f91826116f1565b91612f9f604051938461061c565b82523d5f602084013e565b606090565b60208183031261038e578051906001600160401b03821161038e570181601f8201121561038e578051612fe1816116f1565b92612fef604051948561061c565b8184526020828401011161038e57610694916020808501910161063d565b8051821015612f6e5760209160051b010190565b91909161302d83612efa565b925f5b81811061303c57505050565b5f80613049838587612f57565b6040939161305b855180938193612f73565b0390305af490613069612f80565b911561309057509060019161307e828861300d565b52613089818761300d565b5001613030565b90604481511061038e576130ca6130b560049283810151602480918301019101612faf565b925162461bcd60e51b81529283928301610683565b0390fd5b47633b9aca0081106131b857604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610562575f92613197575b506001600160ff1b03821161317e57907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db916131648261370b565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b6131b191925060203d60201161055b5761054d818361061c565b905f613129565b50565b610109546001600160a01b03168061069457507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91613288575b5060208201916001600160801b03918284511691828214613281578361327461326f61327c95858486511661341a565b6149d5565b1690526149d5565b169052565b5050505050565b6132a1915060203d60201161055b5761054d818361061c565b5f61323f565b90808202905f1981840990828083109203918083039214613316576127109082821115613304577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461338457670de0b6b3a76400009082821115613304577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106949250612e9f565b9091828202915f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b9081606091031261038e578051916040602083015192015161069481610836565b81835290916001600160fb1b03831161038e5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361038e576040830152604081013561350181610783565b6001600160a01b031660608381019190915281013536829003601e190181121561038e5701602081359101906001600160401b03811161038e578060051b3603821361038e5760a08360808061069496015201916134ae565b9190915f8382019384129112908015821691151617610c4f57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906135a090600483016134d2565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610562575f915f905f956136c6575b50841561367357816135ea612a7f565b16917f000000000000000000000000000000000000000000000000000000000000000016821461366c57509060205f92600460405180958193634641257d60e01b83525af190811561056257613647925f9261364b575b5061355a565b9190565b61366591925060203d60201161055b5761054d818361061c565b905f613641565b9081613679575b50509190565b803b1561038e57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015610562576136b3575b80613673565b806110fb6136c0926105d3565b5f6136ad565b919450506136ec915060603d6060116136f4575b6136e4818361061c565b81019061348d565b93905f6135da565b503d6136da565b600160ff1b8114610c4f575f0390565b80156131b857613720610a5f60cf5460801c90565b5f82126137ed578161373191612be9565b9061373e610f9e836149d5565b613753609c549161ffff8360a01c16906132a7565b8015612a3d57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613791610a5f60cf546001600160801b031690565b806137d757505061317990925b6001600160a01b0316916137b28484615511565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b613179926137e79203908461341a565b9261379e565b906137f7906136fb565b61380c610a5f60d5546001600160801b031690565b8061382c575b508061381c575050565b61326f610f9e916116e293612cca565b906138877f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161387761204061386c6138658888612be9565b878561341a565b8080940396036149d5565b6040519081529081906020820190565b0390a15f613812565b6001600160a01b03165f90815261026b602052604090205460ff161561160657565b9190916001600160801b0380809416911601918211610c4f57565b60018060a01b0381165f5261016e60205260405f2090604051916138f0836105b3565b54906001600160801b03918281169081855260801c602085015215612a3d57610a46610a40613943926139216142c3565b61392a866131f2565b6001600160a01b03165f90815260d36020526040902090565b91511611610ae357565b51906001600160401b038216820361038e57565b9081606091031261038e5760405190606082018281106001600160401b038211176105ce576139b3916040918252805161399a816103b2565b84526139a86020820161394d565b60208501520161394d565b604082015290565b92906001600160a01b039081811615610824576139d66142c3565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561038e57604094855193631d8557d760e01b85526004945f81878183895af1801561056257613cc1575b506001600160a01b0388165f90815261016e60205260409020613a4990612909565b906001600160801b03613a6383516001600160801b031690565b1615613cb157613a72826131f2565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561056257613c92575b508651936303d1689d60e11b97888652602091828780613aec888c83019190602083019252565b0381845afa968715610562575f97613c73575b508699613b1f610a408d60018060a01b03165f5260d360205260405f2090565b88118015613c63575b613c53579083613b6592613b4387516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610562575f85948894613baa9c613c36575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561056257610f45613bf194613bd4936104a9936116e29a613c18575b50506149d5565b6001600160a01b0388165f90815261016e6020526040902061295b565b613c13613bfd83614b21565b8097613c0e610f9e610f8b876149d5565b6156a9565b614a08565b81613c2e92903d1061055b5761054d818361061c565b505f80613bcd565b613c4c90873d891161055b5761054d818361061c565b505f613b7f565b825163efda1a2760e01b81528990fd5b50613c6c612a42565b8811613b28565b613c8b919750833d851161055b5761054d818361061c565b955f613aff565b613caa9060603d6060116110d7576110c8818361061c565b505f613ac5565b875163673f032f60e11b81528690fd5b806110fb613cce926105d3565b5f613a27565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610562575f91613da5575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561056257610694935f93613d86575b5050612be9565b613d9d929350803d1061055b5761054d818361061c565b905f80613d7f565b613dbc9150833d851161055b5761054d818361061c565b5f613d2b565b6040515f905f5490613dd382610567565b9283825260209384830193600190866001821691825f14613ec8575050600114613e85575b50509181613e0e613e7f93612d0795038261061c565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020615c138339815191525b828410613eb35750505082010181613e0e613df8565b80548685018601528794909301928101613e9d565b60ff1916875292151560051b85019092019250839150613e0e9050613df8565b9190613ef2614f01565b608082015190613f00614f01565b6001600160a01b038416801561082457613fa094613f9093613f79926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613f673394602083019061065e565b0390a2602085015161ffff1690614f42565b613f838351614f93565b613f8b614fc3565b614fef565b606060408201519101519061501e565b6116e261514b565b6116e2906128ea614f01565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613ff2575b5050611a1f57565b5f80516020615c338339815191525416141590505f80613fea565b906140166152f1565b918201809211610c4f571090565b61402c613cd4565b60d0548060801c8203918211610c4f57816140506001600160801b03809316612984565b9081614076575b50508115612a7957610694916140719160d5541690615333565b615345565b919250908181111561408c57035b905f80614057565b50505f614084565b6037546001600160a01b0316330361160657565b6140b0614024565b9160d654928301809311610c4f57808311156140fa576140d1920390615333565b9060d5548060801c80155f146140e75750508190565b6001600160801b0361069492168461341a565b5050505f905f90565b90604051614110816105b3565b91546001600160a01b038116835260a01c6020830152565b60d1545f9485949390918084108015906142bb575b6142ae5783614278575f5b60d15f526001600160a01b031661416d5f80516020615c738339815191528601614103565b8051909790614184906001600160a01b03166119b5565b986141a961419d6020809b01516001600160601b031690565b6001600160601b031690565b94838110801561426e575b61425c5791600193979a956141d36141df939488035b838c0390615333565b8092019887039161341a565b01970193808611801590614252575b6142475760d15f5282906142105f80516020615c738339815191528701614103565b805190890151969992966001600160a01b0390911694600193926141df9290916001600160601b03909116906141d39088036141ca565b945050509250509190565b50818510156141ee565b60405163e8722f8f60e01b8152600490fd5b50808b11156141b4565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316614148565b505093505050505f905f90565b50841561413d565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f9161432f575b5061431d57565b60405163e775715160e01b8152600490fd5b614348915060203d6020116118ba576118ab818361061c565b5f614316565b604290467f0000000000000000000000000000000000000000000000000000000000000000036143fd5761010a54905b61439561438e6040830183612e59565b369161170c565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526143e081610601565b5190206040519161190160f01b8352600283015260228201522090565b61440561537c565b9061437e565b6004111561441557565b634e487b7160e01b5f52602160045260245ffd5b6144338383615449565b506144408195929561440b565b1593846144dc575b508315614456575b50505090565b5f92935090829160405161448e81612d076020820194630b135d3f60e11b998a8752602484015260406044840152606483019061065e565b51915afa9061449b612f80565b826144ce575b826144b1575b50505f8080614450565b6144c6919250602080825183010191016128ef565b145f806144a7565b9150602082511015916144a1565b6001600160a01b0383811691161493505f614448565b906144fc82612ee3565b614509604051918261061c565b828152809261451a601f1991612ee3565b0190602036910137565b9060301161038e5790603090565b9060901161038e5760300190606090565b9060b01161038e5760900190602090565b9093929384831161038e57841161038e578101920390565b602090836116e293959495604051968361458f899551809288808901910161063d565b84019185830137015f8382015203808552018361061c565b3590602081106145b5575090565b5f199060200360031b1b1690565b916020610694938181520191612dbb565b91926145fe6145ee61460c9360808652608086019061065e565b602095858203602087015261065e565b90838203604085015261065e565b906060818303910152602080845192838152019301915f5b828110614632575050505090565b835185529381019392810192600101614624565b61464e615483565b6060906060905f809460b0810492614665846144f2565b965f905b85821061478457506001600160a01b03947f000000000000000000000000000000000000000000000000000000000000000094506146e09350602092506146b09150612eae565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561056257614765575b501661471d6154e8565b813b1561038e575f80946147476040519788968795869463c82655b760e01b8652600486016145d4565b03925af18015610562576147585750565b806110fb6116e2926105d3565b61477d9060203d6020116118ba576118ab818361061c565b505f614713565b6148096147d96147e46147c66147bd7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612bdb565b80998989614554565b92909a6147d3848d614524565b9161456c565b9a6147d3838c614532565b988b614803866147fd6147f78686614543565b906145a7565b9261300d565b52614524565b90614819604051928392836145c3565b0390a160010183614669565b929461485e670de0b6b3a7640000966148506080979461486c969b9a9b60a0895260a0890191612dbb565b90868203602088015261065e565b918483036040860152612dbb565b9460608201520152565b9061487f615483565b6148898183614524565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af18015610562576149b6575b50169061491b6154e8565b916149346147f761492c8489614532565b949098614543565b95813b1561038e575f8094614961604051998a9687958694630cac9f3160e01b86528c8c60048801614825565b03925af1928315610562577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936149a3575b50613179604051928392836145c3565b806110fb6149b0926105d3565b5f614993565b6149ce9060203d6020116118ba576118ab818361061c565b505f614910565b6001600160801b03908181116149e9571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b90614a11614af2565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561056257614ab094614aab925f91614ad3575b508411614ac6575b60405163a9059cbb60e01b60208201526001600160a01b0391909116602482015260448082019490945292835260648361061c565b615714565b6116e260015f80516020615c9383398151915255565b614ace615483565b614a76565b614aec915060203d60201161055b5761054d818361061c565b5f614a6e565b5f80516020615c938339815191526002815414614b0f5760029055565b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614b50575b15614b435750905090565b6106949260801c9161341a565b508015614b38565b60cf546001600160801b0381169081614b75575050633b9aca0090565b60801c614b828183613395565b918115612ea957633b9aca0009614b965790565b60018101809111156106945761292e565b60cf546001600160801b0381169082158015614be6575b15614bc857505090565b60801c90614bd782828561341a565b928215612ea95709614b965790565b508115614bbe565b614bf66142c3565b6001600160a01b03168015614c3e57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91614d04575b5015614cf257565b604051630a62fbdb60e11b8152600490fd5b614d1d915060203d6020116118ba576118ab818361061c565b5f614cea565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561056257614dbe936001600160401b03610e0b6040614d9d946020975f91614e0e575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610562575f91614df5575090565b610694915060203d60201161055b5761054d818361061c565b614e27915060603d6060116110d7576110c8818361061c565b5f614d8e565b90614e3782613890565b614e4081613890565b6001600160a01b039182169182158015614eb1575b61082457825f5260d360205260405f2090815492858403938411610c4f575f80516020615c538339815191529360209355614ea08160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614e55565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca0060648083019190915281526116e291614aab826105e6565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614f3057565b604051631afcd79f60e31b8152600490fd5b614f4a614f01565b61271061ffff831611614f8157614f6090614bee565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614f9b614f01565b8015614fb15760018101614fac5750565b60d455565b6040516331278a8760e01b8152600490fd5b614fcb614f01565b670de0b6b3a7640000614fdc612bcd565b10614fb157614fe961537c565b61010a55565b614ff7614f01565b6001600160a01b0316806150085750565b6101a180546001600160a01b0319169091179055565b615026614f01565b601e8151118015615140575b61512e5761503e614f01565b8051906001600160401b0382116105ce576150628261505d5f54610567565b615785565b602090816001601f8511146150ba575091806150989261509f95945f926150af575b50508160011b915f199060031b1c19161790565b5f5561584f565b6116e26150aa613dc2565b600455565b015190505f80615084565b5f80529190601f1984165f80516020615c13833981519152935f905b82821061511657505091600193918561509f979694106150fe575b505050811b015f5561584f565b01515f1960f88460031b161c191690555f80806150f1565b806001869782949787015181550196019401906150d6565b604051632d3f993760e21b8152600490fd5b50600a825111615032565b615153614f01565b61515b614f01565b615163614f01565b60015f80516020615c938339815191525561517c6142c3565b301561082457633b9aca008060cf5460801c01615197612bcd565b811161521f576151b1610f9e6151ab614b58565b926149d5565b6151bb8130615511565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36116e230337f0000000000000000000000000000000000000000000000000000000000000000614ebb565b6040516304ffa0ff60e51b8152600490fd5b9081602091031261038e575161069481612561565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816152d0575b5061529657604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020615c3383398151915284036152b7576116e292935061592d565b604051632a87526960e21b815260048101859052602490fd5b6152ea91955060203d60201161055b5761054d818361061c565b935f615270565b60d154806152fe57505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b03166119b5565b9080821015615340575090565b905090565b60d554908160801c81158015615374575b156153615750905090565b6001600160801b0361069493169161341a565b508015615356565b6e5661756c7456616c696461746f727360881b602060405161539d816105b3565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176105ce5760405251902090565b8151919060418303615479576154729250602082015190606060408401519301515f1a906159cf565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561038e575f809160246040518094819363a3066aab60e01b83523060048401525af18015610562576154df5750565b6116e2906105d3565b604051600160f81b60208201525f60218201523060601b602c82015260208152610694816105b3565b5f80516020615c5383398151915260205f9261552c856149d5565b60cf54906155446001600160801b03918284166138b2565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b0382169182156156a35760801c6155b46155a5826155a0613cd4565b612cca565b6155ae85612984565b90615333565b90811561569c576155c482614b21565b9384156156945782615611611f3061326f6116e296610f9e9661560c6155f061326f8d6156899a612cca565b6001600160801b03166001600160801b031960d054161760d055565b612be9565b61561b8187615ac1565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a161326f61566d61565c886149d5565b60cf546001600160801b0316612942565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c612942565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f81815260d360205260409020805483810391908211610c4f575f935f80516020615c5383398151915292602092556156ea816149d5565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b5f8061573c9260018060a01b03169360208151910182865af1615735612f80565b9083615baf565b805190811515918261576a575b50506157525750565b60249060405190635274afe760e01b82526004820152fd5b61577d9250602080918301019101612cb5565b155f80615749565b601f8111615791575050565b5f80525f80516020615c13833981519152906020601f840160051c830193106157d4575b601f0160051c01905b8181106157c9575050565b5f81556001016157be565b90915081906157b5565b90601f82116157eb575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c83019310615845575b601f0160051c01905b81811061583b57505050565b5f8155820161582f565b9091508190615826565b9081516001600160401b0381116105ce57600190615876816158718454610567565b6157de565b602080601f83116001146158ab575081906158a79394955f926150af5750508160011b915f199060031b1c19161790565b9055565b90601f198316956158dd60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061591657505083859697106158fe575b505050811b019055565b01515f1960f88460031b161c191690555f80806158f4565b8087859682949686015181550195019301906158e1565b90813b156159ae575f80516020615c3383398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115615993576131b891615b96565b50503461599c57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615a585790615a286020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15610562575f516001600160a01b03811615615a4e57905f905f90565b505f906001905f90565b5050505f9160039190565b60d15490680100000000000000008210156105ce57600182018060d155821015612f6e5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020615c7383398151915290910155565b91909180158015615b8e575b615b7c57615ad96152f1565b908101809111610c4f576001600160a01b03808211615b5c576001600160601b0390818511615b3c57906116e29394615b26615b3793615b176116e4565b95166001600160a01b03168552565b166001600160601b03166020830152565b615a63565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b508215615acd565b5f8061069493602081519101845af4615bad612f80565b915b90615bd65750805115615bc457805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580615c09575b615be7575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15615bdf56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212204b070bea2fd8d99546c7cd76f5ebae9213985e653bd6ba5b56ff652a77a09acd64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d1141461037f578063066055e01461037a57806306fdde031461037557806307a2d13a14610370578063095ea7b31461036b5780630d392cd91461036657806318160ddd1461032a5780631a7ff55314610361578063201b9eb51461035c57806322758a4a1461035757806323b872dd146103525780632999ad3f1461034d5780632cdf7401146103485780632e2d298414610343578063313ce5671461033e5780633229fa951461033957806333194c0a146103345780633644e5151461032f5780633a98ef391461032a578063439fab911461032557806343e82a7914610320578063469048401461031b5780634ec96b22146103165780634f1ef2861461031157806352d1902d1461030c57806354fd4d50146103075780635c60da1b146103025780635cfc1a51146102fd57806360d60e6e146102f857806370a082311461028a57806372b410a8146102f3578063754c3888146102ee57806376b58b90146102e95780637ecebe00146102e45780637fd6f15c146102df57806383d430d5146102da5780638697d2c2146102d55780638ceab9aa146102d057806395d89b41146102cb578063a49a1e7d146102c6578063a9059cbb146102c1578063ac9650d8146102bc578063ad3cb1cc146102b7578063b0d11302146102b2578063b1f0e7c7146102ad578063c6e6f592146102a8578063d505accf146102a3578063d83ad00c1461029e578063dd62ed3e14610299578063e74b981b14610294578063ee3bd5df1461028f578063f04da65b1461028a578063f6a6830f14610285578063f851a440146102805763f98f5b920361000e576128c2565b61289a565b612859565b611ab8565b612833565b612806565b6127a7565b612781565b61256c565b612543565b612529565b6124f6565b6124b1565b61244c565b6123ab565b612359565b6122b5565b6120cc565b611e6c565b611c9c565b611c78565b611c3d565b611bec565b611b80565b611af3565b611a9a565b611a80565b611a4c565b611a31565b6119c8565b611742565b61165f565b611637565b61153a565b611397565b610872565b611322565b6112e8565b6112bc565b6112a1565b611121565b611107565b610c7d565b610ba1565b610b78565b610910565b610898565b610840565b610794565b61075d565b610697565b6103c3565b610392565b5f91031261038e57565b5f80fd5b3461038e575f36600319011261038e57602060cf5460801c604051908152f35b6001600160801b0381160361038e57565b3461038e57602036600319011261038e576004356103e0816103b2565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1908115610562575f91610533575b50335f90815261016e6020526040902061045c90612909565b916001600160801b0361047684516001600160801b031690565b1615610521576104ca8361048c61051d956131f2565b6104b66104a9846104a484516001600160801b031690565b612942565b6001600160801b03168252565b335f90815261016e6020526040902061295b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b610555915060203d60201161055b575b61054d818361061c565b8101906128ef565b5f610443565b503d610543565b6128fe565b90600182811c92168015610595575b602083101461058157565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610576565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176105ce57604052565b61059f565b6001600160401b0381116105ce57604052565b60a081019081106001600160401b038211176105ce57604052565b608081019081106001600160401b038211176105ce57604052565b90601f801991011681019081106001600160401b038211176105ce57604052565b5f5b83811061064e5750505f910152565b818101518382015260200161063f565b906020916106778151809281855285808601910161063d565b601f01601f1916010190565b90602061069492818152019061065e565b90565b3461038e575f36600319011261038e576040515f80546106b681610567565b8084529060209060019081811690811561073357506001146106ef575b61051d856106e38187038261061c565b60405191829182610683565b5f80805293505f80516020615c138339815191525b838510610720575050505081016020016106e38261051d6106d3565b8054868601840152938201938101610704565b86955061051d969350602092506106e394915060ff191682840152151560051b82010192936106d3565b3461038e57602036600319011261038e57602061077b600435612984565b604051908152f35b6001600160a01b0381160361038e57565b3461038e57604036600319011261038e576004356107b181610783565b6001600160a01b03811690602435908215610824576107ec8291335f52600260205260405f209060018060a01b03165f5260205260405f2090565b556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b60405163d92e233d60e01b8152600490fd5b8015150361038e57565b3461038e57604036600319011261038e5761001860043561086081610783565b6024359061086d82610836565b6129aa565b3461038e575f36600319011261038e5760206001600160801b0360cf5416604051908152f35b3461038e5760031960203682011261038e57600435906001600160401b03821161038e57608090823603011261038e576108d76108de91600401613575565b919061370b565b6108e457005b6108ec615579565b806108f357005b5f906040519081525f80516020615c5383398151915260203092a3005b3461038e57606036600319011261038e5760043561092d81610783565b602435906044359061093e82610783565b61094733613890565b61094f614c97565b6109576142c3565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af1948515610562575f95610b59575b50335f90815261016e602052604090206109d290612909565b926001600160801b036109ec85516001600160801b031690565b1615610af55750506109fd826131f2565b610a29610a1c610a0c876149d5565b84516001600160801b03166138b2565b6001600160801b03168352565b335f90815260d360205260409020610a4b90610a46905b54612984565b614d23565b610a6b610a5f84516001600160801b031690565b6001600160801b031690565b11610ae357335f90815261016e6020526040902061051d957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610ab1919061295b565b604080516001600160a01b0395861681526020810187905290810191909152921660608301523391806080810161050a565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561056257610b3792610b28915f91610b3c575b506149d5565b6001600160801b031690840152565b6109fd565b610b539150833d851161055b5761054d818361061c565b5f610b22565b610b71919550833d851161055b5761054d818361061c565b935f6109b9565b3461038e575f36600319011261038e5761026a546040516001600160a01b039091168152602090f35b3461038e57606036600319011261038e57600435610bbe81610783565b60243590610bcb82610783565b6001600160a01b0381165f8181526002602090815260408083203384529091529020546044359160018201610c1b575b610c0f84610c0a858883614e2d565b6138cd565b60405160018152602090f35b919093818503948511610c4f575f928352600260209081526040808520338652909152909220939093559180610c0f610bfb565b61292e565b606090600319011261038e5760043590602435610c7081610783565b9060443561069481610783565b3461038e57610c8b36610c54565b906001600160a01b038083161561082457610ca46142c3565b807f00000000000000000000000000000000000000000000000000000000000000001691823b1561038e5760408051631d8557d760e01b815260049491905f81878183875af18015610562576110ee575b506001600160a01b0383165f90815261016e60205260409020610d1790612909565b6001600160801b039283610d3283516001600160801b031690565b16156110de57610d41826131f2565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa978815610562575f986110ad575b50602097888101956001600160401b03918280610dba8a516001600160401b031690565b161461109d57908c92918751918c8380610de66303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561056257610e12938e5f94611078575b5050516001600160801b03165b1690613321565b96610e30610a408a60018060a01b03165f5260d360205260405f2090565b928389118015611068575b61105857908b610e799392610e5789516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561056257670de0b6b3a764000094610ec8948e5f9561102b575b5050610eba610eac610ec092612ec6565b93516001600160401b031690565b93612ec6565b92169061341a565b101561101d578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af1908115610562577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610ffa95610f7293610fff575b5050610f556104a9610f458c6149d5565b83516001600160801b0316612942565b6001600160a01b0386165f90815261016e6020526040902061295b565b610f7b82614b21565b90610fb9610f9e610f8b856149d5565b60cf5460801c036001600160801b031690565b6001600160801b0360cf549181199060801b1691161760cf55565b610fc382866156a9565b610fcd8389614a08565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b8161101592903d1061055b5761054d818361061c565b505f80610f34565b835163185cfc6d60e11b8152fd5b610ec092955061104e610eba9282610eac93903d1061055b5761054d818361061c565b959250508e610e9b565b875163efda1a2760e01b81528590fd5b50611071612a42565b8911610e3b565b610e0b929450908161109592903d1061055b5761054d818361061c565b92908e610dfe565b8651630709133160e01b81528490fd5b6110d091985060603d6060116110d7575b6110c8818361061c565b810190613961565b965f610d96565b503d6110be565b825163673f032f60e11b81528790fd5b806110fb611101926105d3565b80610384565b5f610cf5565b3461038e575f36600319011261038e57602061077b612a42565b3461038e5761112f36610c54565b9161113933613890565b61114282613890565b61114a614af2565b6040926111a484516323b872dd60e01b60208201523360248201523060448201528360648201526064815261117e816105e6565b7f0000000000000000000000000000000000000000000000000000000000000000615714565b6111ac6142c3565b6001600160a01b03831692831561129057821561127f57826111d3610a5f60cf5460801c90565b01906111dd612bcd565b821161126e57611254610f9e959361122e86947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c9461122961122160209c9a614ba7565b9a8b936149d5565b615511565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020615c938339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b3461038e575f36600319011261038e57602060405160128152f35b3461038e575f36600319011261038e5760206112d6612a7f565b6040516001600160a01b039091168152f35b3461038e575f36600319011261038e5760206040517f81812efbf43b69af38830f31dcb806af2764ff4398ba7ce084500c10160479b18152f35b3461038e575f36600319011261038e57602061077b612aba565b9181601f8401121561038e578235916001600160401b03831161038e576020838186019501011161038e57565b602060031982011261038e57600435906001600160401b03821161038e576113939160040161133c565b9091565b3461038e576113a536611369565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c168015611526575b6115145768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa928315610562575f936114f5575b50604051636f4fa30f60e01b8152938285600481335afa908115610562576114629561145d945f936114c2575b50506114569192810190612b2e565b9083613ee8565b613fa8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b611456935090816114e792903d106114ee575b6114df818361061c565b810190612aef565b915f611447565b503d6114d5565b61150d919350823d84116114ee576114df818361061c565b915f61141a565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b03821610156113d6565b3461038e5761154836610c54565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105625782915f91611618575b501633036116065781610ffa6115d386867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966139bb565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611631915060203d6020116114ee576114df818361061c565b5f61159b565b3461038e575f36600319011261038e57609c546040516001600160a01b039091168152602090f35b3461038e57602036600319011261038e5760043561167c81610783565b60018060a01b03165f5261016e602052602060405f206040519061169f826105b3565b54906001600160801b03918281169081835260801c848301526116c7575b5116604051908152f35b6116d0816131f2565b6116bd565b604051906116e2826105e6565b565b604051906116e2826105b3565b6001600160401b0381116105ce57601f01601f191660200190565b929192611718826116f1565b91611726604051938461061c565b82948184528183011161038e578281602093845f960137010152565b60408060031936011261038e57600490813561175d81610783565b6024356001600160401b03811161038e573660238201121561038e5761178c903690602481870135910161170c565b91611795613fb4565b8051926117cc846117be60209363439fab9160e01b85840152846024840152604483019061065e565b03601f19810186528561061c565b6117d4613fb4565b6117dc614094565b6001600160a01b03838116801592919087908415611993575b8415611925575b84156118c1575b5050821561182b575b505061181c576100188383615246565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa918215610562575f92611894575b5050155f8061180c565b6118b39250803d106118ba575b6118ab818361061c565b810190612cb5565b5f8061188a565b503d6118a1565b855163054fd4d560e41b81529294508391839182905afa9081156105625760039160ff915f916118f8575b5016141591865f611803565b6119189150843d861161191e575b611910818361061c565b810190615231565b5f6118ec565b503d611906565b935050835163198ca60560e11b815282818981875afa9081156105625788917f81812efbf43b69af38830f31dcb806af2764ff4398ba7ce084500c10160479b1915f91611976575b501415936117fc565b61198d9150853d871161055b5761054d818361061c565b5f61196d565b5f80516020615c338339815191525490945084906119c1906001600160a01b03165b6001600160a01b031690565b14936117f5565b3461038e575f36600319011261038e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003611a1f5760206040515f80516020615c338339815191528152f35b60405163703e46dd60e11b8152600490fd5b3461038e575f36600319011261038e57602060405160028152f35b3461038e575f36600319011261038e575f80516020615c33833981519152546040516001600160a01b039091168152602090f35b3461038e575f36600319011261038e57602061077b612bcd565b3461038e57602036600319011261038e57602061077b600435612bf6565b3461038e57602036600319011261038e57600435611ad581610783565b60018060a01b03165f5260d3602052602060405f2054604051908152f35b3461038e575f36600319011261038e57604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610562576020915f91611b63575b506040519015158152f35b611b7a9150823d84116118ba576118ab818361061c565b5f611b58565b3461038e57602036600319011261038e57600435611b9d81610783565b611ba5614094565b61010980546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b3461038e57608036600319011261038e5761051d611c20600435611c0f81610783565b606435906044359060243590612cd7565b604080519384526020840192909252908201529081906060820190565b3461038e57602036600319011261038e57600435611c5a81610783565b60018060a01b03165f526003602052602060405f2054604051908152f35b3461038e575f36600319011261038e57602061ffff609c5460a01c16604051908152f35b3461038e5760031960403682011261038e5760049081356001600160401b0380821161038e5760a082850193833603011261038e5760243590811161038e57611ce8903690850161133c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b1561038e5760405163837d444160e01b8152905f908290818381611d3b8c828f01612ddb565b03925af1801561056257611e59575b50611d536142c3565b611d5b6131bb565b9081163314159182611e2a575b50509050611e19576044019160b0611d808484612e59565b90500480158015611e01575b611df157611da1611d9b612a42565b91612eae565b11611de2575060b0611db38383612e59565b9050145f14611dcf5761001891611dc991612e59565b90614876565b61001891611ddc91612e59565b90614646565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611e0c8484612e59565b905060b082021415611d8c565b604051634ca8886760e01b81528390fd5b611e4d9250611e47611e5194611e3f8861434e565b92369161170c565b91614429565b1590565b805f80611d68565b806110fb611e66926105d3565b5f611d4a565b3461038e57606036600319011261038e57600435602435611e91604435828433612cd7565b9192611ebd7f000000000000000000000000000000000000000000000000000000000000000082612be9565b421080156120c4575b80156120bc575b6120aa577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611f1186611f0c610a5f60d0546001600160801b031690565b61400d565b1561201857611f4b611f30611f25866149d5565b60d05460801c612942565b6001600160801b0360d0549181199060801b1691161760d055565b60408051336020820190815291810184905260608082018990528152601f1993915f91611f8f9190611f7e60808261061c565b5190205f5260d260205260405f2090565b555f9360018311611fc8575b50505050611fa98233614a08565b604080519485526020850191909152830152339180606081015b0390a2005b61200e92939450611fd99088612be9565b60408051336020820190815291810193909352606083018290529094909190611f7e9082608081015b0390810183528261061c565b555f808080611f9b565b6120206142c3565b61205c61204061202f866149d5565b60d5546001600160801b0316612942565b6001600160801b03166001600160801b031960d554161760d555565b61209161207661206b856149d5565b60d55460801c612942565b6001600160801b0360d5549181199060801b1691161760d555565b6120a56120a08460d654612be9565b60d655565b611f4b565b604051630e3d8e8d60e11b8152600490fd5b508215611ecd565b508115611ec6565b3461038e5760408060031936011261038e57602435906004356120ee83610783565b6120f66142c3565b80156122a4576001600160a01b0383169081156122935761211681612984565b9081156122825761212682615345565b61212f836149d5565b60cf5460801c9061213f91612942565b61215e906001600160801b0360cf549181199060801b1691161760cf55565b61216882336156a9565b60d554958660801c828160d6549061217f91612be9565b98612189876149d5565b61219b916001600160801b03166138b2565b6121bb906001600160801b03166001600160801b031960d554161760d555565b6121c491612be9565b6121cd906149d5565b6121ec906001600160801b0360d5549181199060801b1691161760d555565b85516001600160a01b039190911660208201908152426040830152606080830189905282529061221d60808261061c565b519020612232905f5260d260205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3612279336138cd565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461038e575f36600319011261038e576040515f600180546122d681610567565b808552916020916001811690811561073357506001146123005761051d856106e38187038261061c565b60015f90815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838510612346575050505081016020016106e38261051d6106d3565b805486860184015293820193810161232a565b3461038e57611fc37f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf61238b36611369565b9290612395614094565b6040519182916020835233956020840191612dbb565b3461038e57604036600319011261038e576123d56004356123cb81610783565b6024359033614e2d565b6123de336138cd565b602060405160018152f35b6020808201906020835283518092526040830192602060408460051b8301019501935f915b84831061241e5750505050505090565b909192939495848061243c600193603f198682030187528a5161065e565b980193019301919493929061240e565b3461038e57602036600319011261038e576001600160401b0360043581811161038e573660238201121561038e57806004013591821161038e573660248360051b8301011161038e5761051d9160246124a59201613021565b604051918291826123e9565b3461038e575f36600319011261038e5761051d6040516124d0816105b3565b60058152640352e302e360dc1b602082015260405191829160208352602083019061065e565b3461038e575f36600319011261038e5761250e614af2565b6125166130ce565b60015f80516020615c9383398151915255005b3461038e575f36600319011261038e5760206112d66131bb565b3461038e57602036600319011261038e57602061077b600435614b21565b60ff81160361038e57565b3461038e5760e036600319011261038e5760043561258981610783565b60243561259581610783565b6044359060643592608435906125aa82612561565b6001600160a01b038381169590929086156108245742811061276f576020915f9161200261269d89878a6126606125df612aba565b6001600160a01b0384165f9081526003602052604090209097908054906001820190556040519586948d8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98552600180871b038092166020860152166040840152606083015260808201520152565b0391612674601f199384810183528261061c565b5190206040519384918983019687909160429261190160f01b8352600283015260228201520190565b5190206040805191825260ff92909216602082015260a4359181019190915260c435606082015281805260809060015afa15610562575f51928284168015908115612762575b506127505761273d85916127287f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259660018060a01b03165f52600260205260405f2090565b9060018060a01b03165f5260205260405f2090565b5560405193845216918060208101610ffa565b6040516323389ba560e21b8152600490fd5b905083831614155f6126e3565b604051631ab7da6b60e01b8152600490fd5b3461038e575f36600319011261038e5760206001600160801b0360d05416604051908152f35b3461038e57604036600319011261038e5760206127fd6004356127c981610783565b602435906127d682610783565b60018060a01b03165f526002835260405f209060018060a01b03165f5260205260405f2090565b54604051908152f35b3461038e57602036600319011261038e5761001860043561282681610783565b61282e614094565b614bee565b3461038e575f36600319011261038e5760206001600160801b0360d55416604051908152f35b3461038e57602036600319011261038e5760043561287681610783565b60018060a01b03165f5261026b602052602060ff60405f2054166040519015158152f35b3461038e575f36600319011261038e576037546040516001600160a01b039091168152602090f35b3461038e57602036600319011261038e576100186004356128e281610783565b6128ea614094565b614c50565b9081602091031261038e575190565b6040513d5f823e3d90fd5b90604051612916816105b3565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b039182169082160391908211610c4f57565b815160209092015160801b6001600160801b0319166001600160801b0392909216919091179055565b60cf546001600160801b038116908161299c57505090565b916106949260801c9061341a565b61026a546001600160a01b03919082163303611606576001600160a01b0381165f90815261026b60205260409020549215159260ff1615158314612a3d576001600160a01b0381165f90815261026b6020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b612a4a613cd4565b60d0546001600160801b03612a60818316612984565b9060d55416019060801c01908181115f14612a79570390565b50505f90565b6101a1546001600160a01b03168015612a955790565b507f000000000000000000000000000000000000000000000000000000000000000090565b467f000000000000000000000000000000000000000000000000000000000000000003612ae75760045490565b610694613dc2565b9081602091031261038e575161069481610783565b359061ffff8216820361038e57565b9080601f8301121561038e578160206106949335910161170c565b9060208282031261038e5781356001600160401b039283821161038e57019060a08282031261038e57612b5f6116d5565b9282358452612b7060208401612b04565b6020850152604083013581811161038e5782612b8d918501612b13565b6040850152606083013581811161038e5782612baa918501612b13565b6060850152608083013590811161038e57612bc59201612b13565b608082015290565b60d4548061069457505f1990565b9060b08201809211610c4f57565b91908201809211610c4f57565b6001600160801b0360d05416612c0a6152f1565b908101809111610c4f578110612c3d57612c2e60d654612c28614024565b90612be9565b1115612c38575f90565b5f1990565b60d19060d1549182915f905b848210612c6357505050811015612c5d5790565b505f1990565b909193808316906001818518811c8301809311610c4f575f8790525f80516020615c738339815191528301546001600160a01b0316841015612caa575050935b9190612c49565b909591019250612ca3565b9081602091031261038e575161069481610836565b91908203918211610c4f57565b604080516001600160a01b03909216602083019081529082019390935260608101829052909190612d1581608081015b03601f19810183528261061c565b5190205f5260d260205260405f2054918215612d7f576001600160801b0360d0541690612d406152f1565b918201809211610c4f578391831015612d6d5791612d5d92614128565b90915b828103908111610c4f5792565b5090612d78916140a8565b9091612d60565b5050505f905f905f90565b9035601e198236030181121561038e5701602081359101916001600160401b03821161038e57813603831361038e57565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a061069492602081528235602082015260208301356040820152612e17612e076040850185612d8a565b84606085015260c0840191612dbb565b90612e4a612e3f612e2b6060870187612d8a565b601f19858703810160808701529591612dbb565b946080810190612d8a565b93909282860301910152612dbb565b903590601e198136030182121561038e57018035906001600160401b03821161038e5760200191813603831361038e57565b634e487b7160e01b5f52601260045260245ffd5b8115612ea9570490565b612e8b565b90670de0b6b3a76400009180830292830403610c4f57565b90670de0b6b3a764000091828102928184041490151715610c4f57565b6001600160401b0381116105ce5760051b60200190565b90612f0482612ee3565b612f11604051918261061c565b8281528092612f22601f1991612ee3565b01905f5b828110612f3257505050565b806060602080938501015201612f26565b634e487b7160e01b5f52603260045260245ffd5b90821015612f6e576113939160051b810190612e59565b612f43565b908092918237015f815290565b3d15612faa573d90612f91826116f1565b91612f9f604051938461061c565b82523d5f602084013e565b606090565b60208183031261038e578051906001600160401b03821161038e570181601f8201121561038e578051612fe1816116f1565b92612fef604051948561061c565b8184526020828401011161038e57610694916020808501910161063d565b8051821015612f6e5760209160051b010190565b91909161302d83612efa565b925f5b81811061303c57505050565b5f80613049838587612f57565b6040939161305b855180938193612f73565b0390305af490613069612f80565b911561309057509060019161307e828861300d565b52613089818761300d565b5001613030565b90604481511061038e576130ca6130b560049283810151602480918301019101612faf565b925162461bcd60e51b81529283928301610683565b0390fd5b47633b9aca0081106131b857604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610562575f92613197575b506001600160ff1b03821161317e57907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db916131648261370b565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b6131b191925060203d60201161055b5761054d818361061c565b905f613129565b50565b610109546001600160a01b03168061069457507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91613288575b5060208201916001600160801b03918284511691828214613281578361327461326f61327c95858486511661341a565b6149d5565b1690526149d5565b169052565b5050505050565b6132a1915060203d60201161055b5761054d818361061c565b5f61323f565b90808202905f1981840990828083109203918083039214613316576127109082821115613304577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f198184099082808310920391808303921461338457670de0b6b3a76400009082821115613304577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906106949250612e9f565b9091828202915f198482099383808610950394808603951461340d578483111561330457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b9081606091031261038e578051916040602083015192015161069481610836565b81835290916001600160fb1b03831161038e5760209260051b809284830137010190565b90602082528035602083015260208101358060130b80910361038e576040830152604081013561350181610783565b6001600160a01b031660608381019190915281013536829003601e190181121561038e5701602081359101906001600160401b03811161038e578060051b3603821361038e5760a08360808061069496015201916134ae565b9190915f8382019384129112908015821691151617610c4f57565b6040516325f56f1160e01b81526001600160a01b039291606090829081906135a090600483016134d2565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1928315610562575f915f905f956136c6575b50841561367357816135ea612a7f565b16917f000000000000000000000000000000000000000000000000000000000000000016821461366c57509060205f92600460405180958193634641257d60e01b83525af190811561056257613647925f9261364b575b5061355a565b9190565b61366591925060203d60201161055b5761054d818361061c565b905f613641565b9081613679575b50509190565b803b1561038e57604051636ee3193160e11b815260048101929092525f908290602490829084905af18015610562576136b3575b80613673565b806110fb6136c0926105d3565b5f6136ad565b919450506136ec915060603d6060116136f4575b6136e4818361061c565b81019061348d565b93905f6135da565b503d6136da565b600160ff1b8114610c4f575f0390565b80156131b857613720610a5f60cf5460801c90565b5f82126137ed578161373191612be9565b9061373e610f9e836149d5565b613753609c549161ffff8360a01c16906132a7565b8015612a3d57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793613791610a5f60cf546001600160801b031690565b806137d757505061317990925b6001600160a01b0316916137b28484615511565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b613179926137e79203908461341a565b9261379e565b906137f7906136fb565b61380c610a5f60d5546001600160801b031690565b8061382c575b508061381c575050565b61326f610f9e916116e293612cca565b906138877f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a9161387761204061386c6138658888612be9565b878561341a565b8080940396036149d5565b6040519081529081906020820190565b0390a15f613812565b6001600160a01b03165f90815261026b602052604090205460ff161561160657565b9190916001600160801b0380809416911601918211610c4f57565b60018060a01b0381165f5261016e60205260405f2090604051916138f0836105b3565b54906001600160801b03918281169081855260801c602085015215612a3d57610a46610a40613943926139216142c3565b61392a866131f2565b6001600160a01b03165f90815260d36020526040902090565b91511611610ae357565b51906001600160401b038216820361038e57565b9081606091031261038e5760405190606082018281106001600160401b038211176105ce576139b3916040918252805161399a816103b2565b84526139a86020820161394d565b60208501520161394d565b604082015290565b92906001600160a01b039081811615610824576139d66142c3565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561038e57604094855193631d8557d760e01b85526004945f81878183895af1801561056257613cc1575b506001600160a01b0388165f90815261016e60205260409020613a4990612909565b906001600160801b03613a6383516001600160801b031690565b1615613cb157613a72826131f2565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561056257613c92575b508651936303d1689d60e11b97888652602091828780613aec888c83019190602083019252565b0381845afa968715610562575f97613c73575b508699613b1f610a408d60018060a01b03165f5260d360205260405f2090565b88118015613c63575b613c53579083613b6592613b4387516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa988915610562575f85948894613baa9c613c36575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561056257610f45613bf194613bd4936104a9936116e29a613c18575b50506149d5565b6001600160a01b0388165f90815261016e6020526040902061295b565b613c13613bfd83614b21565b8097613c0e610f9e610f8b876149d5565b6156a9565b614a08565b81613c2e92903d1061055b5761054d818361061c565b505f80613bcd565b613c4c90873d891161055b5761054d818361061c565b505f613b7f565b825163efda1a2760e01b81528990fd5b50613c6c612a42565b8811613b28565b613c8b919750833d851161055b5761054d818361061c565b955f613aff565b613caa9060603d6060116110d7576110c8818361061c565b505f613ac5565b875163673f032f60e11b81528690fd5b806110fb613cce926105d3565b5f613a27565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa908115610562575f91613da5575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561056257610694935f93613d86575b5050612be9565b613d9d929350803d1061055b5761054d818361061c565b905f80613d7f565b613dbc9150833d851161055b5761054d818361061c565b5f613d2b565b6040515f905f5490613dd382610567565b9283825260209384830193600190866001821691825f14613ec8575050600114613e85575b50509181613e0e613e7f93612d0795038261061c565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b51902090565b5f80805286935091905f80516020615c138339815191525b828410613eb35750505082010181613e0e613df8565b80548685018601528794909301928101613e9d565b60ff1916875292151560051b85019092019250839150613e0e9050613df8565b9190613ef2614f01565b608082015190613f00614f01565b6001600160a01b038416801561082457613fa094613f9093613f79926001600160601b0360a01b60375416176037557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf6040516020815280613f673394602083019061065e565b0390a2602085015161ffff1690614f42565b613f838351614f93565b613f8b614fc3565b614fef565b606060408201519101519061501e565b6116e261514b565b6116e2906128ea614f01565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613ff2575b5050611a1f57565b5f80516020615c338339815191525416141590505f80613fea565b906140166152f1565b918201809211610c4f571090565b61402c613cd4565b60d0548060801c8203918211610c4f57816140506001600160801b03809316612984565b9081614076575b50508115612a7957610694916140719160d5541690615333565b615345565b919250908181111561408c57035b905f80614057565b50505f614084565b6037546001600160a01b0316330361160657565b6140b0614024565b9160d654928301809311610c4f57808311156140fa576140d1920390615333565b9060d5548060801c80155f146140e75750508190565b6001600160801b0361069492168461341a565b5050505f905f90565b90604051614110816105b3565b91546001600160a01b038116835260a01c6020830152565b60d1545f9485949390918084108015906142bb575b6142ae5783614278575f5b60d15f526001600160a01b031661416d5f80516020615c738339815191528601614103565b8051909790614184906001600160a01b03166119b5565b986141a961419d6020809b01516001600160601b031690565b6001600160601b031690565b94838110801561426e575b61425c5791600193979a956141d36141df939488035b838c0390615333565b8092019887039161341a565b01970193808611801590614252575b6142475760d15f5282906142105f80516020615c738339815191528701614103565b805190890151969992966001600160a01b0390911694600193926141df9290916001600160601b03909116906141d39088036141ca565b945050509250509190565b50818510156141ee565b60405163e8722f8f60e01b8152600490fd5b50808b11156141b4565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce28401546001600160a01b0316614148565b505093505050505f905f90565b50841561413d565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f9161432f575b5061431d57565b60405163e775715160e01b8152600490fd5b614348915060203d6020116118ba576118ab818361061c565b5f614316565b604290467f0000000000000000000000000000000000000000000000000000000000000000036143fd5761010a54905b61439561438e6040830183612e59565b369161170c565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b084523560408301526060820152606081526143e081610601565b5190206040519161190160f01b8352600283015260228201522090565b61440561537c565b9061437e565b6004111561441557565b634e487b7160e01b5f52602160045260245ffd5b6144338383615449565b506144408195929561440b565b1593846144dc575b508315614456575b50505090565b5f92935090829160405161448e81612d076020820194630b135d3f60e11b998a8752602484015260406044840152606483019061065e565b51915afa9061449b612f80565b826144ce575b826144b1575b50505f8080614450565b6144c6919250602080825183010191016128ef565b145f806144a7565b9150602082511015916144a1565b6001600160a01b0383811691161493505f614448565b906144fc82612ee3565b614509604051918261061c565b828152809261451a601f1991612ee3565b0190602036910137565b9060301161038e5790603090565b9060901161038e5760300190606090565b9060b01161038e5760900190602090565b9093929384831161038e57841161038e578101920390565b602090836116e293959495604051968361458f899551809288808901910161063d565b84019185830137015f8382015203808552018361061c565b3590602081106145b5575090565b5f199060200360031b1b1690565b916020610694938181520191612dbb565b91926145fe6145ee61460c9360808652608086019061065e565b602095858203602087015261065e565b90838203604085015261065e565b906060818303910152602080845192838152019301915f5b828110614632575050505090565b835185529381019392810192600101614624565b61464e615483565b6060906060905f809460b0810492614665846144f2565b965f905b85821061478457506001600160a01b03947f000000000000000000000000000000000000000000000000000000000000000094506146e09350602092506146b09150612eae565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561056257614765575b501661471d6154e8565b813b1561038e575f80946147476040519788968795869463c82655b760e01b8652600486016145d4565b03925af18015610562576147585750565b806110fb6116e2926105d3565b61477d9060203d6020116118ba576118ab818361061c565b505f614713565b6148096147d96147e46147c66147bd7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612bdb565b80998989614554565b92909a6147d3848d614524565b9161456c565b9a6147d3838c614532565b988b614803866147fd6147f78686614543565b906145a7565b9261300d565b52614524565b90614819604051928392836145c3565b0390a160010183614669565b929461485e670de0b6b3a7640000966148506080979461486c969b9a9b60a0895260a0890191612dbb565b90868203602088015261065e565b918483036040860152612dbb565b9460608201520152565b9061487f615483565b6148898183614524565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af18015610562576149b6575b50169061491b6154e8565b916149346147f761492c8489614532565b949098614543565b95813b1561038e575f8094614961604051998a9687958694630cac9f3160e01b86528c8c60048801614825565b03925af1928315610562577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936149a3575b50613179604051928392836145c3565b806110fb6149b0926105d3565b5f614993565b6149ce9060203d6020116118ba576118ab818361061c565b505f614910565b6001600160801b03908181116149e9571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b90614a11614af2565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561056257614ab094614aab925f91614ad3575b508411614ac6575b60405163a9059cbb60e01b60208201526001600160a01b0391909116602482015260448082019490945292835260648361061c565b615714565b6116e260015f80516020615c9383398151915255565b614ace615483565b614a76565b614aec915060203d60201161055b5761054d818361061c565b5f614a6e565b5f80516020615c938339815191526002815414614b0f5760029055565b604051633ee5aeb560e01b8152600490fd5b60cf54906001600160801b03821681158015614b50575b15614b435750905090565b6106949260801c9161341a565b508015614b38565b60cf546001600160801b0381169081614b75575050633b9aca0090565b60801c614b828183613395565b918115612ea957633b9aca0009614b965790565b60018101809111156106945761292e565b60cf546001600160801b0381169082158015614be6575b15614bc857505090565b60801c90614bd782828561341a565b928215612ea95709614b965790565b508115614bbe565b614bf66142c3565b6001600160a01b03168015614c3e57609c80546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61026a80546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610562575f91614d04575b5015614cf257565b604051630a62fbdb60e11b8152600490fd5b614d1d915060203d6020116118ba576118ab818361061c565b5f614cea565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561056257614dbe936001600160401b03610e0b6040614d9d946020975f91614e0e575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610562575f91614df5575090565b610694915060203d60201161055b5761054d818361061c565b614e27915060603d6060116110d7576110c8818361061c565b5f614d8e565b90614e3782613890565b614e4081613890565b6001600160a01b039182169182158015614eb1575b61082457825f5260d360205260405f2090815492858403938411610c4f575f80516020615c538339815191529360209355614ea08160018060a01b03165f5260d360205260405f2090565b8681540190556040519586521693a3565b5080821615614e55565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca0060648083019190915281526116e291614aab826105e6565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615614f3057565b604051631afcd79f60e31b8152600490fd5b614f4a614f01565b61271061ffff831611614f8157614f6090614bee565b609c805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b604051638a81d3b360e01b8152600490fd5b614f9b614f01565b8015614fb15760018101614fac5750565b60d455565b6040516331278a8760e01b8152600490fd5b614fcb614f01565b670de0b6b3a7640000614fdc612bcd565b10614fb157614fe961537c565b61010a55565b614ff7614f01565b6001600160a01b0316806150085750565b6101a180546001600160a01b0319169091179055565b615026614f01565b601e8151118015615140575b61512e5761503e614f01565b8051906001600160401b0382116105ce576150628261505d5f54610567565b615785565b602090816001601f8511146150ba575091806150989261509f95945f926150af575b50508160011b915f199060031b1c19161790565b5f5561584f565b6116e26150aa613dc2565b600455565b015190505f80615084565b5f80529190601f1984165f80516020615c13833981519152935f905b82821061511657505091600193918561509f979694106150fe575b505050811b015f5561584f565b01515f1960f88460031b161c191690555f80806150f1565b806001869782949787015181550196019401906150d6565b604051632d3f993760e21b8152600490fd5b50600a825111615032565b615153614f01565b61515b614f01565b615163614f01565b60015f80516020615c938339815191525561517c6142c3565b301561082457633b9aca008060cf5460801c01615197612bcd565b811161521f576151b1610f9e6151ab614b58565b926149d5565b6151bb8130615511565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36116e230337f0000000000000000000000000000000000000000000000000000000000000000614ebb565b6040516304ffa0ff60e51b8152600490fd5b9081602091031261038e575161069481612561565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f94816152d0575b5061529657604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020615c3383398151915284036152b7576116e292935061592d565b604051632a87526960e21b815260048101859052602490fd5b6152ea91955060203d60201161055b5761054d818361061c565b935f615270565b60d154806152fe57505f90565b60d15f527f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce201546001600160a01b03166119b5565b9080821015615340575090565b905090565b60d554908160801c81158015615374575b156153615750905090565b6001600160801b0361069493169161341a565b508015615356565b6e5661756c7456616c696461746f727360881b602060405161539d816105b3565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176105ce5760405251902090565b8151919060418303615479576154729250602082015190606060408401519301515f1a906159cf565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561038e575f809160246040518094819363a3066aab60e01b83523060048401525af18015610562576154df5750565b6116e2906105d3565b604051600160f81b60208201525f60218201523060601b602c82015260208152610694816105b3565b5f80516020615c5383398151915260205f9261552c856149d5565b60cf54906155446001600160801b03918284166138b2565b6001600160801b031990921691161760cf556001600160a01b031680845260d3825260408085208054870190555194855293a3565b60d054906001600160801b0382169182156156a35760801c6155b46155a5826155a0613cd4565b612cca565b6155ae85612984565b90615333565b90811561569c576155c482614b21565b9384156156945782615611611f3061326f6116e296610f9e9661560c6155f061326f8d6156899a612cca565b6001600160801b03166001600160801b031960d054161760d055565b612be9565b61561b8187615ac1565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a161326f61566d61565c886149d5565b60cf546001600160801b0316612942565b6001600160801b03166001600160801b031960cf54161760cf55565b60cf5460801c612942565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f81815260d360205260409020805483810391908211610c4f575f935f80516020615c5383398151915292602092556156ea816149d5565b60cf54906001600160801b03908183160316906001600160801b0319161760cf55604051908152a3565b5f8061573c9260018060a01b03169360208151910182865af1615735612f80565b9083615baf565b805190811515918261576a575b50506157525750565b60249060405190635274afe760e01b82526004820152fd5b61577d9250602080918301019101612cb5565b155f80615749565b601f8111615791575050565b5f80525f80516020615c13833981519152906020601f840160051c830193106157d4575b601f0160051c01905b8181106157c9575050565b5f81556001016157be565b90915081906157b5565b90601f82116157eb575050565b60019160015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906020601f840160051c83019310615845575b601f0160051c01905b81811061583b57505050565b5f8155820161582f565b9091508190615826565b9081516001600160401b0381116105ce57600190615876816158718454610567565b6157de565b602080601f83116001146158ab575081906158a79394955f926150af5750508160011b915f199060031b1c19161790565b9055565b90601f198316956158dd60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690565b925f905b88821061591657505083859697106158fe575b505050811b019055565b01515f1960f88460031b161c191690555f80806158f4565b8087859682949686015181550195019301906158e1565b90813b156159ae575f80516020615c3383398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115615993576131b891615b96565b50503461599c57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b90917f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615a585790615a286020945f9493604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15610562575f516001600160a01b03811615615a4e57905f905f90565b505f906001905f90565b5050505f9160039190565b60d15490680100000000000000008210156105ce57600182018060d155821015612f6e5760d15f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020615c7383398151915290910155565b91909180158015615b8e575b615b7c57615ad96152f1565b908101809111610c4f576001600160a01b03808211615b5c576001600160601b0390818511615b3c57906116e29394615b26615b3793615b176116e4565b95166001600160a01b03168552565b166001600160601b03166020830152565b615a63565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b508215615acd565b5f8061069493602081519101845af4615bad612f80565b915b90615bd65750805115615bc457805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580615c09575b615be7575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15615bdf56fe290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212204b070bea2fd8d99546c7cd76f5ebae9213985e653bd6ba5b56ff652a77a09acd64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoPrivVault.json b/test/shared/artifacts/GnoPrivVault.json deleted file mode 100644 index fa4c4ea1..00000000 --- a/test/shared/artifacts/GnoPrivVault.json +++ /dev/null @@ -1,1631 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoPrivVault", - "sourceName": "contracts/vaults/gnosis/GnoPrivVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "whitelister", - "type": "address" - } - ], - "name": "WhitelisterUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_whitelister", - "type": "address" - } - ], - "name": "setWhitelister", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "whitelistedAccounts", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "whitelister", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61020034620002af5762005317601f38829003908101601f19168301906001600160401b039081831185841017620002b3578085946040948552853961014094859181010312620002af576200005583620002c7565b906200006460208501620002c7565b9262000072818601620002c7565b956200008160608701620002c7565b906200009060808801620002c7565b926200009f60a08901620002c7565b94620000ae60c08a01620002c7565b96620000bd60e08b01620002c7565b976101009b620000cf8d8d01620002c7565b9a610120809d01519360805260a05260c0523060e0528b52468a52835260018060a01b03806101609516855280610180961686526101a09687526101c0971687526101e09788527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166200029e57808083160362000259575b505050519661503a9889620002dd8a3960805189818161174a015281816118e201528181612e4f01528181613b1e0152614682015260a051896114c1015260c05189818161368a01528181613ebb015281816140d70152614c87015260e05189818161164101526137ff01525188612a7901525187613b9401525186611a8801525185818161035d015281816105ea0152818161085f01528181612ab001528181613318015261479201525184818161091e01528181611124015281816133d701526147160152518381816123c10152612e97015251828181610d4a0152818161363901528181613f2501528181614121015281816142650152614a0b0152518161299b0152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f808062000151565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002af5756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d114146102c9578063066055e0146102c457806307a2d13a146102bf5780630d392cd9146102ba5780631a7ff553146102b5578063201b9eb5146102b057806322758a4a146102ab5780632999ad3f146102a65780632cdf7401146102a15780632e2d29841461029c5780633229fa951461029757806333194c0a146102925780633a98ef391461028d578063439fab911461028857806343e82a7914610283578063469048401461027e5780634ec96b22146102795780634f1ef2861461027457806352d1902d1461026f57806354fd4d501461026a5780635c60da1b146102655780635cfc1a511461026057806360d60e6e1461025b57806372b410a814610256578063754c38881461025157806376b58b901461024c5780637fd6f15c1461024757806383d430d5146102425780638697d2c21461023d5780638ceab9aa14610238578063a49a1e7d14610233578063ac9650d81461022e578063ad3cb1cc14610229578063b0d1130214610224578063b1f0e7c71461021f578063c6e6f5921461021a578063d83ad00c14610215578063e74b981b14610210578063ee3bd5df1461020b578063f04da65b14610206578063f6a6830f14610201578063f851a440146101fc5763f98f5b920361000e576121dd565b6121b6565b612175565b61213a565b612114565b6120e7565b6120c1565b6120a3565b612089565b612056565b612011565b611f9b565b611ea0565b611cb7565b611a5c565b61188c565b611868565b611817565b6117ac565b61171f565b611701565b6116e7565b6116b3565b611698565b61162f565b6113a9565b61121a565b6111f2565b6110f5565b610f52565b610ed1565b610e97565b610e6b565b610ceb565b610cd1565b610835565b6107e0565b610578565b610524565b6104f2565b6104b1565b61030d565b6102dc565b5f9103126102d857565b5f80fd5b346102d8575f3660031901126102d857602060985460801c604051908152f35b6001600160801b038116036102d857565b346102d85760203660031901126102d85760043561032a816102fc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156104ac575f9161047d575b50335f908152610137602052604090206103a690612224565b916001600160801b036103c084516001600160801b031690565b161561046b57610414836103d661046795612a9b565b6104006103f3846103ee84516001600160801b031690565b61225d565b6001600160801b03168252565b335f9081526101376020526040902061227b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61049f915060203d6020116104a5575b6104978183611328565b81019061220a565b5f61038d565b503d61048d565b612219565b346102d85760203660031901126102d85760206104cf6004356122ad565b604051908152f35b6001600160a01b038116036102d857565b801515036102d857565b346102d85760403660031901126102d857610018600435610512816104d7565b6024359061051f826104e8565b6122d3565b346102d8576003196020368201126102d857600435906001600160401b0382116102d85760809082360301126102d85761056361056a91600401612e1e565b9190612fb4565b61057057005b610018613139565b346102d85760603660031901126102d857600435610595816104d7565b60243590604435906105a6826104d7565b6105af33613269565b6105b7614667565b6105bf613b03565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af19485156104ac575f956107c1575b50335f9081526101376020526040902061063a90612224565b926001600160801b0361065485516001600160801b031690565b161561075d57505061066582612a9b565b61069161068461067487614214565b84516001600160801b031661328b565b6001600160801b03168352565b335f908152609c602052604090206106b3906106ae905b546122ad565b6146f3565b6106d36106c784516001600160801b031690565b6001600160801b031690565b1161074b57335f90815261013760205260409020610467957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610719919061227b565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610454565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa9182156104ac5761079f92610790915f916107a4575b50614214565b6001600160801b031690840152565b610665565b6107bb9150833d85116104a5576104978183611328565b5f61078a565b6107d9919550833d85116104a5576104978183611328565b935f610621565b346102d8575f3660031901126102d857610201546040516001600160a01b039091168152602090f35b60609060031901126102d85760043590602435610825816104d7565b90604435610832816104d7565b90565b346102d85761084336610809565b906001600160a01b0380831615610cbf5761085c613b03565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102d85760408051631d8557d760e01b815260049491905f81878183875af180156104ac57610ca6575b506001600160a01b0383165f908152610137602052604090206108cf90612224565b6001600160801b0392836108ea83516001600160801b031690565b1615610c96576108f982612a9b565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa9788156104ac575f98610c65575b50602097888101956001600160401b039182806109728a516001600160401b031690565b1614610c5557908c92918751918c838061099e6303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156104ac576109ca938e5f94610c30575b5050516001600160801b03165b1690612bca565b966109e86106a88a60018060a01b03165f52609c60205260405f2090565b928389118015610c20575b610c1057908b610a319392610a0f89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa9182156104ac57670de0b6b3a764000094610a80948e5f95610be3575b5050610a72610a64610a7892612770565b93516001600160401b031690565b93612770565b921690612cc3565b1015610bd5578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156104ac577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610bb295610b2a93610bb7575b5050610b0d6103f3610afd8c614214565b83516001600160801b031661225d565b6001600160a01b0386165f9081526101376020526040902061227b565b610b3382614360565b90610b71610b56610b4385614214565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610b7b82866147fd565b610b858389614247565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610bcd92903d106104a5576104978183611328565b505f80610aec565b835163185cfc6d60e11b8152fd5b610a78929550610c06610a729282610a6493903d106104a5576104978183611328565b959250508e610a53565b875163efda1a2760e01b81528590fd5b50610c2961236b565b89116109f3565b6109c39294509081610c4d92903d106104a5576104978183611328565b92908e6109b6565b8651630709133160e01b81528490fd5b610c8891985060603d606011610c8f575b610c808183611328565b8101906132ba565b965f61094e565b503d610c76565b825163673f032f60e11b81528790fd5b80610cb3610cb9926112c4565b806102ce565b5f6108ad565b60405163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d85760206104cf61236b565b346102d857610cf936610809565b91610d0333613269565b610d0c82613269565b610d14614331565b604092610d6e84516323b872dd60e01b602082015233602482015230604482015283606482015260648152610d48816112f2565b7f0000000000000000000000000000000000000000000000000000000000000000614d93565b610d76613b03565b6001600160a01b038316928315610e5a578215610e495782610d9d6106c760985460801c90565b0190610da7612477565b8211610e3857610e1e610b569593610df886947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610df3610deb60209c9a6143e6565b9a8b93614214565b6144d6565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020614fe58339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d8576020610e856123a8565b6040516001600160a01b039091168152f35b346102d8575f3660031901126102d85760206040517f9cf76a6c724b9ed90bd013cdce64a987a6e02c4220305b4a140a89d55a1ee0238152f35b346102d8575f3660031901126102d85760206001600160801b0360985416604051908152f35b9181601f840112156102d8578235916001600160401b0383116102d857602083818601950101116102d857565b60206003198201126102d857600435906001600160401b0382116102d857610f4e91600401610ef7565b9091565b346102d857610f6036610f24565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1680156110e1575b6110cf5768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156104ac575f936110b0575b50604051636f4fa30f60e01b8152938285600481335afa9081156104ac5761101d95611018945f9361107d575b505061101191928101906123f8565b9083613701565b6137e9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b611011935090816110a292903d106110a9575b61109a8183611328565b8101906123e3565b915f611002565b503d611090565b6110c8919350823d84116110a95761109a8183611328565b915f610fd5565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015610f91565b346102d85761110336610809565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156104ac5782915f916111d3575b501633036111c15781610bb261118e86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966132fa565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6111ec915060203d6020116110a95761109a8183611328565b5f611156565b346102d8575f3660031901126102d8576065546040516001600160a01b039091168152602090f35b346102d85760203660031901126102d857600435611237816104d7565b60018060a01b03165f52610137602052602060405f206040519061125a826112a4565b54906001600160801b03918281169081835260801c84830152611282575b5116604051908152f35b61128b81612a9b565b611278565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176112bf57604052565b611290565b6001600160401b0381116112bf57604052565b606081019081106001600160401b038211176112bf57604052565b60a081019081106001600160401b038211176112bf57604052565b608081019081106001600160401b038211176112bf57604052565b90601f801991011681019081106001600160401b038211176112bf57604052565b60405190611356826112a4565b565b6001600160401b0381116112bf57601f01601f191660200190565b92919261137f82611358565b9161138d6040519384611328565b8294818452818301116102d8578281602093845f960137010152565b6040806003193601126102d85760049081356113c4816104d7565b6024356001600160401b0381116102d857366023820112156102d8576113f39036906024818701359101611373565b916113fc6137f5565b8051926114338461142560209363439fab9160e01b858401528460248401526044830190611f13565b03601f198101865285611328565b61143b6137f5565b6114436138d5565b6001600160a01b038381168015929190879084156115fa575b841561158c575b8415611528575b50508215611492575b5050611483576100188383614a5a565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac575f926114fb575b5050155f80611473565b61151a9250803d10611521575b6115128183611328565b81019061255f565b5f806114f1565b503d611508565b855163054fd4d560e41b81529294508391839182905afa9081156104ac5760039160ff915f9161155f575b5016141591865f61146a565b61157f9150843d8611611585575b6115778183611328565b810190614a41565b5f611553565b503d61156d565b935050835163198ca60560e11b815282818981875afa9081156104ac5788917f9cf76a6c724b9ed90bd013cdce64a987a6e02c4220305b4a140a89d55a1ee023915f916115dd575b50141593611463565b6115f49150853d87116104a5576104978183611328565b5f6115d4565b5f80516020614fc5833981519152549094508490611628906001600160a01b03165b6001600160a01b031690565b149361145c565b346102d8575f3660031901126102d8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036116865760206040515f80516020614fc58339815191528152f35b60405163703e46dd60e11b8152600490fd5b346102d8575f3660031901126102d857602060405160028152f35b346102d8575f3660031901126102d8575f80516020614fc5833981519152546040516001600160a01b039091168152602090f35b346102d8575f3660031901126102d85760206104cf612477565b346102d85760203660031901126102d85760206104cf6004356124a0565b346102d8575f3660031901126102d857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104ac576020915f9161178f575b506040519015158152f35b6117a69150823d8411611521576115128183611328565b5f611784565b346102d85760203660031901126102d8576004356117c9816104d7565b6117d16138d5565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102d85760803660031901126102d85761046761184b60043561183a816104d7565b606435906044359060243590612581565b604080519384526020840192909252908201529081906060820190565b346102d8575f3660031901126102d857602061ffff60655460a01c16604051908152f35b346102d8576003196040368201126102d85760049081356001600160401b038082116102d85760a08285019383360301126102d8576024359081116102d8576118d89036908501610ef7565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102d85760405163837d444160e01b8152905f90829081838161192b8c828f01612685565b03925af180156104ac57611a49575b50611943613b03565b61194b612a65565b9081163314159182611a1a575b50509050611a09576044019160b06119708484612703565b905004801580156119f1575b6119e15761199161198b61236b565b91612758565b116119d2575060b06119a38383612703565b9050145f146119bf57610018916119b991612703565b906140b5565b610018916119cc91612703565b90613e85565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506119fc8484612703565b905060b08202141561197c565b604051634ca8886760e01b81528390fd5b611a3d9250611a37611a4194611a2f88613b8e565b923691611373565b91613c68565b1590565b805f80611958565b80610cb3611a56926112c4565b5f61193a565b346102d85760603660031901126102d857600435602435611a81604435828433612581565b9192611aad7f000000000000000000000000000000000000000000000000000000000000000082612493565b42108015611caf575b8015611ca7575b611c95577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611b0186611afc6106c76099546001600160801b031690565b61384e565b15611c0357611b3b611b20611b1586614214565b60995460801c61225d565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611b7f9190611b6e608082611328565b5190205f52609b60205260405f2090565b555f9360018311611bb8575b50505050611b998233614247565b604080519485526020850191909152830152339180606081015b0390a2005b611bf992939450611bc99088612493565b6040805133602082019081529181019390935260608301829052608095860183529094909190611b6e9082611328565b555f808080611b8b565b611c0b613b03565b611c47611c2b611c1a86614214565b609e546001600160801b031661225d565b6001600160801b03166001600160801b0319609e541617609e55565b611c7c611c61611c5685614214565b609e5460801c61225d565b6001600160801b03609e549181199060801b16911617609e55565b611c90611c8b84609f54612493565b609f55565b611b3b565b604051630e3d8e8d60e11b8152600490fd5b508215611abd565b508115611ab6565b346102d8576040806003193601126102d85760243590600435611cd9836104d7565b611ce1613b03565b8015611e8f576001600160a01b038316908115611e7e57611d01816122ad565b908115611e6d57611d1182614b47565b611d1a83614214565b60985460801c90611d2a9161225d565b611d49906001600160801b036098549181199060801b16911617609855565b611d5382336147fd565b609e54958660801c8281609f5490611d6a91612493565b98611d7487614214565b611d86916001600160801b031661328b565b611da6906001600160801b03166001600160801b0319609e541617609e55565b611daf91612493565b611db890614214565b611dd7906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611e08608082611328565b519020611e1d905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611e6433614d13565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346102d857611bb37f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611ed236610f24565b9290611edc6138d5565b6040519182916020835233956020840191612665565b5f5b838110611f035750505f910152565b8181015183820152602001611ef4565b90602091611f2c81518092818552858086019101611ef2565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611f6d5750505050505090565b9091929394958480611f8b600193603f198682030187528a51611f13565b9801930193019194939290611f5d565b346102d85760203660031901126102d8576001600160401b036004358181116102d857366023820112156102d85780600401359182116102d8573660248360051b830101116102d857610467916024611ff492016128cb565b60405191829182611f38565b906020610832928181520190611f13565b346102d8575f3660031901126102d857610467604051612030816112a4565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611f13565b346102d8575f3660031901126102d85761206e614331565b612076612978565b60015f80516020614fe583398151915255005b346102d8575f3660031901126102d8576020610e85612a65565b346102d85760203660031901126102d85760206104cf600435614360565b346102d8575f3660031901126102d85760206001600160801b0360995416604051908152f35b346102d85760203660031901126102d857610018600435612107816104d7565b61210f6138d5565b61442d565b346102d8575f3660031901126102d85760206001600160801b03609e5416604051908152f35b346102d85760203660031901126102d857600435612157816104d7565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102d85760203660031901126102d857600435612192816104d7565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b346102d8575f3660031901126102d8575f546040516001600160a01b039091168152602090f35b346102d85760203660031901126102d8576100186004356121fd816104d7565b6122056138d5565b61448f565b908160209103126102d8575190565b6040513d5f823e3d90fd5b90604051612231816112a4565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161227657565b612249565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816122c557505090565b916108329260801c90612cc3565b610201546001600160a01b039190821633036111c1576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612366576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b612373613613565b6099546001600160801b036123898183166122ad565b90609e5416019060801c01908181115f146123a2570390565b50505f90565b61016a546001600160a01b031680156123be5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102d85751610832816104d7565b906020828203126102d85781356001600160401b03928382116102d85701916060838303126102d8576040519261242e846112d7565b80358452602081013561ffff811681036102d857602085015260408101359182116102d857019080601f830112156102d85781602061246f93359101611373565b604082015290565b609d548061083257505f1990565b9060b0820180921161227657565b9190820180921161227657565b6001600160801b03609954166124b4614b05565b9081018091116122765781106124e7576124d8609f546124d2613865565b90612493565b11156124e2575f90565b5f1990565b609a90609a549182915f905b84821061250d575050508110156125075790565b505f1990565b909193808316906001818518811c8301809311612276575f8790525f80516020614fa58339815191528301546001600160a01b0316841015612554575050935b91906124f3565b90959101925061254d565b908160209103126102d85751610832816104e8565b9190820391821161227657565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906125bf81608081015b03601f198101835282611328565b5190205f52609b60205260405f2054918215612629576001600160801b0360995416906125ea614b05565b918201809211612276578391831015612617579161260792613968565b90915b8281039081116122765792565b5090612622916138e8565b909161260a565b5050505f905f905f90565b9035601e19823603018112156102d85701602081359101916001600160401b0382116102d85781360383136102d857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610832926020815282356020820152602083013560408201526126c16126b16040850185612634565b84606085015260c0840191612665565b906126f46126e96126d56060870187612634565b601f19858703810160808701529591612665565b946080810190612634565b93909282860301910152612665565b903590601e19813603018212156102d857018035906001600160401b0382116102d8576020019181360383136102d857565b634e487b7160e01b5f52601260045260245ffd5b8115612753570490565b612735565b90670de0b6b3a7640000918083029283040361227657565b90670de0b6b3a76400009182810292818404149015171561227657565b6001600160401b0381116112bf5760051b60200190565b906127ae8261278d565b6127bb6040519182611328565b82815280926127cc601f199161278d565b01905f5b8281106127dc57505050565b8060606020809385010152016127d0565b634e487b7160e01b5f52603260045260245ffd5b9082101561281857610f4e9160051b810190612703565b6127ed565b908092918237015f815290565b3d15612854573d9061283b82611358565b916128496040519384611328565b82523d5f602084013e565b606090565b6020818303126102d8578051906001600160401b0382116102d8570181601f820112156102d857805161288b81611358565b926128996040519485611328565b818452602082840101116102d8576108329160208085019101611ef2565b80518210156128185760209160051b010190565b9190916128d7836127a4565b925f5b8181106128e657505050565b5f806128f3838587612801565b6040939161290585518093819361281d565b0390305af49061291361282a565b911561293a57509060019161292882886128b7565b5261293381876128b7565b50016128da565b9060448151106102d85761297461295f60049283810151602480918301019101612859565b925162461bcd60e51b81529283928301612000565b0390fd5b47633b9aca008110612a6257604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19182156104ac575f92612a41575b506001600160ff1b038211612a2857907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db91612a0e82612fb4565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b612a5b91925060203d6020116104a5576104978183611328565b905f6129d3565b50565b60d2546001600160a01b03168061083257507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91612b31575b5060208201916001600160801b03918284511691828214612b2a5783612b1d612b18612b25958584865116612cc3565b614214565b169052614214565b169052565b5050505050565b612b4a915060203d6020116104a5576104978183611328565b5f612ae8565b90808202905f1981840990828083109203918083039214612bbf576127109082821115612bad577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612c2d57670de0b6b3a76400009082821115612bad577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906108329250612749565b9091828202915f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102d85780519160406020830151920151610832816104e8565b81835290916001600160fb1b0383116102d85760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102d85760408301526040810135612daa816104d7565b6001600160a01b031660608381019190915281013536829003601e19018112156102d85701602081359101906001600160401b0381116102d8578060051b360382136102d85760a0836080806108329601520191612d57565b9190915f838201938412911290801582169115161761227657565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612e499060048301612d7b565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ac575f915f905f95612f6f575b508415612f1c5781612e936123a8565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612f1557509060205f92600460405180958193634641257d60e01b83525af19081156104ac57612ef0925f92612ef4575b50612e03565b9190565b612f0e91925060203d6020116104a5576104978183611328565b905f612eea565b9081612f22575b50509190565b803b156102d857604051636ee3193160e11b815260048101929092525f908290602490829084905af180156104ac57612f5c575b80612f1c565b80610cb3612f69926112c4565b5f612f56565b91945050612f95915060603d606011612f9d575b612f8d8183611328565b810190612d36565b93905f612e83565b503d612f83565b600160ff1b8114612276575f0390565b8015612a6257612fc96106c760985460801c90565b5f82126130965781612fda91612493565b90612fe7610b5683614214565b612ffc6065549161ffff8360a01c1690612b50565b801561236657807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479361303a6106c76098546001600160801b031690565b80613080575050612a2390925b6001600160a01b03169161305b84846144d6565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b612a239261309092039084612cc3565b92613047565b906130a090612fa4565b6130b56106c7609e546001600160801b031690565b806130d5575b50806130c5575050565b612b18610b569161135693612574565b906131307f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91613120611c2b61311561310e8888612493565b8785612cc3565b808094039603614214565b6040519081529081906020820190565b0390a15f6130bb565b609954906001600160801b0382169182156132635760801c61317461316582613160613613565b612574565b61316e856122ad565b90614522565b90811561325c5761318482614360565b93841561325457826131d1611b20612b1861135696610b56966131cc6131b0612b188d6132499a612574565b6001600160801b03166001600160801b03196099541617609955565b612493565b6131db8187614592565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a1612b1861322d61321c88614214565b6098546001600160801b031661225d565b6001600160801b03166001600160801b03196098541617609855565b60985460801c61225d565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f908152610202602052604090205460ff16156111c157565b9190916001600160801b038080941691160191821161227657565b51906001600160401b03821682036102d857565b908160609103126102d85761246f60408051926132d6846112d7565b80516132e1816102fc565b84526132ef602082016132a6565b6020850152016132a6565b92906001600160a01b039081811615610cbf57613315613b03565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102d857604094855193631d8557d760e01b85526004945f81878183895af180156104ac57613600575b506001600160a01b0388165f9081526101376020526040902061338890612224565b906001600160801b036133a283516001600160801b031690565b16156135f0576133b182612a9b565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156104ac576135d1575b508651936303d1689d60e11b9788865260209182878061342b888c83019190602083019252565b0381845afa9687156104ac575f976135b2575b50869961345e6106a88d60018060a01b03165f52609c60205260405f2090565b881180156135a2575b6135925790836134a49261348287516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa9889156104ac575f859488946134e99c613575575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156104ac57610afd61353094613513936103f3936113569a613557575b5050614214565b6001600160a01b0388165f9081526101376020526040902061227b565b61355261353c83614360565b809761354d610b56610b4387614214565b6147fd565b614247565b8161356d92903d106104a5576104978183611328565b505f8061350c565b61358b90873d89116104a5576104978183611328565b505f6134be565b825163efda1a2760e01b81528990fd5b506135ab61236b565b8811613467565b6135ca919750833d85116104a5576104978183611328565b955f61343e565b6135e99060603d606011610c8f57610c808183611328565b505f613404565b875163673f032f60e11b81528690fd5b80610cb361360d926112c4565b5f613366565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa9081156104ac575f916136e4575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac57610832935f936136c5575b5050612493565b6136dc929350803d106104a5576104978183611328565b905f806136be565b6136fb9150833d85116104a5576104978183611328565b5f61366a565b613709614890565b6040830151613716614890565b6001600160a01b0382168015610cbf576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061376f33946020830190611f13565b0390a2602083015192613780614890565b61271061ffff8516116137d7576137cf9361379d6137c29361442d565b6065805461ffff60a01b191660a09290921b61ffff60a01b16919091179055516148d1565b6137ca614901565b61492c565b61135661495b565b604051638a81d3b360e01b8152600490fd5b61135690612205614890565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613833575b505061168657565b5f80516020614fc58339815191525416141590505f8061382b565b90613857614b05565b918201809211612276571090565b61386d613613565b6099548060801c820391821161227657816138916001600160801b038093166122ad565b90816138b7575b505081156123a257610832916138b291609e541690614522565b614b47565b91925090818111156138cd57035b905f80613898565b50505f6138c5565b5f546001600160a01b031633036111c157565b6138f0613865565b91609f54928301809311612276578083111561393a57613911920390614522565b90609e548060801c80155f146139275750508190565b6001600160801b03610832921684612cc3565b5050505f905f90565b90604051613950816112a4565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613afb575b613aee5783613ab8575f5b609a5f526001600160a01b03166139ad5f80516020614fa58339815191528601613943565b80519097906139c4906001600160a01b031661161c565b986139e96139dd6020809b01516001600160601b031690565b6001600160601b031690565b948381108015613aae575b613a9c5791600193979a95613a13613a1f939488035b838c0390614522565b80920198870391612cc3565b01970193808611801590613a92575b613a8757609a5f528290613a505f80516020614fa58339815191528701613943565b805190890151969992966001600160a01b039091169460019392613a1f9290916001600160601b0390911690613a13908803613a0a565b945050509250509190565b5081851015613a2e565b60405163e8722f8f60e01b8152600490fd5b50808b11156139f4565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613988565b505093505050505f905f90565b50841561397d565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91613b6f575b50613b5d57565b60405163e775715160e01b8152600490fd5b613b88915060203d602011611521576115128183611328565b5f613b56565b604290467f000000000000000000000000000000000000000000000000000000000000000003613c3c5760d354905b613bd4613bcd6040830183612703565b3691611373565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613c1f8161130d565b5190206040519161190160f01b8352600283015260228201522090565b613c44614b7e565b90613bbd565b60041115613c5457565b634e487b7160e01b5f52602160045260245ffd5b613c728383614c4b565b50613c7f81959295613c4a565b159384613d1b575b508315613c95575b50505090565b5f929350908291604051613ccd816125b16020820194630b135d3f60e11b998a87526024840152604060448401526064830190611f13565b51915afa90613cda61282a565b82613d0d575b82613cf0575b50505f8080613c8f565b613d059192506020808251830101910161220a565b145f80613ce6565b915060208251101591613ce0565b6001600160a01b0383811691161493505f613c87565b90613d3b8261278d565b613d486040519182611328565b8281528092613d59601f199161278d565b0190602036910137565b906030116102d85790603090565b906090116102d85760300190606090565b9060b0116102d85760900190602090565b909392938483116102d85784116102d8578101920390565b60209083611356939594956040519683613dce8995518092888089019101611ef2565b84019185830137015f83820152038085520183611328565b359060208110613df4575090565b5f199060200360031b1b1690565b916020610832938181520191612665565b9192613e3d613e2d613e4b93608086526080860190611f13565b6020958582036020870152611f13565b908382036040850152611f13565b906060818303910152602080845192838152019301915f5b828110613e71575050505090565b835185529381019392810192600101613e63565b613e8d614c85565b6060906060905f809460b0810492613ea484613d31565b965f905b858210613fc357506001600160a01b03947f00000000000000000000000000000000000000000000000000000000000000009450613f1f935060209250613eef9150612758565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af180156104ac57613fa4575b5016613f5c614cea565b813b156102d8575f8094613f866040519788968795869463c82655b760e01b865260048601613e13565b03925af180156104ac57613f975750565b80610cb3611356926112c4565b613fbc9060203d602011611521576115128183611328565b505f613f52565b614048614018614023614005613ffc7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612485565b80998989613d93565b92909a614012848d613d63565b91613dab565b9a614012838c613d71565b988b6140428661403c6140368686613d82565b90613de6565b926128b7565b52613d63565b9061405860405192839283613e02565b0390a160010183613ea8565b929461409d670de0b6b3a76400009661408f608097946140ab969b9a9b60a0895260a0890191612665565b908682036020880152611f13565b918483036040860152612665565b9460608201520152565b906140be614c85565b6140c88183613d63565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af180156104ac576141f5575b50169061415a614cea565b9161417361403661416b8489613d71565b949098613d82565b95813b156102d8575f80946141a0604051998a9687958694630cac9f3160e01b86528c8c60048801614064565b03925af19283156104ac577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936141e2575b50612a2360405192839283613e02565b80610cb36141ef926112c4565b5f6141d2565b61420d9060203d602011611521576115128183611328565b505f61414f565b6001600160801b0390818111614228571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b90614250614331565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa9384156104ac576142ef946142ea925f91614312575b508411614305575b60405163a9059cbb60e01b60208201526001600160a01b03919091166024820152604480820194909452928352606483611328565b614d93565b61135660015f80516020614fe583398151915255565b61430d614c85565b6142b5565b61432b915060203d6020116104a5576104978183611328565b5f6142ad565b5f80516020614fe5833981519152600281541461434e5760029055565b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b0382168115801561438f575b156143825750905090565b6108329260801c91612cc3565b508015614377565b6098546001600160801b03811690816143b4575050633b9aca0090565b60801c6143c18183612c3e565b91811561275357633b9aca00096143d55790565b600181018091111561083257612249565b6098546001600160801b0381169082158015614425575b1561440757505090565b60801c90614416828285612cc3565b92821561275357096143d55790565b5081156143fd565b614435613b03565b6001600160a01b0316801561447d57606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61020180546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b6144df82614214565b609854906144f76001600160801b039182841661328b565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b908082101561452f575090565b905090565b609a5490680100000000000000008210156112bf576001820180609a5582101561281857609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614fa583398151915290910155565b9190918015801561465f575b61464d576145aa614b05565b908101809111612276576001600160a01b0380821161462d576001600160601b039081851161460d579061135693946145f7614608936145e8611349565b95166001600160a01b03168552565b166001600160601b03166020830152565b614534565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561459e565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f916146d4575b50156146c257565b604051630a62fbdb60e11b8152600490fd5b6146ed915060203d602011611521576115128183611328565b5f6146ba565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156104ac5761478e936001600160401b036109c3604061476d946020975f916147de575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156104ac575f916147c5575090565b610832915060203d6020116104a5576104978183611328565b6147f7915060603d606011610c8f57610c808183611328565b5f61475e565b60018060a01b03165f52609c60205260405f20908154818103908111612276576148279255614214565b609854906001600160801b03908183160316906001600160801b03191617609855565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca006064808301919091528152611356916142ea826112f2565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156148bf57565b604051631afcd79f60e31b8152600490fd5b6148d9614890565b80156148ef57600181016148ea5750565b609d55565b6040516331278a8760e01b8152600490fd5b614909614890565b670de0b6b3a764000061491a612477565b106148ef57614927614b7e565b60d355565b614934614890565b6001600160a01b0316806149455750565b61016a80546001600160a01b0319169091179055565b614963614890565b61496b614890565b614973614890565b60015f80516020614fe58339815191525561498c613b03565b3015610cbf57633b9aca008060985460801c016149a7612477565b8111614a2f576149c1610b566149bb614397565b92614214565b6149cb81306144d6565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a361135630337f000000000000000000000000000000000000000000000000000000000000000061484a565b6040516304ffa0ff60e51b8152600490fd5b908160209103126102d8575160ff811681036102d85790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614ae4575b50614aaa57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614fc58339815191528403614acb57611356929350614e04565b604051632a87526960e21b815260048101859052602490fd5b614afe91955060203d6020116104a5576104978183611328565b935f614a84565b609a5480614b1257505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661161c565b609e54908160801c81158015614b76575b15614b635750905090565b6001600160801b03610832931691612cc3565b508015614b58565b6e5661756c7456616c696461746f727360881b6020604051614b9f816112a4565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176112bf5760405251902090565b8151919060418303614c7b57614c749250602082015190606060408401519301515f1a90614ea6565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102d8575f809160246040518094819363a3066aab60e01b83523060048401525af180156104ac57614ce15750565b611356906112c4565b604051600160f81b60208201525f60218201523060601b602c82015260208152610832816112a4565b60018060a01b0381165f5261013760205260405f209060405191614d36836112a4565b54906001600160801b03918281169081855260801c602085015215612366576106ae6106a8614d8992614d67613b03565b614d7086612a9b565b6001600160a01b03165f908152609c6020526040902090565b9151161161074b57565b5f80614dbb9260018060a01b03169360208151910182865af1614db461282a565b9083614f41565b8051908115159182614de9575b5050614dd15750565b60249060405190635274afe760e01b82526004820152fd5b614dfc925060208091830101910161255f565b155f80614dc8565b90813b15614e85575f80516020614fc583398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614e6a57612a6291614f28565b505034614e7357565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614f1d579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156104ac575f516001600160a01b03811615614f1357905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061083293602081519101845af4614f3f61282a565b915b90614f685750805115614f5657805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614f9b575b614f79575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614f7156fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220cfa80028933f319f9ed477a8ef5541e76932d9fba50bc4c2f07318749ec7eccc64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d114146102c9578063066055e0146102c457806307a2d13a146102bf5780630d392cd9146102ba5780631a7ff553146102b5578063201b9eb5146102b057806322758a4a146102ab5780632999ad3f146102a65780632cdf7401146102a15780632e2d29841461029c5780633229fa951461029757806333194c0a146102925780633a98ef391461028d578063439fab911461028857806343e82a7914610283578063469048401461027e5780634ec96b22146102795780634f1ef2861461027457806352d1902d1461026f57806354fd4d501461026a5780635c60da1b146102655780635cfc1a511461026057806360d60e6e1461025b57806372b410a814610256578063754c38881461025157806376b58b901461024c5780637fd6f15c1461024757806383d430d5146102425780638697d2c21461023d5780638ceab9aa14610238578063a49a1e7d14610233578063ac9650d81461022e578063ad3cb1cc14610229578063b0d1130214610224578063b1f0e7c71461021f578063c6e6f5921461021a578063d83ad00c14610215578063e74b981b14610210578063ee3bd5df1461020b578063f04da65b14610206578063f6a6830f14610201578063f851a440146101fc5763f98f5b920361000e576121dd565b6121b6565b612175565b61213a565b612114565b6120e7565b6120c1565b6120a3565b612089565b612056565b612011565b611f9b565b611ea0565b611cb7565b611a5c565b61188c565b611868565b611817565b6117ac565b61171f565b611701565b6116e7565b6116b3565b611698565b61162f565b6113a9565b61121a565b6111f2565b6110f5565b610f52565b610ed1565b610e97565b610e6b565b610ceb565b610cd1565b610835565b6107e0565b610578565b610524565b6104f2565b6104b1565b61030d565b6102dc565b5f9103126102d857565b5f80fd5b346102d8575f3660031901126102d857602060985460801c604051908152f35b6001600160801b038116036102d857565b346102d85760203660031901126102d85760043561032a816102fc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156104ac575f9161047d575b50335f908152610137602052604090206103a690612224565b916001600160801b036103c084516001600160801b031690565b161561046b57610414836103d661046795612a9b565b6104006103f3846103ee84516001600160801b031690565b61225d565b6001600160801b03168252565b335f9081526101376020526040902061227b565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61049f915060203d6020116104a5575b6104978183611328565b81019061220a565b5f61038d565b503d61048d565b612219565b346102d85760203660031901126102d85760206104cf6004356122ad565b604051908152f35b6001600160a01b038116036102d857565b801515036102d857565b346102d85760403660031901126102d857610018600435610512816104d7565b6024359061051f826104e8565b6122d3565b346102d8576003196020368201126102d857600435906001600160401b0382116102d85760809082360301126102d85761056361056a91600401612e1e565b9190612fb4565b61057057005b610018613139565b346102d85760603660031901126102d857600435610595816104d7565b60243590604435906105a6826104d7565b6105af33613269565b6105b7614667565b6105bf613b03565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af19485156104ac575f956107c1575b50335f9081526101376020526040902061063a90612224565b926001600160801b0361065485516001600160801b031690565b161561075d57505061066582612a9b565b61069161068461067487614214565b84516001600160801b031661328b565b6001600160801b03168352565b335f908152609c602052604090206106b3906106ae905b546122ad565b6146f3565b6106d36106c784516001600160801b031690565b6001600160801b031690565b1161074b57335f90815261013760205260409020610467957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e58939091610719919061227b565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610454565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa9182156104ac5761079f92610790915f916107a4575b50614214565b6001600160801b031690840152565b610665565b6107bb9150833d85116104a5576104978183611328565b5f61078a565b6107d9919550833d85116104a5576104978183611328565b935f610621565b346102d8575f3660031901126102d857610201546040516001600160a01b039091168152602090f35b60609060031901126102d85760043590602435610825816104d7565b90604435610832816104d7565b90565b346102d85761084336610809565b906001600160a01b0380831615610cbf5761085c613b03565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102d85760408051631d8557d760e01b815260049491905f81878183875af180156104ac57610ca6575b506001600160a01b0383165f908152610137602052604090206108cf90612224565b6001600160801b0392836108ea83516001600160801b031690565b1615610c96576108f982612a9b565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa9788156104ac575f98610c65575b50602097888101956001600160401b039182806109728a516001600160401b031690565b1614610c5557908c92918751918c838061099e6303d1689d60e11b988983528a83019190602083019252565b03818a5afa9182156104ac576109ca938e5f94610c30575b5050516001600160801b03165b1690612bca565b966109e86106a88a60018060a01b03165f52609c60205260405f2090565b928389118015610c20575b610c1057908b610a319392610a0f89516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa9182156104ac57670de0b6b3a764000094610a80948e5f95610be3575b5050610a72610a64610a7892612770565b93516001600160401b031690565b93612770565b921690612cc3565b1015610bd5578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af19081156104ac577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610bb295610b2a93610bb7575b5050610b0d6103f3610afd8c614214565b83516001600160801b031661225d565b6001600160a01b0386165f9081526101376020526040902061227b565b610b3382614360565b90610b71610b56610b4385614214565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610b7b82866147fd565b610b858389614247565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610bcd92903d106104a5576104978183611328565b505f80610aec565b835163185cfc6d60e11b8152fd5b610a78929550610c06610a729282610a6493903d106104a5576104978183611328565b959250508e610a53565b875163efda1a2760e01b81528590fd5b50610c2961236b565b89116109f3565b6109c39294509081610c4d92903d106104a5576104978183611328565b92908e6109b6565b8651630709133160e01b81528490fd5b610c8891985060603d606011610c8f575b610c808183611328565b8101906132ba565b965f61094e565b503d610c76565b825163673f032f60e11b81528790fd5b80610cb3610cb9926112c4565b806102ce565b5f6108ad565b60405163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d85760206104cf61236b565b346102d857610cf936610809565b91610d0333613269565b610d0c82613269565b610d14614331565b604092610d6e84516323b872dd60e01b602082015233602482015230604482015283606482015260648152610d48816112f2565b7f0000000000000000000000000000000000000000000000000000000000000000614d93565b610d76613b03565b6001600160a01b038316928315610e5a578215610e495782610d9d6106c760985460801c90565b0190610da7612477565b8211610e3857610e1e610b569593610df886947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610df3610deb60209c9a6143e6565b9a8b93614214565b6144d6565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020614fe58339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b346102d8575f3660031901126102d8576020610e856123a8565b6040516001600160a01b039091168152f35b346102d8575f3660031901126102d85760206040517f9cf76a6c724b9ed90bd013cdce64a987a6e02c4220305b4a140a89d55a1ee0238152f35b346102d8575f3660031901126102d85760206001600160801b0360985416604051908152f35b9181601f840112156102d8578235916001600160401b0383116102d857602083818601950101116102d857565b60206003198201126102d857600435906001600160401b0382116102d857610f4e91600401610ef7565b9091565b346102d857610f6036610f24565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1680156110e1575b6110cf5768ffffffffffffffffff19166801000000000000000217905560405163e7f6f22560e01b8152906020908183600481335afa9283156104ac575f936110b0575b50604051636f4fa30f60e01b8152938285600481335afa9081156104ac5761101d95611018945f9361107d575b505061101191928101906123f8565b9083613701565b6137e9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600281527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b611011935090816110a292903d106110a9575b61109a8183611328565b8101906123e3565b915f611002565b503d611090565b6110c8919350823d84116110a95761109a8183611328565b915f610fd5565b60405163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015610f91565b346102d85761110336610809565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156104ac5782915f916111d3575b501633036111c15781610bb261118e86867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd3966132fa565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b6111ec915060203d6020116110a95761109a8183611328565b5f611156565b346102d8575f3660031901126102d8576065546040516001600160a01b039091168152602090f35b346102d85760203660031901126102d857600435611237816104d7565b60018060a01b03165f52610137602052602060405f206040519061125a826112a4565b54906001600160801b03918281169081835260801c84830152611282575b5116604051908152f35b61128b81612a9b565b611278565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176112bf57604052565b611290565b6001600160401b0381116112bf57604052565b606081019081106001600160401b038211176112bf57604052565b60a081019081106001600160401b038211176112bf57604052565b608081019081106001600160401b038211176112bf57604052565b90601f801991011681019081106001600160401b038211176112bf57604052565b60405190611356826112a4565b565b6001600160401b0381116112bf57601f01601f191660200190565b92919261137f82611358565b9161138d6040519384611328565b8294818452818301116102d8578281602093845f960137010152565b6040806003193601126102d85760049081356113c4816104d7565b6024356001600160401b0381116102d857366023820112156102d8576113f39036906024818701359101611373565b916113fc6137f5565b8051926114338461142560209363439fab9160e01b858401528460248401526044830190611f13565b03601f198101865285611328565b61143b6137f5565b6114436138d5565b6001600160a01b038381168015929190879084156115fa575b841561158c575b8415611528575b50508215611492575b5050611483576100188383614a5a565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac575f926114fb575b5050155f80611473565b61151a9250803d10611521575b6115128183611328565b81019061255f565b5f806114f1565b503d611508565b855163054fd4d560e41b81529294508391839182905afa9081156104ac5760039160ff915f9161155f575b5016141591865f61146a565b61157f9150843d8611611585575b6115778183611328565b810190614a41565b5f611553565b503d61156d565b935050835163198ca60560e11b815282818981875afa9081156104ac5788917f9cf76a6c724b9ed90bd013cdce64a987a6e02c4220305b4a140a89d55a1ee023915f916115dd575b50141593611463565b6115f49150853d87116104a5576104978183611328565b5f6115d4565b5f80516020614fc5833981519152549094508490611628906001600160a01b03165b6001600160a01b031690565b149361145c565b346102d8575f3660031901126102d8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036116865760206040515f80516020614fc58339815191528152f35b60405163703e46dd60e11b8152600490fd5b346102d8575f3660031901126102d857602060405160028152f35b346102d8575f3660031901126102d8575f80516020614fc5833981519152546040516001600160a01b039091168152602090f35b346102d8575f3660031901126102d85760206104cf612477565b346102d85760203660031901126102d85760206104cf6004356124a0565b346102d8575f3660031901126102d857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104ac576020915f9161178f575b506040519015158152f35b6117a69150823d8411611521576115128183611328565b5f611784565b346102d85760203660031901126102d8576004356117c9816104d7565b6117d16138d5565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b346102d85760803660031901126102d85761046761184b60043561183a816104d7565b606435906044359060243590612581565b604080519384526020840192909252908201529081906060820190565b346102d8575f3660031901126102d857602061ffff60655460a01c16604051908152f35b346102d8576003196040368201126102d85760049081356001600160401b038082116102d85760a08285019383360301126102d8576024359081116102d8576118d89036908501610ef7565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102d85760405163837d444160e01b8152905f90829081838161192b8c828f01612685565b03925af180156104ac57611a49575b50611943613b03565b61194b612a65565b9081163314159182611a1a575b50509050611a09576044019160b06119708484612703565b905004801580156119f1575b6119e15761199161198b61236b565b91612758565b116119d2575060b06119a38383612703565b9050145f146119bf57610018916119b991612703565b906140b5565b610018916119cc91612703565b90613e85565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b506119fc8484612703565b905060b08202141561197c565b604051634ca8886760e01b81528390fd5b611a3d9250611a37611a4194611a2f88613b8e565b923691611373565b91613c68565b1590565b805f80611958565b80610cb3611a56926112c4565b5f61193a565b346102d85760603660031901126102d857600435602435611a81604435828433612581565b9192611aad7f000000000000000000000000000000000000000000000000000000000000000082612493565b42108015611caf575b8015611ca7575b611c95577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611b0186611afc6106c76099546001600160801b031690565b61384e565b15611c0357611b3b611b20611b1586614214565b60995460801c61225d565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611b7f9190611b6e608082611328565b5190205f52609b60205260405f2090565b555f9360018311611bb8575b50505050611b998233614247565b604080519485526020850191909152830152339180606081015b0390a2005b611bf992939450611bc99088612493565b6040805133602082019081529181019390935260608301829052608095860183529094909190611b6e9082611328565b555f808080611b8b565b611c0b613b03565b611c47611c2b611c1a86614214565b609e546001600160801b031661225d565b6001600160801b03166001600160801b0319609e541617609e55565b611c7c611c61611c5685614214565b609e5460801c61225d565b6001600160801b03609e549181199060801b16911617609e55565b611c90611c8b84609f54612493565b609f55565b611b3b565b604051630e3d8e8d60e11b8152600490fd5b508215611abd565b508115611ab6565b346102d8576040806003193601126102d85760243590600435611cd9836104d7565b611ce1613b03565b8015611e8f576001600160a01b038316908115611e7e57611d01816122ad565b908115611e6d57611d1182614b47565b611d1a83614214565b60985460801c90611d2a9161225d565b611d49906001600160801b036098549181199060801b16911617609855565b611d5382336147fd565b609e54958660801c8281609f5490611d6a91612493565b98611d7487614214565b611d86916001600160801b031661328b565b611da6906001600160801b03166001600160801b0319609e541617609e55565b611daf91612493565b611db890614214565b611dd7906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611e08608082611328565b519020611e1d905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611e6433614d13565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b346102d857611bb37f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611ed236610f24565b9290611edc6138d5565b6040519182916020835233956020840191612665565b5f5b838110611f035750505f910152565b8181015183820152602001611ef4565b90602091611f2c81518092818552858086019101611ef2565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611f6d5750505050505090565b9091929394958480611f8b600193603f198682030187528a51611f13565b9801930193019194939290611f5d565b346102d85760203660031901126102d8576001600160401b036004358181116102d857366023820112156102d85780600401359182116102d8573660248360051b830101116102d857610467916024611ff492016128cb565b60405191829182611f38565b906020610832928181520190611f13565b346102d8575f3660031901126102d857610467604051612030816112a4565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611f13565b346102d8575f3660031901126102d85761206e614331565b612076612978565b60015f80516020614fe583398151915255005b346102d8575f3660031901126102d8576020610e85612a65565b346102d85760203660031901126102d85760206104cf600435614360565b346102d8575f3660031901126102d85760206001600160801b0360995416604051908152f35b346102d85760203660031901126102d857610018600435612107816104d7565b61210f6138d5565b61442d565b346102d8575f3660031901126102d85760206001600160801b03609e5416604051908152f35b346102d85760203660031901126102d857600435612157816104d7565b60018060a01b03165f52609c602052602060405f2054604051908152f35b346102d85760203660031901126102d857600435612192816104d7565b60018060a01b03165f52610202602052602060ff60405f2054166040519015158152f35b346102d8575f3660031901126102d8575f546040516001600160a01b039091168152602090f35b346102d85760203660031901126102d8576100186004356121fd816104d7565b6122056138d5565b61448f565b908160209103126102d8575190565b6040513d5f823e3d90fd5b90604051612231816112a4565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161227657565b612249565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816122c557505090565b916108329260801c90612cc3565b610201546001600160a01b039190821633036111c1576001600160a01b0381165f90815261020260205260409020549215159260ff1615158314612366576001600160a01b0381165f9081526102026020526040902060ff1981541660ff851617905560405192835216907fd9c6c3eabe38e3b9a606a66358d8f225489216a59eeba66facefb7d91663526660203392a3565b505050565b612373613613565b6099546001600160801b036123898183166122ad565b90609e5416019060801c01908181115f146123a2570390565b50505f90565b61016a546001600160a01b031680156123be5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102d85751610832816104d7565b906020828203126102d85781356001600160401b03928382116102d85701916060838303126102d8576040519261242e846112d7565b80358452602081013561ffff811681036102d857602085015260408101359182116102d857019080601f830112156102d85781602061246f93359101611373565b604082015290565b609d548061083257505f1990565b9060b0820180921161227657565b9190820180921161227657565b6001600160801b03609954166124b4614b05565b9081018091116122765781106124e7576124d8609f546124d2613865565b90612493565b11156124e2575f90565b5f1990565b609a90609a549182915f905b84821061250d575050508110156125075790565b505f1990565b909193808316906001818518811c8301809311612276575f8790525f80516020614fa58339815191528301546001600160a01b0316841015612554575050935b91906124f3565b90959101925061254d565b908160209103126102d85751610832816104e8565b9190820391821161227657565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906125bf81608081015b03601f198101835282611328565b5190205f52609b60205260405f2054918215612629576001600160801b0360995416906125ea614b05565b918201809211612276578391831015612617579161260792613968565b90915b8281039081116122765792565b5090612622916138e8565b909161260a565b5050505f905f905f90565b9035601e19823603018112156102d85701602081359101916001600160401b0382116102d85781360383136102d857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610832926020815282356020820152602083013560408201526126c16126b16040850185612634565b84606085015260c0840191612665565b906126f46126e96126d56060870187612634565b601f19858703810160808701529591612665565b946080810190612634565b93909282860301910152612665565b903590601e19813603018212156102d857018035906001600160401b0382116102d8576020019181360383136102d857565b634e487b7160e01b5f52601260045260245ffd5b8115612753570490565b612735565b90670de0b6b3a7640000918083029283040361227657565b90670de0b6b3a76400009182810292818404149015171561227657565b6001600160401b0381116112bf5760051b60200190565b906127ae8261278d565b6127bb6040519182611328565b82815280926127cc601f199161278d565b01905f5b8281106127dc57505050565b8060606020809385010152016127d0565b634e487b7160e01b5f52603260045260245ffd5b9082101561281857610f4e9160051b810190612703565b6127ed565b908092918237015f815290565b3d15612854573d9061283b82611358565b916128496040519384611328565b82523d5f602084013e565b606090565b6020818303126102d8578051906001600160401b0382116102d8570181601f820112156102d857805161288b81611358565b926128996040519485611328565b818452602082840101116102d8576108329160208085019101611ef2565b80518210156128185760209160051b010190565b9190916128d7836127a4565b925f5b8181106128e657505050565b5f806128f3838587612801565b6040939161290585518093819361281d565b0390305af49061291361282a565b911561293a57509060019161292882886128b7565b5261293381876128b7565b50016128da565b9060448151106102d85761297461295f60049283810151602480918301019101612859565b925162461bcd60e51b81529283928301612000565b0390fd5b47633b9aca008110612a6257604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19182156104ac575f92612a41575b506001600160ff1b038211612a2857907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db91612a0e82612fb4565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b612a5b91925060203d6020116104a5576104978183611328565b905f6129d3565b50565b60d2546001600160a01b03168061083257507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91612b31575b5060208201916001600160801b03918284511691828214612b2a5783612b1d612b18612b25958584865116612cc3565b614214565b169052614214565b169052565b5050505050565b612b4a915060203d6020116104a5576104978183611328565b5f612ae8565b90808202905f1981840990828083109203918083039214612bbf576127109082821115612bad577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612c2d57670de0b6b3a76400009082821115612bad577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906108329250612749565b9091828202915f1984820993838086109503948086039514612cb65784831115612bad57829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102d85780519160406020830151920151610832816104e8565b81835290916001600160fb1b0383116102d85760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102d85760408301526040810135612daa816104d7565b6001600160a01b031660608381019190915281013536829003601e19018112156102d85701602081359101906001600160401b0381116102d8578060051b360382136102d85760a0836080806108329601520191612d57565b9190915f838201938412911290801582169115161761227657565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612e499060048301612d7b565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af19283156104ac575f915f905f95612f6f575b508415612f1c5781612e936123a8565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612f1557509060205f92600460405180958193634641257d60e01b83525af19081156104ac57612ef0925f92612ef4575b50612e03565b9190565b612f0e91925060203d6020116104a5576104978183611328565b905f612eea565b9081612f22575b50509190565b803b156102d857604051636ee3193160e11b815260048101929092525f908290602490829084905af180156104ac57612f5c575b80612f1c565b80610cb3612f69926112c4565b5f612f56565b91945050612f95915060603d606011612f9d575b612f8d8183611328565b810190612d36565b93905f612e83565b503d612f83565b600160ff1b8114612276575f0390565b8015612a6257612fc96106c760985460801c90565b5f82126130965781612fda91612493565b90612fe7610b5683614214565b612ffc6065549161ffff8360a01c1690612b50565b801561236657807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc353186865479361303a6106c76098546001600160801b031690565b80613080575050612a2390925b6001600160a01b03169161305b84846144d6565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b612a239261309092039084612cc3565b92613047565b906130a090612fa4565b6130b56106c7609e546001600160801b031690565b806130d5575b50806130c5575050565b612b18610b569161135693612574565b906131307f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91613120611c2b61311561310e8888612493565b8785612cc3565b808094039603614214565b6040519081529081906020820190565b0390a15f6130bb565b609954906001600160801b0382169182156132635760801c61317461316582613160613613565b612574565b61316e856122ad565b90614522565b90811561325c5761318482614360565b93841561325457826131d1611b20612b1861135696610b56966131cc6131b0612b188d6132499a612574565b6001600160801b03166001600160801b03196099541617609955565b612493565b6131db8187614592565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a1612b1861322d61321c88614214565b6098546001600160801b031661225d565b6001600160801b03166001600160801b03196098541617609855565b60985460801c61225d565b505f93505050565b505f925050565b505f9150565b6001600160a01b03165f908152610202602052604090205460ff16156111c157565b9190916001600160801b038080941691160191821161227657565b51906001600160401b03821682036102d857565b908160609103126102d85761246f60408051926132d6846112d7565b80516132e1816102fc565b84526132ef602082016132a6565b6020850152016132a6565b92906001600160a01b039081811615610cbf57613315613b03565b817f00000000000000000000000000000000000000000000000000000000000000001690813b156102d857604094855193631d8557d760e01b85526004945f81878183895af180156104ac57613600575b506001600160a01b0388165f9081526101376020526040902061338890612224565b906001600160801b036133a283516001600160801b031690565b16156135f0576133b182612a9b565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa80156104ac576135d1575b508651936303d1689d60e11b9788865260209182878061342b888c83019190602083019252565b0381845afa9687156104ac575f976135b2575b50869961345e6106a88d60018060a01b03165f52609c60205260405f2090565b881180156135a2575b6135925790836134a49261348287516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa9889156104ac575f859488946134e99c613575575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af19586156104ac57610afd61353094613513936103f3936113569a613557575b5050614214565b6001600160a01b0388165f9081526101376020526040902061227b565b61355261353c83614360565b809761354d610b56610b4387614214565b6147fd565b614247565b8161356d92903d106104a5576104978183611328565b505f8061350c565b61358b90873d89116104a5576104978183611328565b505f6134be565b825163efda1a2760e01b81528990fd5b506135ab61236b565b8811613467565b6135ca919750833d85116104a5576104978183611328565b955f61343e565b6135e99060603d606011610c8f57610c808183611328565b505f613404565b875163673f032f60e11b81528690fd5b80610cb361360d926112c4565b5f613366565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa9081156104ac575f916136e4575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104ac57610832935f936136c5575b5050612493565b6136dc929350803d106104a5576104978183611328565b905f806136be565b6136fb9150833d85116104a5576104978183611328565b5f61366a565b613709614890565b6040830151613716614890565b6001600160a01b0382168015610cbf576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061376f33946020830190611f13565b0390a2602083015192613780614890565b61271061ffff8516116137d7576137cf9361379d6137c29361442d565b6065805461ffff60a01b191660a09290921b61ffff60a01b16919091179055516148d1565b6137ca614901565b61492c565b61135661495b565b604051638a81d3b360e01b8152600490fd5b61135690612205614890565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114918215613833575b505061168657565b5f80516020614fc58339815191525416141590505f8061382b565b90613857614b05565b918201809211612276571090565b61386d613613565b6099548060801c820391821161227657816138916001600160801b038093166122ad565b90816138b7575b505081156123a257610832916138b291609e541690614522565b614b47565b91925090818111156138cd57035b905f80613898565b50505f6138c5565b5f546001600160a01b031633036111c157565b6138f0613865565b91609f54928301809311612276578083111561393a57613911920390614522565b90609e548060801c80155f146139275750508190565b6001600160801b03610832921684612cc3565b5050505f905f90565b90604051613950816112a4565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613afb575b613aee5783613ab8575f5b609a5f526001600160a01b03166139ad5f80516020614fa58339815191528601613943565b80519097906139c4906001600160a01b031661161c565b986139e96139dd6020809b01516001600160601b031690565b6001600160601b031690565b948381108015613aae575b613a9c5791600193979a95613a13613a1f939488035b838c0390614522565b80920198870391612cc3565b01970193808611801590613a92575b613a8757609a5f528290613a505f80516020614fa58339815191528701613943565b805190890151969992966001600160a01b039091169460019392613a1f9290916001600160601b0390911690613a13908803613a0a565b945050509250509190565b5081851015613a2e565b60405163e8722f8f60e01b8152600490fd5b50808b11156139f4565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613988565b505093505050505f905f90565b50841561397d565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f91613b6f575b50613b5d57565b60405163e775715160e01b8152600490fd5b613b88915060203d602011611521576115128183611328565b5f613b56565b604290467f000000000000000000000000000000000000000000000000000000000000000003613c3c5760d354905b613bd4613bcd6040830183612703565b3691611373565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613c1f8161130d565b5190206040519161190160f01b8352600283015260228201522090565b613c44614b7e565b90613bbd565b60041115613c5457565b634e487b7160e01b5f52602160045260245ffd5b613c728383614c4b565b50613c7f81959295613c4a565b159384613d1b575b508315613c95575b50505090565b5f929350908291604051613ccd816125b16020820194630b135d3f60e11b998a87526024840152604060448401526064830190611f13565b51915afa90613cda61282a565b82613d0d575b82613cf0575b50505f8080613c8f565b613d059192506020808251830101910161220a565b145f80613ce6565b915060208251101591613ce0565b6001600160a01b0383811691161493505f613c87565b90613d3b8261278d565b613d486040519182611328565b8281528092613d59601f199161278d565b0190602036910137565b906030116102d85790603090565b906090116102d85760300190606090565b9060b0116102d85760900190602090565b909392938483116102d85784116102d8578101920390565b60209083611356939594956040519683613dce8995518092888089019101611ef2565b84019185830137015f83820152038085520183611328565b359060208110613df4575090565b5f199060200360031b1b1690565b916020610832938181520191612665565b9192613e3d613e2d613e4b93608086526080860190611f13565b6020958582036020870152611f13565b908382036040850152611f13565b906060818303910152602080845192838152019301915f5b828110613e71575050505090565b835185529381019392810192600101613e63565b613e8d614c85565b6060906060905f809460b0810492613ea484613d31565b965f905b858210613fc357506001600160a01b03947f00000000000000000000000000000000000000000000000000000000000000009450613f1f935060209250613eef9150612758565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af180156104ac57613fa4575b5016613f5c614cea565b813b156102d8575f8094613f866040519788968795869463c82655b760e01b865260048601613e13565b03925af180156104ac57613f975750565b80610cb3611356926112c4565b613fbc9060203d602011611521576115128183611328565b505f613f52565b614048614018614023614005613ffc7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c612485565b80998989613d93565b92909a614012848d613d63565b91613dab565b9a614012838c613d71565b988b6140428661403c6140368686613d82565b90613de6565b926128b7565b52613d63565b9061405860405192839283613e02565b0390a160010183613ea8565b929461409d670de0b6b3a76400009661408f608097946140ab969b9a9b60a0895260a0890191612665565b908682036020880152611f13565b918483036040860152612665565b9460608201520152565b906140be614c85565b6140c88183613d63565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af180156104ac576141f5575b50169061415a614cea565b9161417361403661416b8489613d71565b949098613d82565b95813b156102d8575f80946141a0604051998a9687958694630cac9f3160e01b86528c8c60048801614064565b03925af19283156104ac577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1936141e2575b50612a2360405192839283613e02565b80610cb36141ef926112c4565b5f6141d2565b61420d9060203d602011611521576115128183611328565b505f61414f565b6001600160801b0390818111614228571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b90614250614331565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa9384156104ac576142ef946142ea925f91614312575b508411614305575b60405163a9059cbb60e01b60208201526001600160a01b03919091166024820152604480820194909452928352606483611328565b614d93565b61135660015f80516020614fe583398151915255565b61430d614c85565b6142b5565b61432b915060203d6020116104a5576104978183611328565b5f6142ad565b5f80516020614fe5833981519152600281541461434e5760029055565b604051633ee5aeb560e01b8152600490fd5b609854906001600160801b0382168115801561438f575b156143825750905090565b6108329260801c91612cc3565b508015614377565b6098546001600160801b03811690816143b4575050633b9aca0090565b60801c6143c18183612c3e565b91811561275357633b9aca00096143d55790565b600181018091111561083257612249565b6098546001600160801b0381169082158015614425575b1561440757505090565b60801c90614416828285612cc3565b92821561275357096143d55790565b5081156143fd565b614435613b03565b6001600160a01b0316801561447d57606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b61020180546001600160a01b0319166001600160a01b03929092169182179055337fda2bcad4d57ac529886ff995d07bce191c08b5424c8f5824de6c73f90cc623d45f80a3565b6144df82614214565b609854906144f76001600160801b039182841661328b565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b908082101561452f575090565b905090565b609a5490680100000000000000008210156112bf576001820180609a5582101561281857609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614fa583398151915290910155565b9190918015801561465f575b61464d576145aa614b05565b908101809111612276576001600160a01b0380821161462d576001600160601b039081851161460d579061135693946145f7614608936145e8611349565b95166001600160a01b03168552565b166001600160601b03166020830152565b614534565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561459e565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104ac575f916146d4575b50156146c257565b604051630a62fbdb60e11b8152600490fd5b6146ed915060203d602011611521576115128183611328565b5f6146ba565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa80156104ac5761478e936001600160401b036109c3604061476d946020975f916147de575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156104ac575f916147c5575090565b610832915060203d6020116104a5576104978183611328565b6147f7915060603d606011610c8f57610c808183611328565b5f61475e565b60018060a01b03165f52609c60205260405f20908154818103908111612276576148279255614214565b609854906001600160801b03908183160316906001600160801b03191617609855565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca006064808301919091528152611356916142ea826112f2565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156148bf57565b604051631afcd79f60e31b8152600490fd5b6148d9614890565b80156148ef57600181016148ea5750565b609d55565b6040516331278a8760e01b8152600490fd5b614909614890565b670de0b6b3a764000061491a612477565b106148ef57614927614b7e565b60d355565b614934614890565b6001600160a01b0316806149455750565b61016a80546001600160a01b0319169091179055565b614963614890565b61496b614890565b614973614890565b60015f80516020614fe58339815191525561498c613b03565b3015610cbf57633b9aca008060985460801c016149a7612477565b8111614a2f576149c1610b566149bb614397565b92614214565b6149cb81306144d6565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a361135630337f000000000000000000000000000000000000000000000000000000000000000061484a565b6040516304ffa0ff60e51b8152600490fd5b908160209103126102d8575160ff811681036102d85790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f9481614ae4575b50614aaa57604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614fc58339815191528403614acb57611356929350614e04565b604051632a87526960e21b815260048101859052602490fd5b614afe91955060203d6020116104a5576104978183611328565b935f614a84565b609a5480614b1257505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b031661161c565b609e54908160801c81158015614b76575b15614b635750905090565b6001600160801b03610832931691612cc3565b508015614b58565b6e5661756c7456616c696461746f727360881b6020604051614b9f816112a4565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176112bf5760405251902090565b8151919060418303614c7b57614c749250602082015190606060408401519301515f1a90614ea6565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156102d8575f809160246040518094819363a3066aab60e01b83523060048401525af180156104ac57614ce15750565b611356906112c4565b604051600160f81b60208201525f60218201523060601b602c82015260208152610832816112a4565b60018060a01b0381165f5261013760205260405f209060405191614d36836112a4565b54906001600160801b03918281169081855260801c602085015215612366576106ae6106a8614d8992614d67613b03565b614d7086612a9b565b6001600160a01b03165f908152609c6020526040902090565b9151161161074b57565b5f80614dbb9260018060a01b03169360208151910182865af1614db461282a565b9083614f41565b8051908115159182614de9575b5050614dd15750565b60249060405190635274afe760e01b82526004820152fd5b614dfc925060208091830101910161255f565b155f80614dc8565b90813b15614e85575f80516020614fc583398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614e6a57612a6291614f28565b505034614e7357565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614f1d579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156104ac575f516001600160a01b03811615614f1357905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061083293602081519101845af4614f3f61282a565b915b90614f685750805115614f5657805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614f9b575b614f79575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614f7156fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220cfa80028933f319f9ed477a8ef5541e76932d9fba50bc4c2f07318749ec7eccc64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoValidatorsRegistry.json b/test/shared/artifacts/GnoValidatorsRegistry.json deleted file mode 100644 index e3d8713b..00000000 --- a/test/shared/artifacts/GnoValidatorsRegistry.json +++ /dev/null @@ -1,395 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "amount", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "index", - "type": "bytes" - } - ], - "name": "DepositEvent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "pubkeys", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "bytes32[]", - "name": "deposit_data_roots", - "type": "bytes32[]" - } - ], - "name": "batchDeposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - } - ], - "name": "claimTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_address", - "type": "address" - } - ], - "name": "claimWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_addresses", - "type": "address[]" - } - ], - "name": "claimWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "withdrawal_credentials", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "deposit_data_root", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "stake_amount", - "type": "uint256" - } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64[]", - "name": "_amounts", - "type": "uint64[]" - }, - { - "internalType": "address[]", - "name": "_addresses", - "type": "address[]" - } - ], - "name": "executeSystemWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint64[]", - "name": "_amounts", - "type": "uint64[]" - }, - { - "internalType": "address[]", - "name": "_addresses", - "type": "address[]" - } - ], - "name": "executeSystemWithdrawals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "get_deposit_count", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "get_deposit_root", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "stake_amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "onTokenTransfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "stake_token", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IUnwrapper", - "name": "_unwrapper", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "_token", - "type": "address" - } - ], - "name": "unwrapTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "validator_withdrawal_credentials", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "withdrawableAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x60a06040523480156200001157600080fd5b506040516200379838038062003798833981016040819052620000349162000050565b6000805460ff191690556001600160a01b031660805262000082565b6000602082840312156200006357600080fd5b81516001600160a01b03811681146200007b57600080fd5b9392505050565b6080516136d0620000c86000396000818161020401528181610415015281816105d80152818161078101528181610b2f01528181610b78015261158d01526136d06000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806369ffa08a116100b2578063a4c0ed3611610081578063be7ab51b11610066578063be7ab51b146102b2578063c5f2892f146102d2578063c82655b7146102da57600080fd5b8063a4c0ed361461028c578063bb30b8fd1461029f57600080fd5b806369ffa08a1461024b57806379d0c0bc1461025e5780638456cb5914610271578063a3066aab1461027957600080fd5b80633f4ba83a116101095780635c975abb116100ee5780635c975abb146101df578063621fd130146101ea578063640415bf146101ff57600080fd5b80633f4ba83a146101c45780634694bd1e146101cc57600080fd5b806301ffc9a71461013b5780630cac9f311461016357806324db4c4614610178578063319ebe9c146101b1575b600080fd5b61014e610149366004612b43565b6102ed565b60405190151581526020015b60405180910390f35b610176610171366004612c66565b6103d2565b005b6101a3610186366004612d00565b805160208183018101805160428252928201919093012091525481565b60405190815260200161015a565b6101766101bf366004612d81565b6104bb565b6101766104cf565b6101766101da366004612e12565b610532565b60005460ff1661014e565b6101f26106fd565b60405161015a9190612ec1565b6102267f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161015a565b610176610259366004612e12565b61070f565b61017661026c366004612ed4565b610857565b610176610a75565b610176610287366004612f4e565b610ad6565b61014e61029a366004612fad565b610b56565b6101766102ad366004612ffd565b611010565b6101a36102c0366004612f4e565b60436020526000908152604090205481565b6101a3611055565b6101766102e836600461303f565b611284565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061038057507fffffffff0000000000000000000000000000000000000000000000000000000082167fab41c72e00000000000000000000000000000000000000000000000000000000145b806103cc57507fffffffff0000000000000000000000000000000000000000000000000000000082167fa4c0ed3600000000000000000000000000000000000000000000000000000000145b92915050565b6103da6117d5565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b15801561046e57600080fd5b505af1158015610482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a69190613103565b506104b48585858585611842565b5050505050565b6104c9600085858585610857565b50505050565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461052857600080fd5b6105306122c5565b565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461058b57600080fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff808416916339f47693917f000000000000000000000000000000000000000000000000000000000000000091908516906370a082319060240160206040518083038186803b15801561061d57600080fd5b505afa158015610631573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106559190613125565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381600087803b1580156106c057600080fd5b505af11580156106d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f89190613125565b505050565b606061070a604154612342565b905090565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461076857600080fd5b8173ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161415610849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f4465706f736974436f6e74726163743a206e6f7420616c6c6f77656420746f2060448201527f636c61696d206465706f73697420746f6b656e0000000000000000000000000060648201526084015b60405180910390fd5b61085382826125b6565b5050565b3373fffffffffffffffffffffffffffffffffffffffe14806108c557507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f546869732066756e6374696f6e2073686f756c642062652063616c6c6564206f60448201527f6e6c792062792053595354454d5f5749544844524157414c5f4558454355544f60648201527f52206f72205f61646d696e282900000000000000000000000000000000000000608482015260a401610840565b8281146109865761098661313e565b60005b83811015610a6d57600060208686848181106109a7576109a761316d565b90506020020160208101906109bc919061319c565b6109d49067ffffffffffffffff16633b9aca006131f5565b6109de9190613261565b905080604360008686868181106109f7576109f761316d565b9050602002016020810190610a0c9190612f4e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610a559190613275565b90915550610a66915082905061328d565b9050610989565b505050505050565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ace57600080fd5b6105306125e4565b73ffffffffffffffffffffffffffffffffffffffff811660009081526043602052604090205480156108535773ffffffffffffffffffffffffffffffffffffffff808316600090815260436020526040812055610853907f000000000000000000000000000000000000000000000000000000000000000016838361263f565b6000610b606117d5565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610c24576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4465706f736974436f6e74726163743a206e6f742061206465706f736974207460448201527f6f6b656e000000000000000000000000000000000000000000000000000000006064820152608401610840565b610c2f60b0836132c6565b602014610cbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4465706f736974436f6e74726163743a20696e636f7272656374206465706f7360448201527f69742064617461206c656e6774680000000000000000000000000000000000006064820152608401610840565b6000610ccb60b084613261565b905060008111610d5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f42617463684465706f7369743a20596f752073686f756c64206465706f73697460448201527f206174206c65617374206f6e652076616c696461746f720000000000000000006064820152608401610840565b846001821115610ea3576080821115610df8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f42617463684465706f7369743a20596f752063616e206465706f736974206d6160448201527f78203132382076616c696461746f727320617420612074696d650000000000006064820152608401610840565b610e0a82670de0b6b3a76400006131f5565b8614610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f42617463684465706f7369743a206261746368206465706f736974732072657160448201527f75697265203120474e4f206465706f73697420616d6f756e74000000000000006064820152608401610840565b50670de0b6b3a76400005b6000610eb260208287896132da565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293506020925050505b85811015610fff576000878288610f05826030613275565b92610f12939291906132da565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394508b92508a9150610f589050856030613275565b90610f64866090613275565b92610f71939291906132da565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394508c92508b9150610fb79050866090613275565b90610fc38760b0613275565b92610fd0939291906132da565b610fd991613304565b9050610fe8838684848a611842565b50505060b081610ff89190613275565b9050610eed565b50600193505050505b949350505050565b60005b818110156106f8576110458383838181106110305761103061316d565b90506020020160208101906102879190612f4e565b61104e8161328d565b9050611013565b6041546000908190815b60208110156111e257816001166001141561111e576002602182602081106110895761108961316d565b01546040805160208101929092528101859052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526110d791613340565b602060405180830381855afa1580156110f4573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906111179190613125565b92506111c3565b600283600183602081106111345761113461316d565b0154604080516020810193909352820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261118091613340565b602060405180830381855afa15801561119d573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906111c09190613125565b92505b6111ce600283613261565b9150806111da8161328d565b91505061105f565b506002826111f1604154612342565b60405161120592919060009060200161335c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261123d91613340565b602060405180830381855afa15801561125a573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061127d9190613125565b9250505090565b61128c6117d5565b808061131a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f42617463684465706f7369743a20596f752073686f756c64206465706f73697460448201527f206174206c65617374206f6e652076616c696461746f720000000000000000006064820152608401610840565b60808111156113ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f42617463684465706f7369743a20596f752063616e206465706f736974206d6160448201527f78203132382076616c696461746f727320617420612074696d650000000000006064820152608401610840565b6113b68160306131f5565b8814611444576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f42617463684465706f7369743a205075626b657920636f756e7420646f6e277460448201527f206d6174636800000000000000000000000000000000000000000000000000006064820152608401610840565b61144f8160606131f5565b84146114dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f42617463684465706f7369743a205369676e61747572657320636f756e74206460448201527f6f6e2774206d61746368000000000000000000000000000000000000000000006064820152608401610840565b6020861461156d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f42617463684465706f7369743a205769746864726177616c2043726564656e7460448201527f69616c7320636f756e7420646f6e2774206d61746368000000000000000000006064820152608401610840565b670de0b6b3a764000073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166323b872dd33306115be86866131f5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401602060405180830381600087803b15801561163257600080fd5b505af1158015611646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166a9190613103565b5060005b828110156117c85760008b8b6116858460306131f5565b90611691856001613275565b61169c9060306131f5565b926116a9939291906132da565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394508b92508a91506116ef90508560606131f5565b906116fb866001613275565b6117069060606131f5565b92611713939291906132da565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506117b5828c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508692508c91508b9050888181106117a8576117a861316d565b9050602002013588611842565b5050806117c19061328d565b905061166e565b5050505050505050505050565b60005460ff1615610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610840565b61184d8160206131f5565b905084516030146118e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4465706f736974436f6e74726163743a20696e76616c6964207075626b65792060448201527f6c656e67746800000000000000000000000000000000000000000000000000006064820152608401610840565b8351602014611971576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f4465706f736974436f6e74726163743a20696e76616c6964207769746864726160448201527f77616c5f63726564656e7469616c73206c656e677468000000000000000000006064820152608401610840565b8251606014611a02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4465706f736974436f6e74726163743a20696e76616c6964207369676e61747560448201527f7265206c656e67746800000000000000000000000000000000000000000000006064820152608401610840565b670de0b6b3a7640000811015611a9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4465706f736974436f6e74726163743a206465706f7369742076616c7565207460448201527f6f6f206c6f7700000000000000000000000000000000000000000000000000006064820152608401610840565b611aa8633b9aca00826132c6565b15611b35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f4465706f736974436f6e74726163743a206465706f7369742076616c7565206e60448201527f6f74206d756c7469706c65206f662067776569000000000000000000000000006064820152608401610840565b6000611b45633b9aca0083613261565b905067ffffffffffffffff811115611bdf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4465706f736974436f6e74726163743a206465706f7369742076616c7565207460448201527f6f6f2068696768000000000000000000000000000000000000000000000000006064820152608401610840565b6000611bea82612342565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c587878388611c1c604154612342565b604051611c2d9594939291906133b0565b60405180910390a16000600288600060801b604051602001611c5092919061341d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611c8891613340565b602060405180830381855afa158015611ca5573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611cc89190613125565b9050600086806020019051810190611ce09190613464565b90506000600280838360200201518460016020020151604051602001611d10929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611d4891613340565b602060405180830381855afa158015611d65573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611d889190613125565b60408481015181516020810191909152600081830152815180820383018152606090910191829052600291611dbd9190613340565b602060405180830381855afa158015611dda573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611dfd9190613125565b604080516020810193909352820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611e4791613340565b602060405180830381855afa158015611e64573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611e879190613125565b90506000600280858c604051602001611ea19291906134e2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611ed991613340565b602060405180830381855afa158015611ef6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611f199190613125565b604051600290611f329089906000908890602001613508565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611f6a91613340565b602060405180830381855afa158015611f87573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611faa9190613125565b604080516020810193909352820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611ff491613340565b602060405180830381855afa158015612011573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906120349190613125565b90508781146120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605460248201527f4465706f736974436f6e74726163743a207265636f6e7374727563746564204460448201527f65706f7369744461746120646f6573206e6f74206d6174636820737570706c6960648201527f6564206465706f7369745f646174615f726f6f74000000000000000000000000608482015260a401610840565b60016120f960206002613677565b6121039190613683565b60415410612193576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c60448201527f6c000000000000000000000000000000000000000000000000000000000000006064820152608401610840565b6001604160008282546121a69190613275565b909155505060415460005b60208110156122ae5781600116600114156121ea5782602182602081106121da576121da61316d565b0155506104b49650505050505050565b6002602182602081106121ff576121ff61316d565b01546040805160208101929092528101859052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261224d91613340565b602060405180830381855afa15801561226a573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061228d9190613125565b925061229a600283613261565b9150806122a68161328d565b9150506121b1565b506122b761313e565b505050505050505050505050565b6122cd6126cc565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106123825761238261316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b826001815181106123cb576123cb61316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b826002815181106124145761241461316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b8260038151811061245d5761245d61316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b826004815181106124a6576124a661316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b826005815181106124ef576124ef61316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b826006815181106125385761253861316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106125815761258161316d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b73ffffffffffffffffffffffffffffffffffffffff82166125da5761085381612738565b610853828261277d565b6125ec6117d5565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586123183390565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526106f89084906128c9565b60005460ff16610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610840565b604051479073ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156106f8573d6000803e3d6000fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8416906370a082319060240160206040518083038186803b1580156127e557600080fd5b505afa1580156127f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061281d9190613125565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018390529192509084169063a9059cbb90604401602060405180830381600087803b15801561289157600080fd5b505af11580156128a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c99190613103565b600061292b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166129d59092919063ffffffff16565b8051909150156106f857808060200190518101906129499190613103565b6106f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610840565b60606110088484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051612a099190613340565b60006040518083038185875af1925050503d8060008114612a46576040519150601f19603f3d011682016040523d82523d6000602084013e612a4b565b606091505b5091509150612a5c87838387612a67565b979650505050505050565b60608315612afa578251612af35773ffffffffffffffffffffffffffffffffffffffff85163b612af3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610840565b5081611008565b6110088383815115612b0f5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108409190612ec1565b600060208284031215612b5557600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114612b8557600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112612bcc57600080fd5b813567ffffffffffffffff80821115612be757612be7612b8c565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612c2d57612c2d612b8c565b81604052838152866020858801011115612c4657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a08688031215612c7e57600080fd5b853567ffffffffffffffff80821115612c9657600080fd5b612ca289838a01612bbb565b96506020880135915080821115612cb857600080fd5b612cc489838a01612bbb565b95506040880135915080821115612cda57600080fd5b50612ce788828901612bbb565b9598949750949560608101359550608001359392505050565b600060208284031215612d1257600080fd5b813567ffffffffffffffff811115612d2957600080fd5b61100884828501612bbb565b60008083601f840112612d4757600080fd5b50813567ffffffffffffffff811115612d5f57600080fd5b6020830191508360208260051b8501011115612d7a57600080fd5b9250929050565b60008060008060408587031215612d9757600080fd5b843567ffffffffffffffff80821115612daf57600080fd5b612dbb88838901612d35565b90965094506020870135915080821115612dd457600080fd5b50612de187828801612d35565b95989497509550505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612e0f57600080fd5b50565b60008060408385031215612e2557600080fd5b8235612e3081612ded565b91506020830135612e4081612ded565b809150509250929050565b60005b83811015612e66578181015183820152602001612e4e565b838111156104c95750506000910152565b60008151808452612e8f816020860160208601612e4b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612b856020830184612e77565b600080600080600060608688031215612eec57600080fd5b85359450602086013567ffffffffffffffff80821115612f0b57600080fd5b612f1789838a01612d35565b90965094506040880135915080821115612f3057600080fd5b50612f3d88828901612d35565b969995985093965092949392505050565b600060208284031215612f6057600080fd5b8135612b8581612ded565b60008083601f840112612f7d57600080fd5b50813567ffffffffffffffff811115612f9557600080fd5b602083019150836020828501011115612d7a57600080fd5b60008060008060608587031215612fc357600080fd5b8435612fce81612ded565b935060208501359250604085013567ffffffffffffffff811115612ff157600080fd5b612de187828801612f6b565b6000806020838503121561301057600080fd5b823567ffffffffffffffff81111561302757600080fd5b61303385828601612d35565b90969095509350505050565b6000806000806000806000806080898b03121561305b57600080fd5b883567ffffffffffffffff8082111561307357600080fd5b61307f8c838d01612f6b565b909a50985060208b013591508082111561309857600080fd5b6130a48c838d01612f6b565b909850965060408b01359150808211156130bd57600080fd5b6130c98c838d01612f6b565b909650945060608b01359150808211156130e257600080fd5b506130ef8b828c01612d35565b999c989b5096995094979396929594505050565b60006020828403121561311557600080fd5b81518015158114612b8557600080fd5b60006020828403121561313757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156131ae57600080fd5b813567ffffffffffffffff81168114612b8557600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561322d5761322d6131c6565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261327057613270613232565b500490565b60008219821115613288576132886131c6565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156132bf576132bf6131c6565b5060010190565b6000826132d5576132d5613232565b500690565b600080858511156132ea57600080fd5b838611156132f757600080fd5b5050820193919092039150565b803560208310156103cc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b60008251613352818460208701612e4b565b9190910192915050565b83815260008351613374816020850160208801612e4b565b80830190507fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008416602082015260388101915050949350505050565b60a0815260006133c360a0830188612e77565b82810360208401526133d58188612e77565b905082810360408401526133e98187612e77565b905082810360608401526133fd8186612e77565b905082810360808401526134118185612e77565b98975050505050505050565b6000835161342f818460208801612e4b565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000939093169190920190815260100192915050565b60006060828403121561347657600080fd5b82601f83011261348557600080fd5b6040516060810181811067ffffffffffffffff821117156134a8576134a8612b8c565b6040528060608401858111156134bd57600080fd5b845b818110156134d75780518352602092830192016134bf565b509195945050505050565b828152600082516134fa816020850160208701612e4b565b919091016020019392505050565b6000845161351a818460208901612e4b565b7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009490941691909301908152601881019190915260380192915050565b600181815b808511156135b057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613596576135966131c6565b808516156135a357918102915b93841c939080029061355c565b509250929050565b6000826135c7575060016103cc565b816135d4575060006103cc565b81600181146135ea57600281146135f457613610565b60019150506103cc565b60ff841115613605576136056131c6565b50506001821b6103cc565b5060208310610133831016604e8410600b8410161715613633575081810a6103cc565b61363d8383613557565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561366f5761366f6131c6565b029392505050565b6000612b8583836135b8565b600082821015613695576136956131c6565b50039056fea26469706673582212203ce20f2f56588a2b91a30cd55aa2ef0ce265594100ba89ba293e06012ab7a20a64736f6c63430008090033" -} \ No newline at end of file diff --git a/test/shared/artifacts/GnoVault.json b/test/shared/artifacts/GnoVault.json deleted file mode 100644 index 2c9bfa81..00000000 --- a/test/shared/artifacts/GnoVault.json +++ /dev/null @@ -1,1524 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoVault", - "sourceName": "contracts/vaults/gnosis/GnoVault.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_keeper", - "type": "address" - }, - { - "internalType": "address", - "name": "_vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_validatorsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenVaultController", - "type": "address" - }, - { - "internalType": "address", - "name": "osTokenConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "sharedMevEscrow", - "type": "address" - }, - { - "internalType": "address", - "name": "depositDataRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - }, - { - "internalType": "address", - "name": "xdaiExchange", - "type": "address" - }, - { - "internalType": "uint256", - "name": "exitingAssetsClaimDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AccessDenied", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "CapacityExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "ExitRequestNotProcessed", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCapacity", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointIndex", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidCheckpointValue", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeePercent", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidFeeRecipient", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHealthFactor", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPosition", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidReceivedAssets", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShares", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidValidators", - "type": "error" - }, - { - "inputs": [], - "name": "LiquidationDisabled", - "type": "error" - }, - { - "inputs": [], - "name": "LowLtv", - "type": "error" - }, - { - "inputs": [], - "name": "MathOverflowedMulDiv", - "type": "error" - }, - { - "inputs": [], - "name": "NotCollateralized", - "type": "error" - }, - { - "inputs": [], - "name": "NotHarvested", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "bits", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeCastOverflowedUintToInt", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "inputs": [], - "name": "UpgradeFailed", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "CheckpointCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "Deposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "prevPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPositionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAssets", - "type": "uint256" - } - ], - "name": "ExitedAssetsClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "penalty", - "type": "uint256" - } - ], - "name": "ExitingAssetsPenalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "feeRecipient", - "type": "address" - } - ], - "name": "FeeRecipientUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "FeeSharesMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "keysManager", - "type": "address" - } - ], - "name": "KeysManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "MetadataUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "OsTokenBurned", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "receivedAssets", - "type": "uint256" - } - ], - "name": "OsTokenLiquidated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "OsTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "OsTokenRedeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "Redeemed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "V2ExitQueueEntered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes", - "name": "publicKey", - "type": "bytes" - } - ], - "name": "ValidatorRegistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "validatorsManager", - "type": "address" - } - ], - "name": "ValidatorsManagerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "validatorsRoot", - "type": "bytes32" - } - ], - "name": "ValidatorsRootUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "XdaiSwapped", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "osTokenShares", - "type": "uint128" - } - ], - "name": "burnOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "calculateExitedAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "leftTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedTickets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitedAssets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "capacity", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitQueueIndex", - "type": "uint256" - } - ], - "name": "claimExitedAssets", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "name": "convertToAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "name": "convertToShares", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "enterExitQueue", - "outputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "feePercent", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeRecipient", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "positionTicket", - "type": "uint256" - } - ], - "name": "getExitQueueIndex", - "outputs": [ - { - "internalType": "int256", - "name": "", - "type": "int256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isStateUpdateRequired", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "liquidateOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "referrer", - "type": "address" - } - ], - "name": "mintOsToken", - "outputs": [ - { - "internalType": "uint256", - "name": "assets", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "osTokenPositions", - "outputs": [ - { - "internalType": "uint128", - "name": "shares", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "queuedShares", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "osTokenShares", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemOsToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "validatorsRegistryRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "validators", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "string", - "name": "exitSignaturesIpfsHash", - "type": "string" - } - ], - "internalType": "struct IKeeperValidators.ApprovalParams", - "name": "keeperParams", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "validatorsManagerSignature", - "type": "bytes" - } - ], - "name": "registerValidators", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_feeRecipient", - "type": "address" - } - ], - "name": "setFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "metadataIpfsHash", - "type": "string" - } - ], - "name": "setMetadata", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validatorsManager_", - "type": "address" - } - ], - "name": "setValidatorsManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "swapXdaiToGno", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalExitingAssets", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalShares", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "rewardsRoot", - "type": "bytes32" - }, - { - "internalType": "int160", - "name": "reward", - "type": "int160" - }, - { - "internalType": "uint160", - "name": "unlockedMevReward", - "type": "uint160" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "internalType": "struct IKeeperRewards.HarvestParams", - "name": "harvestParams", - "type": "tuple" - } - ], - "name": "updateState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorsManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawableAssets", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x61020034620002af57620050cc601f38829003908101601f19168301906001600160401b039081831185841017620002b3578085946040948552853961014094859181010312620002af576200005583620002c7565b906200006460208501620002c7565b9262000072818601620002c7565b956200008160608701620002c7565b906200009060808801620002c7565b926200009f60a08901620002c7565b94620000ae60c08a01620002c7565b96620000bd60e08b01620002c7565b976101009b620000cf8d8d01620002c7565b9a610120809d01519360805260a05260c0523060e0528b52468a52835260018060a01b03806101609516855280610180961686526101a09687526101c0971687526101e09788527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166200029e57808083160362000259575b5050505196614def9889620002dd8a396080518981816116e20152818161187a01528181612c87015281816130c1015261314d015260a05189611459015260c0518981816136e601528181613efa015281816141160152614aad015260e0518981816115d901526138c9015251886128b301525187613bd301525186611a2001525185818161031d01528181610565015281816107b1015281816128ea015281816132eb0152613374015251848181610870015281816110bc0152818161326f015261343301525183818161226e0152612ccf015251828181610c8a0152818161369501528181613f6401528181614160015281816142710152614831015251816127d50152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f808062000151565b835163f92ee8a960e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620002af5756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d11414610289578063066055e01461028457806307a2d13a1461027f5780631a7ff5531461027a578063201b9eb5146102755780632999ad3f146102705780632cdf74011461026b5780632e2d2984146102665780633229fa951461026157806333194c0a1461025c5780633a98ef3914610257578063439fab911461025257806343e82a791461024d57806346904840146102485780634ec96b22146102435780634f1ef2861461023e57806352d1902d1461023957806354fd4d50146102345780635c60da1b1461022f5780635cfc1a511461022a57806360d60e6e1461022557806372b410a814610220578063754c38881461021b57806376b58b90146102165780637fd6f15c1461021157806383d430d51461020c5780638697d2c2146102075780638ceab9aa14610202578063a49a1e7d146101fd578063ac9650d8146101f8578063ad3cb1cc146101f3578063b0d11302146101ee578063b1f0e7c7146101e9578063c6e6f592146101e4578063d83ad00c146101df578063e74b981b146101da578063ee3bd5df146101d5578063f04da65b146101d05763f851a4400361000e5761210d565b6120d2565b6120ac565b61207f565b612059565b61203b565b612021565b611fee565b611fa9565b611f33565b611e38565b611c4f565b6119f4565b611824565b611800565b6117af565b611744565b6116b7565b611699565b61167f565b61164b565b611630565b6115c7565b611341565b6111b2565b61118a565b61108d565b610e92565b610e11565b610dd7565b610dab565b610c3d565b610c23565b610787565b6104fc565b610497565b610471565b6102cd565b61029c565b5f91031261029857565b5f80fd5b34610298575f36600319011261029857602060985460801c604051908152f35b6001600160801b0381160361029857565b34610298576020366003190112610298576004356102ea816102bc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561046c575f9161043d575b50335f908152610137602052604090206103669061214e565b916001600160801b0361038084516001600160801b031690565b161561042b576103d483610396610427956128d5565b6103c06103b3846103ae84516001600160801b031690565b612187565b6001600160801b03168252565b335f908152610137602052604090206121a5565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61045f915060203d602011610465575b61045781836112c0565b810190612134565b5f61034d565b503d61044d565b612143565b3461029857602036600319011261029857602061048f6004356121d7565b604051908152f35b346102985760031960203682011261029857600435906001600160401b038211610298576080908236030112610298576104d66104dd91600401612c56565b9190612dec565b6104e357005b610018612f76565b6001600160a01b0381160361029857565b3461029857606036600319011261029857600435610519816104eb565b602435906044359061052a826104eb565b6105326130a6565b61053a613132565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af194851561046c575f9561073c575b50335f908152610137602052604090206105b59061214e565b926001600160801b036105cf85516001600160801b031690565b16156106d85750506105e0826128d5565b61060c6105ff6105ef876131bd565b84516001600160801b03166121fd565b6001600160801b03168352565b335f908152609c6020526040902061062e90610629905b546121d7565b61324c565b61064e61064284516001600160801b031690565b6001600160801b031690565b116106c657335f90815261013760205260409020610427957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5893909161069491906121a5565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610414565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561046c5761071a9261070b915f9161071f575b506131bd565b6001600160801b031690840152565b6105e0565b6107369150833d85116104655761045781836112c0565b5f610705565b610754919550833d85116104655761045781836112c0565b935f61059c565b60609060031901126102985760043590602435610777816104eb565b90604435610784816104eb565b90565b34610298576107953661075b565b906001600160a01b0380831615610c11576107ae613132565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102985760408051631d8557d760e01b815260049491905f81878183875af1801561046c57610bf8575b506001600160a01b0383165f908152610137602052604090206108219061214e565b6001600160801b03928361083c83516001600160801b031690565b1615610be85761084b826128d5565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561046c575f98610bb7575b50602097888101956001600160401b039182806108c48a516001600160401b031690565b1614610ba757908c92918751918c83806108f06303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561046c5761091c938e5f94610b82575b5050516001600160801b03165b1690612a04565b9661093a6106238a60018060a01b03165f52609c60205260405f2090565b928389118015610b72575b610b6257908b610983939261096189516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561046c57670de0b6b3a7640000946109d2948e5f95610b35575b50506109c46109b66109ca926125aa565b93516001600160401b031690565b936125aa565b921690612afd565b1015610b27578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561046c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610b0495610a7c93610b09575b5050610a5f6103b3610a4f8c6131bd565b83516001600160801b0316612187565b6001600160a01b0386165f908152610137602052604090206121a5565b610a8582614338565b90610ac3610aa8610a95856131bd565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610acd82866145f8565b610ad78389614253565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610b1f92903d106104655761045781836112c0565b505f80610a3e565b835163185cfc6d60e11b8152fd5b6109ca929550610b586109c492826109b693903d106104655761045781836112c0565b959250508e6109a5565b875163efda1a2760e01b81528590fd5b50610b7b612218565b8911610945565b6109159294509081610b9f92903d106104655761045781836112c0565b92908e610908565b8651630709133160e01b81528490fd5b610bda91985060603d606011610be1575b610bd281836112c0565b810190613204565b965f6108a0565b503d610bc8565b825163673f032f60e11b81528790fd5b80610c05610c0b9261125c565b8061028e565b5f6107ff565b60405163d92e233d60e01b8152600490fd5b34610298575f36600319011261029857602061048f612218565b3461029857610c4b3661075b565b91610c5461375d565b604092610cae84516323b872dd60e01b602082015233602482015230604482015283606482015260648152610c888161128a565b7f0000000000000000000000000000000000000000000000000000000000000000614645565b610cb6613132565b6001600160a01b038316928315610d9a578215610d895782610cdd61064260985460801c90565b0190610ce76122a5565b8211610d7857610d5e610aa89593610d3886947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610d33610d2b60209c9a6143be565b9a8b936131bd565b614467565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020614d9a8339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b34610298575f366003190112610298576020610dc5612255565b6040516001600160a01b039091168152f35b34610298575f3660031901126102985760206040517f92db5a150616972630ec6ff109fcce78f8559cc5594d540f16cd3cfa3fc86bcc8152f35b34610298575f3660031901126102985760206001600160801b0360985416604051908152f35b9181601f84011215610298578235916001600160401b038311610298576020838186019501011161029857565b602060031982011261029857600435906001600160401b03821161029857610e8e91600401610e37565b9091565b3461029857610ea036610e64565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c168015611079575b6110685768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020918285600481335afa94851561046c575f95611049575b508351636f4fa30f60e01b8152908382600481335afa91821561046c575f9261101a575b5082019483838703126102985782356001600160401b039384821161029857019260608488031261029857855193610f738561126f565b803585528581013561ffff8116810361029857868601528681013591821161029857019386601f86011215610298577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29685610fd592610fde9735910161130b565b858401526137d7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff0000000000000000191690555160028152602090a1005b61103b919250843d8611611042575b61103381836112c0565b810190612290565b905f610f3c565b503d611029565b611061919550833d85116110425761103381836112c0565b935f610f18565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015610ed5565b346102985761109b3661075b565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561046c5782915f9161116b575b501633036111595781610b0461112686867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613356565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611184915060203d6020116110425761103381836112c0565b5f6110ee565b34610298575f366003190112610298576065546040516001600160a01b039091168152602090f35b34610298576020366003190112610298576004356111cf816104eb565b60018060a01b03165f52610137602052602060405f20604051906111f28261123c565b54906001600160801b03918281169081835260801c8483015261121a575b5116604051908152f35b611223816128d5565b611210565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761125757604052565b611228565b6001600160401b03811161125757604052565b606081019081106001600160401b0382111761125757604052565b60a081019081106001600160401b0382111761125757604052565b608081019081106001600160401b0382111761125757604052565b90601f801991011681019081106001600160401b0382111761125757604052565b604051906112ee8261123c565b565b6001600160401b03811161125757601f01601f191660200190565b929192611317826112f0565b9161132560405193846112c0565b829481845281830111610298578281602093845f960137010152565b60408060031936011261029857600490813561135c816104eb565b6024356001600160401b03811161029857366023820112156102985761138b903690602481870135910161130b565b916113946138bf565b8051926113cb846113bd60209363439fab9160e01b858401528460248401526044830190611eab565b03601f1981018652856112c0565b6113d36138bf565b6113db61399f565b6001600160a01b03838116801592919087908415611592575b8415611524575b84156114c0575b5050821561142a575b505061141b576100188383614880565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561046c575f92611493575b5050155f8061140b565b6114b29250803d106114b9575b6114aa81836112c0565b81019061239a565b5f80611489565b503d6114a0565b855163054fd4d560e41b81529294508391839182905afa90811561046c5760039160ff915f916114f7575b5016141591865f611402565b6115179150843d861161151d575b61150f81836112c0565b810190614867565b5f6114eb565b503d611505565b935050835163198ca60560e11b815282818981875afa90811561046c5788917f92db5a150616972630ec6ff109fcce78f8559cc5594d540f16cd3cfa3fc86bcc915f91611575575b501415936113fb565b61158c9150853d87116104655761045781836112c0565b5f61156c565b5f80516020614d7a8339815191525490945084906115c0906001600160a01b03165b6001600160a01b031690565b14936113f4565b34610298575f366003190112610298577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361161e5760206040515f80516020614d7a8339815191528152f35b60405163703e46dd60e11b8152600490fd5b34610298575f36600319011261029857602060405160028152f35b34610298575f366003190112610298575f80516020614d7a833981519152546040516001600160a01b039091168152602090f35b34610298575f36600319011261029857602061048f6122a5565b3461029857602036600319011261029857602061048f6004356122ce565b34610298575f36600319011261029857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561046c576020915f91611727575b506040519015158152f35b61173e9150823d84116114b9576114aa81836112c0565b5f61171c565b3461029857602036600319011261029857600435611761816104eb565b61176961399f565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b34610298576080366003190112610298576104276117e36004356117d2816104eb565b6064359060443590602435906123bb565b604080519384526020840192909252908201529081906060820190565b34610298575f36600319011261029857602061ffff60655460a01c16604051908152f35b34610298576003196040368201126102985760049081356001600160401b038082116102985760a082850193833603011261029857602435908111610298576118709036908501610e37565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102985760405163837d444160e01b8152905f9082908183816118c38c828f016124bf565b03925af1801561046c576119e1575b506118db613132565b6118e361289f565b90811633141591826119b2575b505090506119a1576044019160b0611908848461253d565b90500480158015611989575b61197957611929611923612218565b91612592565b1161196a575060b061193b838361253d565b9050145f1461195757610018916119519161253d565b906140f4565b610018916119649161253d565b90613ec4565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611994848461253d565b905060b082021415611914565b604051634ca8886760e01b81528390fd5b6119d592506119cf6119d9946119c788613bcd565b92369161130b565b91613ca7565b1590565b805f806118f0565b80610c056119ee9261125c565b5f6118d2565b3461029857606036600319011261029857600435602435611a196044358284336123bb565b9192611a457f0000000000000000000000000000000000000000000000000000000000000000826122c1565b42108015611c47575b8015611c3f575b611c2d577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611a9986611a946106426099546001600160801b031690565b613918565b15611b9b57611ad3611ab8611aad866131bd565b60995460801c612187565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611b179190611b066080826112c0565b5190205f52609b60205260405f2090565b555f9360018311611b50575b50505050611b318233614253565b604080519485526020850191909152830152339180606081015b0390a2005b611b9192939450611b6190886122c1565b6040805133602082019081529181019390935260608301829052608095860183529094909190611b0690826112c0565b555f808080611b23565b611ba3613132565b611bdf611bc3611bb2866131bd565b609e546001600160801b0316612187565b6001600160801b03166001600160801b0319609e541617609e55565b611c14611bf9611bee856131bd565b609e5460801c612187565b6001600160801b03609e549181199060801b16911617609e55565b611c28611c2384609f546122c1565b609f55565b611ad3565b604051630e3d8e8d60e11b8152600490fd5b508215611a55565b508115611a4e565b34610298576040806003193601126102985760243590600435611c71836104eb565b611c79613132565b8015611e27576001600160a01b038316908115611e1657611c99816121d7565b908115611e0557611ca98261496d565b611cb2836131bd565b60985460801c90611cc291612187565b611ce1906001600160801b036098549181199060801b16911617609855565b611ceb82336145f8565b609e54958660801c8281609f5490611d02916122c1565b98611d0c876131bd565b611d1e916001600160801b03166121fd565b611d3e906001600160801b03166001600160801b0319609e541617609e55565b611d47916122c1565b611d50906131bd565b611d6f906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611da06080826112c0565b519020611db5905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611dfc33614b39565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461029857611b4b7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611e6a36610e64565b9290611e7461399f565b604051918291602083523395602084019161249f565b5f5b838110611e9b5750505f910152565b8181015183820152602001611e8c565b90602091611ec481518092818552858086019101611e8a565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611f055750505050505090565b9091929394958480611f23600193603f198682030187528a51611eab565b9801930193019194939290611ef5565b34610298576020366003190112610298576001600160401b036004358181116102985736602382011215610298578060040135918211610298573660248360051b8301011161029857610427916024611f8c9201612705565b60405191829182611ed0565b906020610784928181520190611eab565b34610298575f36600319011261029857610427604051611fc88161123c565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611eab565b34610298575f3660031901126102985761200661375d565b61200e6127b2565b60015f80516020614d9a83398151915255005b34610298575f366003190112610298576020610dc561289f565b3461029857602036600319011261029857602061048f600435614338565b34610298575f3660031901126102985760206001600160801b0360995416604051908152f35b346102985760203660031901126102985761001860043561209f816104eb565b6120a761399f565b614405565b34610298575f3660031901126102985760206001600160801b03609e5416604051908152f35b34610298576020366003190112610298576004356120ef816104eb565b60018060a01b03165f52609c602052602060405f2054604051908152f35b34610298575f366003190112610298575f546040516001600160a01b039091168152602090f35b90816020910312610298575190565b6040513d5f823e3d90fd5b9060405161215b8161123c565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b0391821690821603919082116121a057565b612173565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816121ef57505090565b916107849260801c90612afd565b9190916001600160801b03808094169116019182116121a057565b61222061366f565b6099546001600160801b036122368183166121d7565b90609e5416019060801c01908181115f1461224f570390565b50505f90565b61016a546001600160a01b0316801561226b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102985751610784816104eb565b609d548061078457505f1990565b9060b082018092116121a057565b919082018092116121a057565b6001600160801b03609954166122e261492b565b9081018091116121a057811061231557612306609f5461230061392f565b906122c1565b1115612310575f90565b5f1990565b609a90609a549182915f905b84821061233b575050508110156123355790565b505f1990565b909193808316906001818518811c83018093116121a0575f8790525f80516020614d5a8339815191528301546001600160a01b0316841015612382575050935b9190612321565b90959101925061237b565b5190811515820361029857565b90816020910312610298576107849061238d565b919082039182116121a057565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906123f981608081015b03601f1981018352826112c0565b5190205f52609b60205260405f2054918215612463576001600160801b03609954169061242461492b565b9182018092116121a0578391831015612451579161244192613a32565b90915b8281039081116121a05792565b509061245c916139b2565b9091612444565b5050505f905f905f90565b9035601e19823603018112156102985701602081359101916001600160401b03821161029857813603831361029857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610784926020815282356020820152602083013560408201526124fb6124eb604085018561246e565b84606085015260c084019161249f565b9061252e61252361250f606087018761246e565b601f1985870381016080870152959161249f565b94608081019061246e565b9390928286030191015261249f565b903590601e198136030182121561029857018035906001600160401b0382116102985760200191813603831361029857565b634e487b7160e01b5f52601260045260245ffd5b811561258d570490565b61256f565b90670de0b6b3a764000091808302928304036121a057565b90670de0b6b3a7640000918281029281840414901517156121a057565b6001600160401b0381116112575760051b60200190565b906125e8826125c7565b6125f560405191826112c0565b8281528092612606601f19916125c7565b01905f5b82811061261657505050565b80606060208093850101520161260a565b634e487b7160e01b5f52603260045260245ffd5b9082101561265257610e8e9160051b81019061253d565b612627565b908092918237015f815290565b3d1561268e573d90612675826112f0565b9161268360405193846112c0565b82523d5f602084013e565b606090565b602081830312610298578051906001600160401b038211610298570181601f820112156102985780516126c5816112f0565b926126d360405194856112c0565b81845260208284010111610298576107849160208085019101611e8a565b80518210156126525760209160051b010190565b919091612711836125de565b925f5b81811061272057505050565b5f8061272d83858761263b565b6040939161273f855180938193612657565b0390305af49061274d612664565b911561277457509060019161276282886126f1565b5261276d81876126f1565b5001612714565b906044815110610298576127ae61279960049283810151602480918301019101612693565b925162461bcd60e51b81529283928301611f98565b0390fd5b47633b9aca00811061289c57604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af191821561046c575f9261287b575b506001600160ff1b03821161286257907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db9161284882612dec565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b61289591925060203d6020116104655761045781836112c0565b905f61280d565b50565b60d2546001600160a01b03168061078457507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561046c575f9161296b575b5060208201916001600160801b03918284511691828214612964578361295761295261295f958584865116612afd565b6131bd565b1690526131bd565b169052565b5050505050565b612984915060203d6020116104655761045781836112c0565b5f612922565b90808202905f19818409908280831092039180830392146129f95761271090828211156129e7577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612a6757670de0b6b3a764000090828211156129e7577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612af057848311156129e757829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107849250612583565b9091828202915f1984820993838086109503948086039514612af057848311156129e757829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102985780519161078460406020840151930161238d565b81835290916001600160fb1b0383116102985760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102985760408301526040810135612be2816104eb565b6001600160a01b031660608381019190915281013536829003601e19018112156102985701602081359101906001600160401b038111610298578060051b360382136102985760a0836080806107849601520191612b8f565b9190915f83820193841291129080158216911516176121a057565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612c819060048301612bb3565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561046c575f915f905f95612da7575b508415612d545781612ccb612255565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612d4d57509060205f92600460405180958193634641257d60e01b83525af190811561046c57612d28925f92612d2c575b50612c3b565b9190565b612d4691925060203d6020116104655761045781836112c0565b905f612d22565b9081612d5a575b50509190565b803b1561029857604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561046c57612d94575b80612d54565b80610c05612da19261125c565b5f612d8e565b91945050612dcd915060603d606011612dd5575b612dc581836112c0565b810190612b70565b93905f612cbb565b503d612dbb565b600160ff1b81146121a0575f0390565b801561289c57612e0161064260985460801c90565b5f8212612ed35781612e12916122c1565b90612e1f610aa8836131bd565b612e346065549161ffff8360a01c169061298a565b8015612ece57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793612e726106426098546001600160801b031690565b80612eb857505061285d90925b6001600160a01b031691612e938484614467565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b61285d92612ec892039084612afd565b92612e7f565b505050565b90612edd90612ddc565b612ef2610642609e546001600160801b031690565b80612f12575b5080612f02575050565b612952610aa8916112ee936123ae565b90612f6d7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91612f5d611bc3612f52612f4b88886122c1565b8785612afd565b8080940396036131bd565b6040519081529081906020820190565b0390a15f612ef8565b609954906001600160801b0382169182156130a05760801c612fb1612fa282612f9d61366f565b6123ae565b612fab856121d7565b906144b3565b90811561309957612fc182614338565b938415613091578261300e611ab86129526112ee96610aa896613009612fed6129528d6130869a6123ae565b6001600160801b03166001600160801b03196099541617609955565b6122c1565b6130188187614523565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a161295261306a613059886131bd565b6098546001600160801b0316612187565b6001600160801b03166001600160801b03196098541617609855565b60985460801c612187565b505f93505050565b505f925050565b505f9150565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561046c575f91613113575b501561310157565b604051630a62fbdb60e11b8152600490fd5b61312c915060203d6020116114b9576114aa81836112c0565b5f6130f9565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561046c575f9161319e575b5061318c57565b60405163e775715160e01b8152600490fd5b6131b7915060203d6020116114b9576114aa81836112c0565b5f613185565b6001600160801b03908181116131d1571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b51906001600160401b038216820361029857565b908160609103126102985761324460408051926132208461126f565b805161322b816102bc565b8452613239602082016131f0565b6020850152016131f0565b604082015290565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561046c576132e7936001600160401b0361091560406132c6946020975f91613337575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561046c575f9161331e575090565b610784915060203d6020116104655761045781836112c0565b613350915060603d606011610be157610bd281836112c0565b5f6132b7565b92906001600160a01b039081811615610c1157613371613132565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561029857604094855193631d8557d760e01b85526004945f81878183895af1801561046c5761365c575b506001600160a01b0388165f908152610137602052604090206133e49061214e565b906001600160801b036133fe83516001600160801b031690565b161561364c5761340d826128d5565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561046c5761362d575b508651936303d1689d60e11b97888652602091828780613487888c83019190602083019252565b0381845afa96871561046c575f9761360e575b5086996134ba6106238d60018060a01b03165f52609c60205260405f2090565b881180156135fe575b6135ee579083613500926134de87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561046c575f859488946135459c6135d1575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561046c57610a4f61358c9461356f936103b3936112ee9a6135b3575b50506131bd565b6001600160a01b0388165f908152610137602052604090206121a5565b6135ae61359883614338565b80976135a9610aa8610a95876131bd565b6145f8565b614253565b816135c992903d106104655761045781836112c0565b505f80613568565b6135e790873d89116104655761045781836112c0565b505f61351a565b825163efda1a2760e01b81528990fd5b50613607612218565b88116134c3565b613626919750833d85116104655761045781836112c0565b955f61349a565b6136459060603d606011610be157610bd281836112c0565b505f613460565b875163673f032f60e11b81528690fd5b80610c056136699261125c565b5f6133c2565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561046c575f91613740575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561046c57610784935f93613721575b50506122c1565b613738929350803d106104655761045781836112c0565b905f8061371a565b6137579150833d85116104655761045781836112c0565b5f6136c6565b5f80516020614d9a833981519152600281541461377a5760029055565b604051633ee5aeb560e01b8152600490fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca0060648083019190915281526112ee916137d28261128a565b614645565b6137df6146b6565b60408301516137ec6146b6565b6001600160a01b0382168015610c11576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061384533946020830190611eab565b0390a26020830151926138566146b6565b61271061ffff8516116138ad576138a59361387361389893614405565b6065805461ffff60a01b191660a09290921b61ffff60a01b16919091179055516146f7565b6138a0614727565b614752565b6112ee614781565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149182156138fd575b505061161e57565b5f80516020614d7a8339815191525416141590505f806138f5565b9061392161492b565b9182018092116121a0571090565b61393761366f565b6099548060801c82039182116121a0578161395b6001600160801b038093166121d7565b9081613981575b5050811561224f576107849161397c91609e5416906144b3565b61496d565b919250908181111561399757035b905f80613962565b50505f61398f565b5f546001600160a01b0316330361115957565b6139ba61392f565b91609f549283018093116121a05780831115613a04576139db9203906144b3565b90609e548060801c80155f146139f15750508190565b6001600160801b03610784921684612afd565b5050505f905f90565b90604051613a1a8161123c565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613bc5575b613bb85783613b82575f5b609a5f526001600160a01b0316613a775f80516020614d5a8339815191528601613a0d565b8051909790613a8e906001600160a01b03166115b4565b98613ab3613aa76020809b01516001600160601b031690565b6001600160601b031690565b948381108015613b78575b613b665791600193979a95613add613ae9939488035b838c03906144b3565b80920198870391612afd565b01970193808611801590613b5c575b613b5157609a5f528290613b1a5f80516020614d5a8339815191528701613a0d565b805190890151969992966001600160a01b039091169460019392613ae99290916001600160601b0390911690613add908803613ad4565b945050509250509190565b5081851015613af8565b60405163e8722f8f60e01b8152600490fd5b50808b1115613abe565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613a52565b505093505050505f905f90565b508415613a47565b604290467f000000000000000000000000000000000000000000000000000000000000000003613c7b5760d354905b613c13613c0c604083018361253d565b369161130b565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613c5e816112a5565b5190206040519161190160f01b8352600283015260228201522090565b613c836149a4565b90613bfc565b60041115613c9357565b634e487b7160e01b5f52602160045260245ffd5b613cb18383614a71565b50613cbe81959295613c89565b159384613d5a575b508315613cd4575b50505090565b5f929350908291604051613d0c816123eb6020820194630b135d3f60e11b998a87526024840152604060448401526064830190611eab565b51915afa90613d19612664565b82613d4c575b82613d2f575b50505f8080613cce565b613d4491925060208082518301019101612134565b145f80613d25565b915060208251101591613d1f565b6001600160a01b0383811691161493505f613cc6565b90613d7a826125c7565b613d8760405191826112c0565b8281528092613d98601f19916125c7565b0190602036910137565b906030116102985790603090565b906090116102985760300190606090565b9060b0116102985760900190602090565b90939293848311610298578411610298578101920390565b602090836112ee939594956040519683613e0d8995518092888089019101611e8a565b84019185830137015f838201520380855201836112c0565b359060208110613e33575090565b5f199060200360031b1b1690565b91602061078493818152019161249f565b9192613e7c613e6c613e8a93608086526080860190611eab565b6020958582036020870152611eab565b908382036040850152611eab565b906060818303910152602080845192838152019301915f5b828110613eb0575050505090565b835185529381019392810192600101613ea2565b613ecc614aab565b6060906060905f809460b0810492613ee384613d70565b965f905b85821061400257506001600160a01b03947f00000000000000000000000000000000000000000000000000000000000000009450613f5e935060209250613f2e9150612592565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561046c57613fe3575b5016613f9b614b10565b813b15610298575f8094613fc56040519788968795869463c82655b760e01b865260048601613e52565b03925af1801561046c57613fd65750565b80610c056112ee9261125c565b613ffb9060203d6020116114b9576114aa81836112c0565b505f613f91565b61408761405761406261404461403b7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c6122b3565b80998989613dd2565b92909a614051848d613da2565b91613dea565b9a614051838c613db0565b988b6140818661407b6140758686613dc1565b90613e25565b926126f1565b52613da2565b9061409760405192839283613e41565b0390a160010183613ee7565b92946140dc670de0b6b3a7640000966140ce608097946140ea969b9a9b60a0895260a089019161249f565b908682036020880152611eab565b91848303604086015261249f565b9460608201520152565b906140fd614aab565b6141078183613da2565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af1801561046c57614234575b501690614199614b10565b916141b26140756141aa8489613db0565b949098613dc1565b95813b15610298575f80946141df604051998a9687958694630cac9f3160e01b86528c8c600488016140a3565b03925af192831561046c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb193614221575b5061285d60405192839283613e41565b80610c0561422e9261125c565b5f614211565b61424c9060203d6020116114b9576114aa81836112c0565b505f61418e565b9061425c61375d565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561046c576142f6946137d2925f91614319575b50841161430c575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836112c0565b6112ee60015f80516020614d9a83398151915255565b614314614aab565b6142c1565b614332915060203d6020116104655761045781836112c0565b5f6142b9565b609854906001600160801b03821681158015614367575b1561435a5750905090565b6107849260801c91612afd565b50801561434f565b6098546001600160801b038116908161438c575050633b9aca0090565b60801c6143998183612a78565b91811561258d57633b9aca00096143ad5790565b600181018091111561078457612173565b6098546001600160801b03811690821580156143fd575b156143df57505090565b60801c906143ee828285612afd565b92821561258d57096143ad5790565b5081156143d5565b61440d613132565b6001600160a01b0316801561445557606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b614470826131bd565b609854906144886001600160801b03918284166121fd565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b90808210156144c0575090565b905090565b609a549068010000000000000000821015611257576001820180609a5582101561265257609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614d5a83398151915290910155565b919091801580156145f0575b6145de5761453b61492b565b9081018091116121a0576001600160a01b038082116145be576001600160601b039081851161459e57906112ee9394614588614599936145796112e1565b95166001600160a01b03168552565b166001600160601b03166020830152565b6144c5565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561452f565b60018060a01b03165f52609c60205260405f209081548181039081116121a05761462292556131bd565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f8061466d9260018060a01b03169360208151910182865af1614666612664565b9083614cf6565b805190811515918261469b575b50506146835750565b60249060405190635274afe760e01b82526004820152fd5b6146ae925060208091830101910161239a565b155f8061467a565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156146e557565b604051631afcd79f60e31b8152600490fd5b6146ff6146b6565b801561471557600181016147105750565b609d55565b6040516331278a8760e01b8152600490fd5b61472f6146b6565b670de0b6b3a76400006147406122a5565b106147155761474d6149a4565b60d355565b61475a6146b6565b6001600160a01b03168061476b5750565b61016a80546001600160a01b0319169091179055565b6147896146b6565b6147916146b6565b6147996146b6565b60015f80516020614d9a833981519152556147b2613132565b3015610c1157633b9aca008060985460801c016147cd6122a5565b8111614855576147e7610aa86147e161436f565b926131bd565b6147f18130614467565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36112ee30337f000000000000000000000000000000000000000000000000000000000000000061378c565b6040516304ffa0ff60e51b8152600490fd5b90816020910312610298575160ff811681036102985790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948161490a575b506148d057604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614d7a83398151915284036148f1576112ee929350614bb9565b604051632a87526960e21b815260048101859052602490fd5b61492491955060203d6020116104655761045781836112c0565b935f6148aa565b609a548061493857505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166115b4565b609e54908160801c8115801561499c575b156149895750905090565b6001600160801b03610784931691612afd565b50801561497e565b6e5661756c7456616c696461746f727360881b60206040516149c58161123c565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176112575760405251902090565b8151919060418303614aa157614a9a9250602082015190606060408401519301515f1a90614c5b565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610298575f809160246040518094819363a3066aab60e01b83523060048401525af1801561046c57614b075750565b6112ee9061125c565b604051600160f81b60208201525f60218201523060601b602c820152602081526107848161123c565b60018060a01b0381165f5261013760205260405f209060405191614b5c8361123c565b54906001600160801b03918281169081855260801c602085015215612ece57610629610623614baf92614b8d613132565b614b96866128d5565b6001600160a01b03165f908152609c6020526040902090565b915116116106c657565b90813b15614c3a575f80516020614d7a83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614c1f5761289c91614cdd565b505034614c2857565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614cd2579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1561046c575f516001600160a01b03811615614cc857905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061078493602081519101845af4614cf4612664565b915b90614d1d5750805115614d0b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614d50575b614d2e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614d2656fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220aa0ce264a9718bea85c45b437146008c0488db5f4a0d4ef1f521b857be74f98a64736f6c63430008160033", - "deployedBytecode": "0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301e1d11414610289578063066055e01461028457806307a2d13a1461027f5780631a7ff5531461027a578063201b9eb5146102755780632999ad3f146102705780632cdf74011461026b5780632e2d2984146102665780633229fa951461026157806333194c0a1461025c5780633a98ef3914610257578063439fab911461025257806343e82a791461024d57806346904840146102485780634ec96b22146102435780634f1ef2861461023e57806352d1902d1461023957806354fd4d50146102345780635c60da1b1461022f5780635cfc1a511461022a57806360d60e6e1461022557806372b410a814610220578063754c38881461021b57806376b58b90146102165780637fd6f15c1461021157806383d430d51461020c5780638697d2c2146102075780638ceab9aa14610202578063a49a1e7d146101fd578063ac9650d8146101f8578063ad3cb1cc146101f3578063b0d11302146101ee578063b1f0e7c7146101e9578063c6e6f592146101e4578063d83ad00c146101df578063e74b981b146101da578063ee3bd5df146101d5578063f04da65b146101d05763f851a4400361000e5761210d565b6120d2565b6120ac565b61207f565b612059565b61203b565b612021565b611fee565b611fa9565b611f33565b611e38565b611c4f565b6119f4565b611824565b611800565b6117af565b611744565b6116b7565b611699565b61167f565b61164b565b611630565b6115c7565b611341565b6111b2565b61118a565b61108d565b610e92565b610e11565b610dd7565b610dab565b610c3d565b610c23565b610787565b6104fc565b610497565b610471565b6102cd565b61029c565b5f91031261029857565b5f80fd5b34610298575f36600319011261029857602060985460801c604051908152f35b6001600160801b0381160361029857565b34610298576020366003190112610298576004356102ea816102bc565b604051633b9e9f0160e21b81523360048201526001600160801b03821660248201526020816044815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561046c575f9161043d575b50335f908152610137602052604090206103669061214e565b916001600160801b0361038084516001600160801b031690565b161561042b576103d483610396610427956128d5565b6103c06103b3846103ae84516001600160801b031690565b612187565b6001600160801b03168252565b335f908152610137602052604090206121a5565b604080518381526001600160801b03909216602083015233917f3f7354ba02880b4fa37a629985852a38417ff369369ce1e52fa6f8342a9100a791819081015b0390a26040519081529081906020820190565b0390f35b60405163673f032f60e11b8152600490fd5b61045f915060203d602011610465575b61045781836112c0565b810190612134565b5f61034d565b503d61044d565b612143565b3461029857602036600319011261029857602061048f6004356121d7565b604051908152f35b346102985760031960203682011261029857600435906001600160401b038211610298576080908236030112610298576104d66104dd91600401612c56565b9190612dec565b6104e357005b610018612f76565b6001600160a01b0381160361029857565b3461029857606036600319011261029857600435610519816104eb565b602435906044359061052a826104eb565b6105326130a6565b61053a613132565b6040516329460cc560e11b81526001600160a01b0382811660048301526024820185905290926020917f00000000000000000000000000000000000000000000000000000000000000001682856044815f855af194851561046c575f9561073c575b50335f908152610137602052604090206105b59061214e565b926001600160801b036105cf85516001600160801b031690565b16156106d85750506105e0826128d5565b61060c6105ff6105ef876131bd565b84516001600160801b03166121fd565b6001600160801b03168352565b335f908152609c6020526040902061062e90610629905b546121d7565b61324c565b61064e61064284516001600160801b031690565b6001600160801b031690565b116106c657335f90815261013760205260409020610427957fa16d97739893e1436c9753925fb5cef174c4f368699dc86cc8fdb0e6e60f8e5893909161069491906121a5565b604080516001600160a01b03958616815260208101879052908101919091529216606083015233918060808101610414565b604051633684c65960e01b8152600490fd5b806004926040519384809263752a536d60e01b82525afa91821561046c5761071a9261070b915f9161071f575b506131bd565b6001600160801b031690840152565b6105e0565b6107369150833d85116104655761045781836112c0565b5f610705565b610754919550833d85116104655761045781836112c0565b935f61059c565b60609060031901126102985760043590602435610777816104eb565b90604435610784816104eb565b90565b34610298576107953661075b565b906001600160a01b0380831615610c11576107ae613132565b807f00000000000000000000000000000000000000000000000000000000000000001691823b156102985760408051631d8557d760e01b815260049491905f81878183875af1801561046c57610bf8575b506001600160a01b0383165f908152610137602052604090206108219061214e565b6001600160801b03928361083c83516001600160801b031690565b1615610be85761084b826128d5565b825163e48a5f7b60e01b8152308882019081529097906060908990819060200103818a7f0000000000000000000000000000000000000000000000000000000000000000165afa97881561046c575f98610bb7575b50602097888101956001600160401b039182806108c48a516001600160401b031690565b1614610ba757908c92918751918c83806108f06303d1689d60e11b988983528a83019190602083019252565b03818a5afa91821561046c5761091c938e5f94610b82575b5050516001600160801b03165b1690612a04565b9661093a6106238a60018060a01b03165f52609c60205260405f2090565b928389118015610b72575b610b6257908b610983939261096189516001600160801b031690565b908a51958692839283528983019190916001600160801b036020820193169052565b0381895afa91821561046c57670de0b6b3a7640000946109d2948e5f95610b35575b50506109c46109b66109ca926125aa565b93516001600160401b031690565b936125aa565b921690612afd565b1015610b27578351633b9e9f0160e21b815233918101918252602082018b905294939291889186919082905f90829060400103925af190811561046c577f61fd285f9e34a3dbfa9846bdcf22a023e37a3c93549902843b30dd74a18c535097610b0495610a7c93610b09575b5050610a5f6103b3610a4f8c6131bd565b83516001600160801b0316612187565b6001600160a01b0386165f908152610137602052604090206121a5565b610a8582614338565b90610ac3610aa8610a95856131bd565b60985460801c036001600160801b031690565b6001600160801b036098549181199060801b16911617609855565b610acd82866145f8565b610ad78389614253565b51948594169733978590949392606092608083019660018060a01b03168352602083015260408201520152565b0390a3005b81610b1f92903d106104655761045781836112c0565b505f80610a3e565b835163185cfc6d60e11b8152fd5b6109ca929550610b586109c492826109b693903d106104655761045781836112c0565b959250508e6109a5565b875163efda1a2760e01b81528590fd5b50610b7b612218565b8911610945565b6109159294509081610b9f92903d106104655761045781836112c0565b92908e610908565b8651630709133160e01b81528490fd5b610bda91985060603d606011610be1575b610bd281836112c0565b810190613204565b965f6108a0565b503d610bc8565b825163673f032f60e11b81528790fd5b80610c05610c0b9261125c565b8061028e565b5f6107ff565b60405163d92e233d60e01b8152600490fd5b34610298575f36600319011261029857602061048f612218565b3461029857610c4b3661075b565b91610c5461375d565b604092610cae84516323b872dd60e01b602082015233602482015230604482015283606482015260648152610c888161128a565b7f0000000000000000000000000000000000000000000000000000000000000000614645565b610cb6613132565b6001600160a01b038316928315610d9a578215610d895782610cdd61064260985460801c90565b0190610ce76122a5565b8211610d7857610d5e610aa89593610d3886947f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c94610d33610d2b60209c9a6143be565b9a8b936131bd565b614467565b8551938452602084018790526001600160a01b0316604084015233929081906060820190565b0390a360015f80516020614d9a8339815191525551908152f35b85516304ffa0ff60e51b8152600490fd5b84516318374fd160e21b8152600490fd5b845163d92e233d60e01b8152600490fd5b34610298575f366003190112610298576020610dc5612255565b6040516001600160a01b039091168152f35b34610298575f3660031901126102985760206040517f92db5a150616972630ec6ff109fcce78f8559cc5594d540f16cd3cfa3fc86bcc8152f35b34610298575f3660031901126102985760206001600160801b0360985416604051908152f35b9181601f84011215610298578235916001600160401b038311610298576020838186019501011161029857565b602060031982011261029857600435906001600160401b03821161029857610e8e91600401610e37565b9091565b3461029857610ea036610e64565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549160409260ff81851c168015611079575b6110685768ffffffffffffffffff191668010000000000000002179055815163e7f6f22560e01b8152926020918285600481335afa94851561046c575f95611049575b508351636f4fa30f60e01b8152908382600481335afa91821561046c575f9261101a575b5082019483838703126102985782356001600160401b039384821161029857019260608488031261029857855193610f738561126f565b803585528581013561ffff8116810361029857868601528681013591821161029857019386601f86011215610298577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29685610fd592610fde9735910161130b565b858401526137d7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff0000000000000000191690555160028152602090a1005b61103b919250843d8611611042575b61103381836112c0565b810190612290565b905f610f3c565b503d611029565b611061919550833d85116110425761103381836112c0565b935f610f18565b835163f92ee8a960e01b8152600490fd5b5060026001600160401b0382161015610ed5565b346102985761109b3661075b565b60405163057453a760e31b81529091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa801561046c5782915f9161116b575b501633036111595781610b0461112686867f57f5eb636bf62215c111b54545422f11dfb0cb115f606be905f0be08e8859dd396613356565b604080516001600160a01b0390981688526020880198909852968601526060850195909552169233929081906080820190565b604051634ca8886760e01b8152600490fd5b611184915060203d6020116110425761103381836112c0565b5f6110ee565b34610298575f366003190112610298576065546040516001600160a01b039091168152602090f35b34610298576020366003190112610298576004356111cf816104eb565b60018060a01b03165f52610137602052602060405f20604051906111f28261123c565b54906001600160801b03918281169081835260801c8483015261121a575b5116604051908152f35b611223816128d5565b611210565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761125757604052565b611228565b6001600160401b03811161125757604052565b606081019081106001600160401b0382111761125757604052565b60a081019081106001600160401b0382111761125757604052565b608081019081106001600160401b0382111761125757604052565b90601f801991011681019081106001600160401b0382111761125757604052565b604051906112ee8261123c565b565b6001600160401b03811161125757601f01601f191660200190565b929192611317826112f0565b9161132560405193846112c0565b829481845281830111610298578281602093845f960137010152565b60408060031936011261029857600490813561135c816104eb565b6024356001600160401b03811161029857366023820112156102985761138b903690602481870135910161130b565b916113946138bf565b8051926113cb846113bd60209363439fab9160e01b858401528460248401526044830190611eab565b03601f1981018652856112c0565b6113d36138bf565b6113db61399f565b6001600160a01b03838116801592919087908415611592575b8415611524575b84156114c0575b5050821561142a575b505061141b576100188383614880565b516355299b4960e01b81528390fd5b83516345da87c560e01b81526001600160a01b03861688820190815292935091839183918290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa91821561046c575f92611493575b5050155f8061140b565b6114b29250803d106114b9575b6114aa81836112c0565b81019061239a565b5f80611489565b503d6114a0565b855163054fd4d560e41b81529294508391839182905afa90811561046c5760039160ff915f916114f7575b5016141591865f611402565b6115179150843d861161151d575b61150f81836112c0565b810190614867565b5f6114eb565b503d611505565b935050835163198ca60560e11b815282818981875afa90811561046c5788917f92db5a150616972630ec6ff109fcce78f8559cc5594d540f16cd3cfa3fc86bcc915f91611575575b501415936113fb565b61158c9150853d87116104655761045781836112c0565b5f61156c565b5f80516020614d7a8339815191525490945084906115c0906001600160a01b03165b6001600160a01b031690565b14936113f4565b34610298575f366003190112610298577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361161e5760206040515f80516020614d7a8339815191528152f35b60405163703e46dd60e11b8152600490fd5b34610298575f36600319011261029857602060405160028152f35b34610298575f366003190112610298575f80516020614d7a833981519152546040516001600160a01b039091168152602090f35b34610298575f36600319011261029857602061048f6122a5565b3461029857602036600319011261029857602061048f6004356122ce565b34610298575f36600319011261029857604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561046c576020915f91611727575b506040519015158152f35b61173e9150823d84116114b9576114aa81836112c0565b5f61171c565b3461029857602036600319011261029857600435611761816104eb565b61176961399f565b60d280546001600160a01b0319166001600160a01b03929092169182179055337f6bdc78d8c88160b3fc3638e67f2afe523b3f4c7d00c56ebb6216790e4c3eb2cb5f80a3005b34610298576080366003190112610298576104276117e36004356117d2816104eb565b6064359060443590602435906123bb565b604080519384526020840192909252908201529081906060820190565b34610298575f36600319011261029857602061ffff60655460a01c16604051908152f35b34610298576003196040368201126102985760049081356001600160401b038082116102985760a082850193833603011261029857602435908111610298576118709036908501610e37565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116803b156102985760405163837d444160e01b8152905f9082908183816118c38c828f016124bf565b03925af1801561046c576119e1575b506118db613132565b6118e361289f565b90811633141591826119b2575b505090506119a1576044019160b0611908848461253d565b90500480158015611989575b61197957611929611923612218565b91612592565b1161196a575060b061193b838361253d565b9050145f1461195757610018916119519161253d565b906140f4565b610018916119649161253d565b90613ec4565b6040516396d8043360e01b8152fd5b50604051631c6c4cf360e31b8152fd5b50611994848461253d565b905060b082021415611914565b604051634ca8886760e01b81528390fd5b6119d592506119cf6119d9946119c788613bcd565b92369161130b565b91613ca7565b1590565b805f806118f0565b80610c056119ee9261125c565b5f6118d2565b3461029857606036600319011261029857600435602435611a196044358284336123bb565b9192611a457f0000000000000000000000000000000000000000000000000000000000000000826122c1565b42108015611c47575b8015611c3f575b611c2d577feb3b05c070c24f667611fdb3ff75fe007d42401c573aed8d8faca95fd00ccb5693611a9986611a946106426099546001600160801b031690565b613918565b15611b9b57611ad3611ab8611aad866131bd565b60995460801c612187565b6001600160801b036099549181199060801b16911617609955565b60408051336020820190815291810184905260608082018990528152601f1993915f91611b179190611b066080826112c0565b5190205f52609b60205260405f2090565b555f9360018311611b50575b50505050611b318233614253565b604080519485526020850191909152830152339180606081015b0390a2005b611b9192939450611b6190886122c1565b6040805133602082019081529181019390935260608301829052608095860183529094909190611b0690826112c0565b555f808080611b23565b611ba3613132565b611bdf611bc3611bb2866131bd565b609e546001600160801b0316612187565b6001600160801b03166001600160801b0319609e541617609e55565b611c14611bf9611bee856131bd565b609e5460801c612187565b6001600160801b03609e549181199060801b16911617609e55565b611c28611c2384609f546122c1565b609f55565b611ad3565b604051630e3d8e8d60e11b8152600490fd5b508215611a55565b508115611a4e565b34610298576040806003193601126102985760243590600435611c71836104eb565b611c79613132565b8015611e27576001600160a01b038316908115611e1657611c99816121d7565b908115611e0557611ca98261496d565b611cb2836131bd565b60985460801c90611cc291612187565b611ce1906001600160801b036098549181199060801b16911617609855565b611ceb82336145f8565b609e54958660801c8281609f5490611d02916122c1565b98611d0c876131bd565b611d1e916001600160801b03166121fd565b611d3e906001600160801b03166001600160801b0319609e541617609e55565b611d47916122c1565b611d50906131bd565b611d6f906001600160801b03609e549181199060801b16911617609e55565b85516001600160a01b0391909116602082019081524260408301526060808301899052825290611da06080826112c0565b519020611db5905f52609b60205260405f2090565b5583518581526020810191909152604081019190915233907f869f12645d154414259c47bcb998b6b6983fae50e5e0c6053bc87d4330db9f2d90606090a3611dfc33614b39565b51908152602090f35b83516318374fd160e21b8152600490fd5b825163d92e233d60e01b8152600490fd5b8151636edcc52360e01b8152600490fd5b3461029857611b4b7f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf611e6a36610e64565b9290611e7461399f565b604051918291602083523395602084019161249f565b5f5b838110611e9b5750505f910152565b8181015183820152602001611e8c565b90602091611ec481518092818552858086019101611e8a565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310611f055750505050505090565b9091929394958480611f23600193603f198682030187528a51611eab565b9801930193019194939290611ef5565b34610298576020366003190112610298576001600160401b036004358181116102985736602382011215610298578060040135918211610298573660248360051b8301011161029857610427916024611f8c9201612705565b60405191829182611ed0565b906020610784928181520190611eab565b34610298575f36600319011261029857610427604051611fc88161123c565b60058152640352e302e360dc1b6020820152604051918291602083526020830190611eab565b34610298575f3660031901126102985761200661375d565b61200e6127b2565b60015f80516020614d9a83398151915255005b34610298575f366003190112610298576020610dc561289f565b3461029857602036600319011261029857602061048f600435614338565b34610298575f3660031901126102985760206001600160801b0360995416604051908152f35b346102985760203660031901126102985761001860043561209f816104eb565b6120a761399f565b614405565b34610298575f3660031901126102985760206001600160801b03609e5416604051908152f35b34610298576020366003190112610298576004356120ef816104eb565b60018060a01b03165f52609c602052602060405f2054604051908152f35b34610298575f366003190112610298575f546040516001600160a01b039091168152602090f35b90816020910312610298575190565b6040513d5f823e3d90fd5b9060405161215b8161123c565b91546001600160801b038116835260801c6020830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b0391821690821603919082116121a057565b612173565b815160209092015160801b6fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055565b6098546001600160801b03811690816121ef57505090565b916107849260801c90612afd565b9190916001600160801b03808094169116019182116121a057565b61222061366f565b6099546001600160801b036122368183166121d7565b90609e5416019060801c01908181115f1461224f570390565b50505f90565b61016a546001600160a01b0316801561226b5790565b507f000000000000000000000000000000000000000000000000000000000000000090565b908160209103126102985751610784816104eb565b609d548061078457505f1990565b9060b082018092116121a057565b919082018092116121a057565b6001600160801b03609954166122e261492b565b9081018091116121a057811061231557612306609f5461230061392f565b906122c1565b1115612310575f90565b5f1990565b609a90609a549182915f905b84821061233b575050508110156123355790565b505f1990565b909193808316906001818518811c83018093116121a0575f8790525f80516020614d5a8339815191528301546001600160a01b0316841015612382575050935b9190612321565b90959101925061237b565b5190811515820361029857565b90816020910312610298576107849061238d565b919082039182116121a057565b604080516001600160a01b039092166020830190815290820193909352606081018290529091906123f981608081015b03601f1981018352826112c0565b5190205f52609b60205260405f2054918215612463576001600160801b03609954169061242461492b565b9182018092116121a0578391831015612451579161244192613a32565b90915b8281039081116121a05792565b509061245c916139b2565b9091612444565b5050505f905f905f90565b9035601e19823603018112156102985701602081359101916001600160401b03821161029857813603831361029857565b908060209392818452848401375f828201840152601f01601f1916010190565b9060a0610784926020815282356020820152602083013560408201526124fb6124eb604085018561246e565b84606085015260c084019161249f565b9061252e61252361250f606087018761246e565b601f1985870381016080870152959161249f565b94608081019061246e565b9390928286030191015261249f565b903590601e198136030182121561029857018035906001600160401b0382116102985760200191813603831361029857565b634e487b7160e01b5f52601260045260245ffd5b811561258d570490565b61256f565b90670de0b6b3a764000091808302928304036121a057565b90670de0b6b3a7640000918281029281840414901517156121a057565b6001600160401b0381116112575760051b60200190565b906125e8826125c7565b6125f560405191826112c0565b8281528092612606601f19916125c7565b01905f5b82811061261657505050565b80606060208093850101520161260a565b634e487b7160e01b5f52603260045260245ffd5b9082101561265257610e8e9160051b81019061253d565b612627565b908092918237015f815290565b3d1561268e573d90612675826112f0565b9161268360405193846112c0565b82523d5f602084013e565b606090565b602081830312610298578051906001600160401b038211610298570181601f820112156102985780516126c5816112f0565b926126d360405194856112c0565b81845260208284010111610298576107849160208085019101611e8a565b80518210156126525760209160051b010190565b919091612711836125de565b925f5b81811061272057505050565b5f8061272d83858761263b565b6040939161273f855180938193612657565b0390305af49061274d612664565b911561277457509060019161276282886126f1565b5261276d81876126f1565b5001612714565b906044815110610298576127ae61279960049283810151602480918301019101612693565b925162461bcd60e51b81529283928301611f98565b0390fd5b47633b9aca00811061289c57604051638119c06560e01b815290602082600481847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af191821561046c575f9261287b575b506001600160ff1b03821161286257907f07554795962e1f72c5bca846be8a8f44143aa1b4ced204ffc7899be95e7040db9161284882612dec565b60408051918252602082019290925290819081015b0390a1565b60405163123baf0360e11b815260048101839052602490fd5b61289591925060203d6020116104655761045781836112c0565b905f61280d565b50565b60d2546001600160a01b03168061078457507f000000000000000000000000000000000000000000000000000000000000000090565b60405163752a536d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561046c575f9161296b575b5060208201916001600160801b03918284511691828214612964578361295761295261295f958584865116612afd565b6131bd565b1690526131bd565b169052565b5050505050565b612984915060203d6020116104655761045781836112c0565b5f612922565b90808202905f19818409908280831092039180830392146129f95761271090828211156129e7577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b60405163227bc15360e01b8152600490fd5b505061271091500490565b90808202905f1981840990828083109203918083039214612a6757670de0b6b3a764000090828211156129e7577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b90633b9aca0080830291905f1984820993838086109503948086039514612af057848311156129e757829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b5050906107849250612583565b9091828202915f1984820993838086109503948086039514612af057848311156129e757829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b908160609103126102985780519161078460406020840151930161238d565b81835290916001600160fb1b0383116102985760209260051b809284830137010190565b90602082528035602083015260208101358060130b8091036102985760408301526040810135612be2816104eb565b6001600160a01b031660608381019190915281013536829003601e19018112156102985701602081359101906001600160401b038111610298578060051b360382136102985760a0836080806107849601520191612b8f565b9190915f83820193841291129080158216911516176121a057565b6040516325f56f1160e01b81526001600160a01b03929160609082908190612c819060048301612bb3565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af192831561046c575f915f905f95612da7575b508415612d545781612ccb612255565b16917f0000000000000000000000000000000000000000000000000000000000000000168214612d4d57509060205f92600460405180958193634641257d60e01b83525af190811561046c57612d28925f92612d2c575b50612c3b565b9190565b612d4691925060203d6020116104655761045781836112c0565b905f612d22565b9081612d5a575b50509190565b803b1561029857604051636ee3193160e11b815260048101929092525f908290602490829084905af1801561046c57612d94575b80612d54565b80610c05612da19261125c565b5f612d8e565b91945050612dcd915060603d606011612dd5575b612dc581836112c0565b810190612b70565b93905f612cbb565b503d612dbb565b600160ff1b81146121a0575f0390565b801561289c57612e0161064260985460801c90565b5f8212612ed35781612e12916122c1565b90612e1f610aa8836131bd565b612e346065549161ffff8360a01c169061298a565b8015612ece57807f555ee6b2ef9506d870f386c067e47d3689435330b012ad263d8cc3531868654793612e726106426098546001600160801b031690565b80612eb857505061285d90925b6001600160a01b031691612e938484614467565b60405193849384604091949392606082019560018060a01b0316825260208201520152565b61285d92612ec892039084612afd565b92612e7f565b505050565b90612edd90612ddc565b612ef2610642609e546001600160801b031690565b80612f12575b5080612f02575050565b612952610aa8916112ee936123ae565b90612f6d7f3623a54e8078be0d90ecfbef82da6a31ff3e6be8aa1718e7a7f3d0d33ff1d32a91612f5d611bc3612f52612f4b88886122c1565b8785612afd565b8080940396036131bd565b6040519081529081906020820190565b0390a15f612ef8565b609954906001600160801b0382169182156130a05760801c612fb1612fa282612f9d61366f565b6123ae565b612fab856121d7565b906144b3565b90811561309957612fc182614338565b938415613091578261300e611ab86129526112ee96610aa896613009612fed6129528d6130869a6123ae565b6001600160801b03166001600160801b03196099541617609955565b6122c1565b6130188187614523565b60408051878152602081018390527f624ea167e477f9d39f7f4094b9dfe2e6346eb4a7aada54338db51abd554c4b9f9190a161295261306a613059886131bd565b6098546001600160801b0316612187565b6001600160801b03166001600160801b03196098541617609855565b60985460801c612187565b505f93505050565b505f925050565b505f9150565b604051630156a69560e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561046c575f91613113575b501561310157565b604051630a62fbdb60e11b8152600490fd5b61312c915060203d6020116114b9576114aa81836112c0565b5f6130f9565b604051633eb1acf760e11b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561046c575f9161319e575b5061318c57565b60405163e775715160e01b8152600490fd5b6131b7915060203d6020116114b9576114aa81836112c0565b5f613185565b6001600160801b03908181116131d1571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b51906001600160401b038216820361029857565b908160609103126102985761324460408051926132208461126f565b805161322b816102bc565b8452613239602082016131f0565b6020850152016131f0565b604082015290565b60405163e48a5f7b60e01b81523060048201526001600160a01b036060826024817f000000000000000000000000000000000000000000000000000000000000000085165afa801561046c576132e7936001600160401b0361091560406132c6946020975f91613337575b5001516001600160401b031690565b9060405180809581946363737ac960e11b8352600483019190602083019252565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa90811561046c575f9161331e575090565b610784915060203d6020116104655761045781836112c0565b613350915060603d606011610be157610bd281836112c0565b5f6132b7565b92906001600160a01b039081811615610c1157613371613132565b817f00000000000000000000000000000000000000000000000000000000000000001690813b1561029857604094855193631d8557d760e01b85526004945f81878183895af1801561046c5761365c575b506001600160a01b0388165f908152610137602052604090206133e49061214e565b906001600160801b036133fe83516001600160801b031690565b161561364c5761340d826128d5565b875163e48a5f7b60e01b81523087820190815290916060918391908290819060200103917f0000000000000000000000000000000000000000000000000000000000000000165afa801561046c5761362d575b508651936303d1689d60e11b97888652602091828780613487888c83019190602083019252565b0381845afa96871561046c575f9761360e575b5086996134ba6106238d60018060a01b03165f52609c60205260405f2090565b881180156135fe575b6135ee579083613500926134de87516001600160801b031690565b908551948592839283528d83019190916001600160801b036020820193169052565b0381845afa98891561046c575f859488946135459c6135d1575b5051633b9e9f0160e21b815233928101928352602083019490945292998a9384929091839160400190565b03925af195861561046c57610a4f61358c9461356f936103b3936112ee9a6135b3575b50506131bd565b6001600160a01b0388165f908152610137602052604090206121a5565b6135ae61359883614338565b80976135a9610aa8610a95876131bd565b6145f8565b614253565b816135c992903d106104655761045781836112c0565b505f80613568565b6135e790873d89116104655761045781836112c0565b505f61351a565b825163efda1a2760e01b81528990fd5b50613607612218565b88116134c3565b613626919750833d85116104655761045781836112c0565b955f61349a565b6136459060603d606011610be157610bd281836112c0565b505f613460565b875163673f032f60e11b81528690fd5b80610c056136699261125c565b5f6133c2565b6040516370a0823160e01b81523060048201526020906001600160a01b039082816024817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561046c575f91613740575b5060405163be7ab51b60e01b8152306004820152918390839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa91821561046c57610784935f93613721575b50506122c1565b613738929350803d106104655761045781836112c0565b905f8061371a565b6137579150833d85116104655761045781836112c0565b5f6136c6565b5f80516020614d9a833981519152600281541461377a5760029055565b604051633ee5aeb560e01b8152600490fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152919092166044820152633b9aca0060648083019190915281526112ee916137d28261128a565b614645565b6137df6146b6565b60408301516137ec6146b6565b6001600160a01b0382168015610c11576001600160601b0360a01b5f5416175f557f2013570c343af8ab14a9778150e381a0fda34ed6368127a95fd5e7210cbec5bf604051602081528061384533946020830190611eab565b0390a26020830151926138566146b6565b61271061ffff8516116138ad576138a59361387361389893614405565b6065805461ffff60a01b191660a09290921b61ffff60a01b16919091179055516146f7565b6138a0614727565b614752565b6112ee614781565b604051638a81d3b360e01b8152600490fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149182156138fd575b505061161e57565b5f80516020614d7a8339815191525416141590505f806138f5565b9061392161492b565b9182018092116121a0571090565b61393761366f565b6099548060801c82039182116121a0578161395b6001600160801b038093166121d7565b9081613981575b5050811561224f576107849161397c91609e5416906144b3565b61496d565b919250908181111561399757035b905f80613962565b50505f61398f565b5f546001600160a01b0316330361115957565b6139ba61392f565b91609f549283018093116121a05780831115613a04576139db9203906144b3565b90609e548060801c80155f146139f15750508190565b6001600160801b03610784921684612afd565b5050505f905f90565b90604051613a1a8161123c565b91546001600160a01b038116835260a01c6020830152565b609a545f948594939091808410801590613bc5575b613bb85783613b82575f5b609a5f526001600160a01b0316613a775f80516020614d5a8339815191528601613a0d565b8051909790613a8e906001600160a01b03166115b4565b98613ab3613aa76020809b01516001600160601b031690565b6001600160601b031690565b948381108015613b78575b613b665791600193979a95613add613ae9939488035b838c03906144b3565b80920198870391612afd565b01970193808611801590613b5c575b613b5157609a5f528290613b1a5f80516020614d5a8339815191528701613a0d565b805190890151969992966001600160a01b039091169460019392613ae99290916001600160601b0390911690613add908803613ad4565b945050509250509190565b5081851015613af8565b60405163e8722f8f60e01b8152600490fd5b50808b1115613abe565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be38401546001600160a01b0316613a52565b505093505050505f905f90565b508415613a47565b604290467f000000000000000000000000000000000000000000000000000000000000000003613c7b5760d354905b613c13613c0c604083018361253d565b369161130b565b602081519101206040519060208201927f838af86bfca91ada6557e38d913af1c2f24ef9b2567b3b77cc9e1144314b35b08452356040830152606082015260608152613c5e816112a5565b5190206040519161190160f01b8352600283015260228201522090565b613c836149a4565b90613bfc565b60041115613c9357565b634e487b7160e01b5f52602160045260245ffd5b613cb18383614a71565b50613cbe81959295613c89565b159384613d5a575b508315613cd4575b50505090565b5f929350908291604051613d0c816123eb6020820194630b135d3f60e11b998a87526024840152604060448401526064830190611eab565b51915afa90613d19612664565b82613d4c575b82613d2f575b50505f8080613cce565b613d4491925060208082518301019101612134565b145f80613d25565b915060208251101591613d1f565b6001600160a01b0383811691161493505f613cc6565b90613d7a826125c7565b613d8760405191826112c0565b8281528092613d98601f19916125c7565b0190602036910137565b906030116102985790603090565b906090116102985760300190606090565b9060b0116102985760900190602090565b90939293848311610298578411610298578101920390565b602090836112ee939594956040519683613e0d8995518092888089019101611e8a565b84019185830137015f838201520380855201836112c0565b359060208110613e33575090565b5f199060200360031b1b1690565b91602061078493818152019161249f565b9192613e7c613e6c613e8a93608086526080860190611eab565b6020958582036020870152611eab565b908382036040850152611eab565b906060818303910152602080845192838152019301915f5b828110613eb0575050505090565b835185529381019392810192600101613ea2565b613ecc614aab565b6060906060905f809460b0810492613ee384613d70565b965f905b85821061400257506001600160a01b03947f00000000000000000000000000000000000000000000000000000000000000009450613f5e935060209250613f2e9150612592565b60405163095ea7b360e01b81526001600160a01b0385166004820152602481019190915291829081906044820190565b03815f877f0000000000000000000000000000000000000000000000000000000000000000165af1801561046c57613fe3575b5016613f9b614b10565b813b15610298575f8094613fc56040519788968795869463c82655b760e01b865260048601613e52565b03925af1801561046c57613fd65750565b80610c056112ee9261125c565b613ffb9060203d6020116114b9576114aa81836112c0565b505f613f91565b61408761405761406261404461403b7f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb1959c9b9c6122b3565b80998989613dd2565b92909a614051848d613da2565b91613dea565b9a614051838c613db0565b988b6140818661407b6140758686613dc1565b90613e25565b926126f1565b52613da2565b9061409760405192839283613e41565b0390a160010183613ee7565b92946140dc670de0b6b3a7640000966140ce608097946140ea969b9a9b60a0895260a089019161249f565b908682036020880152611eab565b91848303604086015261249f565b9460608201520152565b906140fd614aab565b6141078183613da2565b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152670de0b6b3a76400006024840152929492916020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af1801561046c57614234575b501690614199614b10565b916141b26140756141aa8489613db0565b949098613dc1565b95813b15610298575f80946141df604051998a9687958694630cac9f3160e01b86528c8c600488016140a3565b03925af192831561046c577f64b6e61d93b7a91e8cc4376183ede0997a27b44fd9dd2f30a866b2a5730efdb193614221575b5061285d60405192839283613e41565b80610c0561422e9261125c565b5f614211565b61424c9060203d6020116114b9576114aa81836112c0565b505f61418e565b9061425c61375d565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa93841561046c576142f6946137d2925f91614319575b50841161430c575b60405163a9059cbb60e01b60208201526001600160a01b039190911660248201526044808201949094529283526064836112c0565b6112ee60015f80516020614d9a83398151915255565b614314614aab565b6142c1565b614332915060203d6020116104655761045781836112c0565b5f6142b9565b609854906001600160801b03821681158015614367575b1561435a5750905090565b6107849260801c91612afd565b50801561434f565b6098546001600160801b038116908161438c575050633b9aca0090565b60801c6143998183612a78565b91811561258d57633b9aca00096143ad5790565b600181018091111561078457612173565b6098546001600160801b03811690821580156143fd575b156143df57505090565b60801c906143ee828285612afd565b92821561258d57096143ad5790565b5081156143d5565b61440d613132565b6001600160a01b0316801561445557606580546001600160a01b03191682179055337faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d35f80a3565b604051630ed1b8b360e31b8152600490fd5b614470826131bd565b609854906144886001600160801b03918284166121fd565b16906001600160801b0319161760985560018060a01b03165f52609c60205260405f20908154019055565b90808210156144c0575090565b905090565b609a549068010000000000000000821015611257576001820180609a5582101561265257609a5f52805160209091015160a01b6001600160a01b0319166001600160a01b0391909116175f80516020614d5a83398151915290910155565b919091801580156145f0575b6145de5761453b61492b565b9081018091116121a0576001600160a01b038082116145be576001600160601b039081851161459e57906112ee9394614588614599936145796112e1565b95166001600160a01b03168552565b166001600160601b03166020830152565b6144c5565b6040516306dfcc6560e41b81526060600482015260248101869052604490fd5b6040516306dfcc6560e41b815260a0600482015260248101839052604490fd5b604051632ec8835b60e21b8152600490fd5b50821561452f565b60018060a01b03165f52609c60205260405f209081548181039081116121a05761462292556131bd565b609854906001600160801b03908183160316906001600160801b03191617609855565b5f8061466d9260018060a01b03169360208151910182865af1614666612664565b9083614cf6565b805190811515918261469b575b50506146835750565b60249060405190635274afe760e01b82526004820152fd5b6146ae925060208091830101910161239a565b155f8061467a565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156146e557565b604051631afcd79f60e31b8152600490fd5b6146ff6146b6565b801561471557600181016147105750565b609d55565b6040516331278a8760e01b8152600490fd5b61472f6146b6565b670de0b6b3a76400006147406122a5565b106147155761474d6149a4565b60d355565b61475a6146b6565b6001600160a01b03168061476b5750565b61016a80546001600160a01b0319169091179055565b6147896146b6565b6147916146b6565b6147996146b6565b60015f80516020614d9a833981519152556147b2613132565b3015610c1157633b9aca008060985460801c016147cd6122a5565b8111614855576147e7610aa86147e161436f565b926131bd565b6147f18130614467565b60405191825260208201525f604082015230907f861a4138e41fb21c121a7dbb1053df465c837fc77380cc7226189a662281be2c60603392a36112ee30337f000000000000000000000000000000000000000000000000000000000000000061378c565b6040516304ffa0ff60e51b8152600490fd5b90816020910312610298575160ff811681036102985790565b6040516352d1902d60e01b81529290916020846004816001600160a01b0387165afa5f948161490a575b506148d057604051634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b90915f80516020614d7a83398151915284036148f1576112ee929350614bb9565b604051632a87526960e21b815260048101859052602490fd5b61492491955060203d6020116104655761045781836112c0565b935f6148aa565b609a548061493857505f90565b609a5f527f44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be301546001600160a01b03166115b4565b609e54908160801c8115801561499c575b156149895750905090565b6001600160801b03610784931691612afd565b50801561497e565b6e5661756c7456616c696461746f727360881b60206040516149c58161123c565b600f8152015260405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f35d6cf9768d8be929c3a11ed667b1560ae6f1920195a985758fdd7265505d1ca60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c081018181106001600160401b038211176112575760405251902090565b8151919060418303614aa157614a9a9250602082015190606060408401519301515f1a90614c5b565b9192909190565b50505f9160029190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610298575f809160246040518094819363a3066aab60e01b83523060048401525af1801561046c57614b075750565b6112ee9061125c565b604051600160f81b60208201525f60218201523060601b602c820152602081526107848161123c565b60018060a01b0381165f5261013760205260405f209060405191614b5c8361123c565b54906001600160801b03918281169081855260801c602085015215612ece57610629610623614baf92614b8d613132565b614b96866128d5565b6001600160a01b03165f908152609c6020526040902090565b915116116106c657565b90813b15614c3a575f80516020614d7a83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2805115614c1f5761289c91614cdd565b505034614c2857565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614cd2579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1561046c575f516001600160a01b03811615614cc857905f905f90565b505f906001905f90565b5050505f9160039190565b5f8061078493602081519101845af4614cf4612664565b915b90614d1d5750805115614d0b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614d50575b614d2e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614d2656fe44da158ba27f9252712a74ff6a55c5d531f69609f1f6e7f17c4443a8e2089be4360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220aa0ce264a9718bea85c45b437146008c0488db5f4a0d4ef1f521b857be74f98a64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/artifacts/GnoVaultFactory.json b/test/shared/artifacts/GnoVaultFactory.json deleted file mode 100644 index efe133f8..00000000 --- a/test/shared/artifacts/GnoVaultFactory.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "GnoVaultFactory", - "sourceName": "contracts/vaults/gnosis/GnoVaultFactory.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_implementation", - "type": "address" - }, - { - "internalType": "contract IVaultsRegistry", - "name": "vaultsRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "gnoToken", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "vault", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "ownMevEscrow", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "params", - "type": "bytes" - } - ], - "name": "VaultCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "params", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "isOwnMevEscrow", - "type": "bool" - } - ], - "name": "createVault", - "outputs": [ - { - "internalType": "address", - "name": "vault", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ownMevEscrow", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vaultAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x60e0346100a657601f610c7a38819003918201601f19168301916001600160401b038311848410176100aa578084926060946040528339810103126100a657610047816100be565b60208201516001600160a01b039283821682036100a657604061006a91016100be565b9160c0526080521660a052604051610ba790816100d382396080518161029d015260a05181610125015260c0518181816101be01526104e60152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100a65756fe6080604081815260049182361015610015575f80fd5b5f925f3560e01c9182635c60da1b146104d4575081636f4fa30f146104ad5781639a0d79ad14610079575063e7f6f2251461004e575f80fd5b3461007557816003193601126100755760015490516001600160a01b039091168152602090f35b5080fd5b9190503461039757806003193601126103975781359067ffffffffffffffff808311610397573660238401121561039757828401359080821161039757602493848101908584369201011161039757843590811515820361039757845197602096878a01946323b872dd60e01b865233828c01523060448c0152633b9aca008060648d015260648c5260a08c018c81108382111761049b575f809b9c9d81928c5260018060a01b03998a7f0000000000000000000000000000000000000000000000000000000000000000169d8e9251925af13d1561048f573d83811161047d57610186918d918c519061017684601f19601f840116018361053d565b81525f81933d92013e5b8c610597565b8051908c8215159283610464575b50505061044e5788516102c8808201908282108583111761043b576060918c8f85936105fb85398c7f00000000000000000000000000000000000000000000000000000000000000001683528201525f8d8201520301905ff08015610431578960448e5f8f948c169e8f9451968795869463095ea7b360e01b8652850152898401525af180156104315790869291610404575b505f9561039b575b506bffffffffffffffffffffffff60a01b9033826001541617600155893b1561039757845f898c8f8f9084908f61027e90519788968795869463439fab9160e01b86528501528c840191610577565b03925af1801561038d5761037a575b5061036f575b60015416600155847f000000000000000000000000000000000000000000000000000000000000000016998a3b1561036b5782918991838a519d8e9485936312b5ad0160e11b85528401525af198891561035f5787989997969761033c575b5050906103337f0d606510f33b5e566ed1ca2b9e88d388ab81cea532909665d725b33134516aff93928751938493168352878a840152339588840191610577565b0390a351908152f35b8192939495965061034c90610515565b61035c57908187959493926102f2565b80fd5b508551903d90823e3d90fd5b8280fd5b808354168355610293565b610385919450610515565b5f925f61028d565b8a513d5f823e3d90fd5b5f80fd5b88519195506102af808301918211838310176103f2578b9183916108c383398b81520301905ff080156103e857851693846bffffffffffffffffffffffff60a01b5f5416175f555f61022f565b87513d5f823e3d90fd5b8360418e634e487b7160e01b5f52525ffd5b610423908c8d3d1061042a575b61041b818361053d565b81019061055f565b505f610227565b503d610411565b89513d5f823e3d90fd5b508460418f634e487b7160e01b5f52525ffd5b8851635274afe760e01b8152808d018b90528390fd5b610474935082018101910161055f565b155f8c81610194565b8460418f634e487b7160e01b5f52525ffd5b61018690606090610180565b8360418d634e487b7160e01b5f52525ffd5b8234610397575f366003190112610397575f5490516001600160a01b039091168152602090f35b34610397575f366003190112610397577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b67ffffffffffffffff811161052957604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761052957604052565b90816020910312610397575180151581036103975790565b908060209392818452848401375f828201840152601f01601f1916010190565b906105be57508051156105ac57805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806105f1575b6105cf575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156105c756fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003360a03461007157601f6102af38819003918201601f19168301916001600160401b038311848410176100755780849260209460405283398101031261007157516001600160a01b0381169081900361007157608052604051610225908161008a82396080518181816081015260c80152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040908082526004908136101561004a575b5050361561001f575f80fd5b60207f7cb3607a76b32d6d17ca5d1aeb444650b19ac0fabbb1f24c93a0da57346b56109151348152a1005b5f3560e01c9182634641257d146100b457505063fbfa77cf1461006e575f80610013565b346100b0575f3660031901126100b057517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b8390346100b0575f3660031901126100b0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692338490036101e3575047928361010b575b602083515f8152f35b8347106101cc575f80808681945af13d156101c75767ffffffffffffffff3d8181116101b457845191601f8201601f19908116603f01168301908111838210176101a157855281525f60203d92013e5b1561019357507f8e55ccfc9778ff8eba1646d765cf1982537ce0f9257054a17b48aad745250183602080938351908152a18280610102565b9051630a12f52160e11b8152fd5b604185634e487b7160e01b5f525260245ffd5b604184634e487b7160e01b5f525260245ffd5b61015b565b50602491519063cd78605960e01b82523090820152fd5b630d599dd960e11b8152fdfea2646970667358221220946ad74fcaa520949345e848339f2c8ef2b0c8c2b984044d3abdc40e465aa56b64736f6c63430008160033a26469706673582212201be709277a73e23c40a3e8e666638aa05caa6c557e0fd22ffe2c89b141092ebd64736f6c63430008160033", - "deployedBytecode": "0x6080604081815260049182361015610015575f80fd5b5f925f3560e01c9182635c60da1b146104d4575081636f4fa30f146104ad5781639a0d79ad14610079575063e7f6f2251461004e575f80fd5b3461007557816003193601126100755760015490516001600160a01b039091168152602090f35b5080fd5b9190503461039757806003193601126103975781359067ffffffffffffffff808311610397573660238401121561039757828401359080821161039757602493848101908584369201011161039757843590811515820361039757845197602096878a01946323b872dd60e01b865233828c01523060448c0152633b9aca008060648d015260648c5260a08c018c81108382111761049b575f809b9c9d81928c5260018060a01b03998a7f0000000000000000000000000000000000000000000000000000000000000000169d8e9251925af13d1561048f573d83811161047d57610186918d918c519061017684601f19601f840116018361053d565b81525f81933d92013e5b8c610597565b8051908c8215159283610464575b50505061044e5788516102c8808201908282108583111761043b576060918c8f85936105fb85398c7f00000000000000000000000000000000000000000000000000000000000000001683528201525f8d8201520301905ff08015610431578960448e5f8f948c169e8f9451968795869463095ea7b360e01b8652850152898401525af180156104315790869291610404575b505f9561039b575b506bffffffffffffffffffffffff60a01b9033826001541617600155893b1561039757845f898c8f8f9084908f61027e90519788968795869463439fab9160e01b86528501528c840191610577565b03925af1801561038d5761037a575b5061036f575b60015416600155847f000000000000000000000000000000000000000000000000000000000000000016998a3b1561036b5782918991838a519d8e9485936312b5ad0160e11b85528401525af198891561035f5787989997969761033c575b5050906103337f0d606510f33b5e566ed1ca2b9e88d388ab81cea532909665d725b33134516aff93928751938493168352878a840152339588840191610577565b0390a351908152f35b8192939495965061034c90610515565b61035c57908187959493926102f2565b80fd5b508551903d90823e3d90fd5b8280fd5b808354168355610293565b610385919450610515565b5f925f61028d565b8a513d5f823e3d90fd5b5f80fd5b88519195506102af808301918211838310176103f2578b9183916108c383398b81520301905ff080156103e857851693846bffffffffffffffffffffffff60a01b5f5416175f555f61022f565b87513d5f823e3d90fd5b8360418e634e487b7160e01b5f52525ffd5b610423908c8d3d1061042a575b61041b818361053d565b81019061055f565b505f610227565b503d610411565b89513d5f823e3d90fd5b508460418f634e487b7160e01b5f52525ffd5b8851635274afe760e01b8152808d018b90528390fd5b610474935082018101910161055f565b155f8c81610194565b8460418f634e487b7160e01b5f52525ffd5b61018690606090610180565b8360418d634e487b7160e01b5f52525ffd5b8234610397575f366003190112610397575f5490516001600160a01b039091168152602090f35b34610397575f366003190112610397577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b67ffffffffffffffff811161052957604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761052957604052565b90816020910312610397575180151581036103975790565b908060209392818452848401375f828201840152601f01601f1916010190565b906105be57508051156105ac57805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806105f1575b6105cf575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156105c756fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003360a03461007157601f6102af38819003918201601f19168301916001600160401b038311848410176100755780849260209460405283398101031261007157516001600160a01b0381169081900361007157608052604051610225908161008a82396080518181816081015260c80152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040908082526004908136101561004a575b5050361561001f575f80fd5b60207f7cb3607a76b32d6d17ca5d1aeb444650b19ac0fabbb1f24c93a0da57346b56109151348152a1005b5f3560e01c9182634641257d146100b457505063fbfa77cf1461006e575f80610013565b346100b0575f3660031901126100b057517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b8390346100b0575f3660031901126100b0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692338490036101e3575047928361010b575b602083515f8152f35b8347106101cc575f80808681945af13d156101c75767ffffffffffffffff3d8181116101b457845191601f8201601f19908116603f01168301908111838210176101a157855281525f60203d92013e5b1561019357507f8e55ccfc9778ff8eba1646d765cf1982537ce0f9257054a17b48aad745250183602080938351908152a18280610102565b9051630a12f52160e11b8152fd5b604185634e487b7160e01b5f525260245ffd5b604184634e487b7160e01b5f525260245ffd5b61015b565b50602491519063cd78605960e01b82523090820152fd5b630d599dd960e11b8152fdfea2646970667358221220946ad74fcaa520949345e848339f2c8ef2b0c8c2b984044d3abdc40e465aa56b64736f6c63430008160033a26469706673582212201be709277a73e23c40a3e8e666638aa05caa6c557e0fd22ffe2c89b141092ebd64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/test/shared/constants.ts b/test/shared/constants.ts deleted file mode 100644 index 0365a1f9..00000000 --- a/test/shared/constants.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { ethers, parseEther } from 'ethers' - -export const PANIC_CODES = { - ARITHMETIC_UNDER_OR_OVERFLOW: 0x11, - DIVISION_BY_ZERO: 0x12, - OUT_OF_BOUND_INDEX: 0x32, -} - -export const SECURITY_DEPOSIT = 1000000000n -export const MAX_UINT256 = 2n ** 256n - 1n -export const MAX_UINT64 = 2n ** 64n - 1n -export const MAX_UINT128 = 2n ** 128n - 1n -export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -export const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000' -export const ONE_DAY = 86400 - -export const VALIDATORS_DEADLINE = 1914150396n - -export const REWARDS_DELAY = ONE_DAY / 2 // 12 hours -export const ORACLES = [ - Buffer.from('c2bc8560ffcc278ded2efffaccfc4ce08b2a3a867eb744cec45732603e30ebf7', 'hex'), - Buffer.from('aff434fa2127355afdf265af1ba7e1d1384ffca4b7c2a8b7b9e04d23e316f395', 'hex'), - Buffer.from('cdb517b473daa98584897f3d224453ec4b1ed574ad98697a0e910103599903d6', 'hex'), - Buffer.from('f6e9186ab80c4e210edf231708353727cfd65a0211fa483e144cd5bf72913a3b', 'hex'), - Buffer.from('d44d4b9d464979a765d668ed9c83150048b6cb6be363ebec5b4e929d1513f126', 'hex'), - Buffer.from('1d523e07453be2a5ad304e7fb950713a6021bbcbe5bd8c19b15033a419abea67', 'hex'), - Buffer.from('6b64cbac8e5a12f78bd984b99df2c1a1984665017068531ccf9fe7b35bacb518', 'hex'), - Buffer.from('16594b5022a199029ae2614b1906c03ffc8b0fc1f2a1efb5836275a1e52f611a', 'hex'), - Buffer.from('27bad568920a145813ff66b73360c84f221043e1861fcfdf43f9d150e84202ea', 'hex'), - Buffer.from('06087f518d2c684d1a2a3523fe358f3fdc45dfe560cf7a7ccb8ba01da7786796', 'hex'), - Buffer.from('3999c56744678c5cb451df5eadf2846b92aa158b6d5eda55775f27064c6e880a', 'hex'), - Buffer.from('ca960119ad719a55764d0f5913fb354c301f614d3f49219c7b03202b2062890f', 'hex'), -] -export const REWARDS_MIN_ORACLES = 6 -export const VALIDATORS_MIN_ORACLES = 6 -export const ORACLES_CONFIG = 'QmbwQ6zFEWs1SjLPGk4NNJqn4wduVe6dK3xyte2iG59Uru' -export const EXITING_ASSETS_MIN_DELAY = 24 * 60 * 60 // 24 hours -export const OSTOKEN_FEE = 500 // 5% -export const OSTOKEN_CAPACITY = ethers.parseEther('10000000') -export const OSTOKEN_NAME = 'Staked ETH' -export const OSTOKEN_SYMBOL = 'osETH' - -export const OSTOKEN_LIQ_THRESHOLD = parseEther('0.92') // 92% -export const OSTOKEN_LIQ_BONUS = parseEther('1.01') // 101% -export const OSTOKEN_LTV = parseEther('0.9') // 90% -export const OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD = parseEther('0.999') // 99.9% -export const OSTOKEN_VAULT_ESCROW_LIQ_BONUS = parseEther('1.001') // 100.1% - -export const MAX_AVG_REWARD_PER_SECOND = 6341958397 // 20% APY - -export const XDAI_EXCHANGE_MAX_SLIPPAGE = 50 // 0.5% - -export const XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA = 86400 // 1 day - -export const EIP712Domain = [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, -] - -export const PermitSig = [ - { name: 'owner', type: 'address' }, - { name: 'spender', type: 'address' }, - { name: 'value', type: 'uint256' }, - { name: 'nonce', type: 'uint256' }, - { name: 'deadline', type: 'uint256' }, -] - -export const KeeperRewardsSig = [ - { name: 'rewardsRoot', type: 'bytes32' }, - { name: 'rewardsIpfsHash', type: 'string' }, - { name: 'avgRewardPerSecond', type: 'uint256' }, - { name: 'updateTimestamp', type: 'uint64' }, - { name: 'nonce', type: 'uint64' }, -] - -export const KeeperValidatorsSig = [ - { name: 'validatorsRegistryRoot', type: 'bytes32' }, - { name: 'vault', type: 'address' }, - { name: 'validators', type: 'bytes' }, - { name: 'exitSignaturesIpfsHash', type: 'string' }, - { name: 'deadline', type: 'uint256' }, -] - -export const VaultValidatorsSig = [ - { name: 'validatorsRegistryRoot', type: 'bytes32' }, - { name: 'validators', type: 'bytes' }, -] - -export const KeeperUpdateExitSignaturesSig = [ - { name: 'vault', type: 'address' }, - { name: 'exitSignaturesIpfsHash', type: 'string' }, - { name: 'nonce', type: 'uint256' }, - { name: 'deadline', type: 'uint256' }, -] diff --git a/test/shared/contracts.ts b/test/shared/contracts.ts deleted file mode 100644 index 2642c56c..00000000 --- a/test/shared/contracts.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { Contract, ContractFactory } from 'ethers' -import { ethers } from 'hardhat' -import EthValidatorsRegistry from './artifacts/EthValidatorsRegistry.json' -import GnoValidatorsRegistry from './artifacts/GnoValidatorsRegistry.json' -import EthVaultV1 from './artifacts/EthVaultV1.json' -import EthVault from './artifacts/EthVault.json' -import EthErc20Vault from './artifacts/EthErc20Vault.json' -import EthPrivErc20Vault from './artifacts/EthPrivErc20Vault.json' -import EthPrivVault from './artifacts/EthPrivVault.json' -import EthBlocklistVault from './artifacts/EthBlocklistVault.json' -import EthBlocklistErc20Vault from './artifacts/EthBlocklistErc20Vault.json' -import GnoVault from './artifacts/GnoVault.json' -import GnoPrivVault from './artifacts/GnoPrivVault.json' -import GnoErc20Vault from './artifacts/GnoErc20Vault.json' -import GnoPrivErc20Vault from './artifacts/GnoPrivErc20Vault.json' -import GnoBlocklistVault from './artifacts/GnoBlocklistVault.json' -import GnoBlocklistErc20Vault from './artifacts/GnoBlocklistErc20Vault.json' -import GnoGenesisVault from './artifacts/GnoGenesisVault.json' -import EthGenesisVault from './artifacts/EthGenesisVault.json' -import EigenPodManager from './artifacts/EigenPodManager.json' -import EigenDelegationManager from './artifacts/EigenDelegationManager.json' -import EigenDelayedWithdrawalRouter from './artifacts/EigenDelayedWithdrawalRouter.json' -import { MAINNET_FORK } from '../../helpers/constants' - -export async function getEthValidatorsRegistryFactory(): Promise { - return await ethers.getContractFactory(EthValidatorsRegistry.abi, EthValidatorsRegistry.bytecode) -} - -export async function getGnoValidatorsRegistryFactory(): Promise { - return await ethers.getContractFactory(GnoValidatorsRegistry.abi, GnoValidatorsRegistry.bytecode) -} - -export async function getEthVaultV1Factory(): Promise { - return await ethers.getContractFactory(EthVaultV1.abi, EthVaultV1.bytecode) -} - -export async function getEthVaultV3Factory(): Promise { - return await ethers.getContractFactory(EthVault.abi, EthVault.bytecode) -} - -export async function getEthErc20VaultV3Factory(): Promise { - return await ethers.getContractFactory(EthErc20Vault.abi, EthErc20Vault.bytecode) -} - -export async function getEthPrivErc20VaultV3Factory(): Promise { - return await ethers.getContractFactory(EthPrivErc20Vault.abi, EthPrivErc20Vault.bytecode) -} - -export async function getEthBlocklistErc20VaultV3Factory(): Promise { - return await ethers.getContractFactory( - EthBlocklistErc20Vault.abi, - EthBlocklistErc20Vault.bytecode - ) -} - -export async function getEthPrivVaultV3Factory(): Promise { - return await ethers.getContractFactory(EthPrivVault.abi, EthPrivVault.bytecode) -} - -export async function getEthBlocklistVaultV3Factory(): Promise { - return await ethers.getContractFactory(EthBlocklistVault.abi, EthBlocklistVault.bytecode) -} - -export async function getEthGenesisVaultV3Factory(): Promise { - return await ethers.getContractFactory(EthGenesisVault.abi, EthGenesisVault.bytecode) -} - -export async function getGnoVaultV2Factory(): Promise { - return await ethers.getContractFactory(GnoVault.abi, GnoVault.bytecode) -} - -export async function getGnoPrivVaultV2Factory(): Promise { - return await ethers.getContractFactory(GnoPrivVault.abi, GnoPrivVault.bytecode) -} - -export async function getGnoErc20VaultV2Factory(): Promise { - return await ethers.getContractFactory(GnoErc20Vault.abi, GnoErc20Vault.bytecode) -} - -export async function getGnoPrivErc20VaultV2Factory(): Promise { - return await ethers.getContractFactory(GnoPrivErc20Vault.abi, GnoPrivErc20Vault.bytecode) -} - -export async function getGnoBlocklistVaultV2Factory(): Promise { - return await ethers.getContractFactory(GnoBlocklistVault.abi, GnoBlocklistVault.bytecode) -} - -export async function getGnoBlocklistErc20VaultV2Factory(): Promise { - return await ethers.getContractFactory( - GnoBlocklistErc20Vault.abi, - GnoBlocklistErc20Vault.bytecode - ) -} - -export async function getGnoGenesisVaultV2Factory(): Promise { - return await ethers.getContractFactory(GnoGenesisVault.abi, GnoGenesisVault.bytecode) -} - -export async function getEigenPodManager(): Promise { - return await ethers.getContractAt(EigenPodManager.abi, MAINNET_FORK.eigenPodManager) -} - -export async function getEigenDelegationManager(): Promise { - return await ethers.getContractAt(EigenDelegationManager.abi, MAINNET_FORK.eigenDelegationManager) -} - -export async function getEigenDelayedWithdrawalRouter(): Promise { - return await ethers.getContractAt( - EigenDelayedWithdrawalRouter.abi, - MAINNET_FORK.eigenDelayedWithdrawalRouter - ) -} diff --git a/test/shared/expect.ts b/test/shared/expect.ts deleted file mode 100644 index 5dca90e6..00000000 --- a/test/shared/expect.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, use } from 'chai' -import { jestSnapshotPlugin } from 'mocha-chai-jest-snapshot' - -use(jestSnapshotPlugin()) - -export { expect } diff --git a/test/shared/fixtures.ts b/test/shared/fixtures.ts deleted file mode 100644 index 4213960a..00000000 --- a/test/shared/fixtures.ts +++ /dev/null @@ -1,1156 +0,0 @@ -import hre, { ethers } from 'hardhat' -import { BigNumberish, Contract, ContractFactory, parseEther, Signer, Wallet } from 'ethers' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import { - impersonateAccount, - stopImpersonatingAccount, -} from '@nomicfoundation/hardhat-toolbox/network-helpers' -import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util' -import EthereumWallet from 'ethereumjs-wallet' -import { - EthBlocklistErc20Vault, - EthBlocklistErc20Vault__factory, - EthBlocklistVault, - EthBlocklistVault__factory, - EthErc20Vault, - EthErc20Vault__factory, - EthFoxVault, - EthFoxVault__factory, - EthGenesisVault, - EthGenesisVault__factory, - EthPrivErc20Vault, - EthPrivErc20Vault__factory, - EthPrivVault, - EthPrivVault__factory, - EthVault, - EthVault__factory, - EthVaultFactory, - EthVaultFactory__factory, - EthVaultMock, - EthVaultMock__factory, - IKeeperRewards, - Keeper, - Keeper__factory, - LegacyRewardTokenMock, - LegacyRewardTokenMock__factory, - OsToken, - OsToken__factory, - OsTokenConfig, - OsTokenConfig__factory, - OsTokenVaultController, - OsTokenVaultController__factory, - PoolEscrowMock, - PoolEscrowMock__factory, - PriceFeed, - PriceFeed__factory, - RewardSplitterFactory, - RewardSplitterFactory__factory, - SharedMevEscrow, - SharedMevEscrow__factory, - VaultsRegistry, - VaultsRegistry__factory, - DepositDataRegistry, - DepositDataRegistry__factory, - EthValidatorsChecker__factory, - OsTokenVaultEscrow, - OsTokenVaultEscrow__factory, - OsTokenVaultEscrowAuthMock, - OsTokenVaultEscrowAuthMock__factory, - OsTokenFlashLoans, - OsTokenFlashLoans__factory, -} from '../../typechain-types' -import { getEthValidatorsRegistryFactory } from './contracts' -import { - EXITING_ASSETS_MIN_DELAY, - MAX_AVG_REWARD_PER_SECOND, - ORACLES, - ORACLES_CONFIG, - OSTOKEN_CAPACITY, - OSTOKEN_FEE, - OSTOKEN_LIQ_BONUS, - OSTOKEN_LIQ_THRESHOLD, - OSTOKEN_LTV, - OSTOKEN_NAME, - OSTOKEN_SYMBOL, - OSTOKEN_VAULT_ESCROW_LIQ_BONUS, - OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD, - REWARDS_DELAY, - REWARDS_MIN_ORACLES, - SECURITY_DEPOSIT, - VALIDATORS_MIN_ORACLES, -} from './constants' -import { EthErc20VaultInitParamsStruct, EthVaultInitParamsStruct, EthVaultType } from './types' -import { DepositorMock } from '../../typechain-types/contracts/mocks/DepositorMock' -import { DepositorMock__factory } from '../../typechain-types/factories/contracts/mocks/DepositorMock__factory' -import { UnknownVaultMock } from '../../typechain-types/contracts/mocks/UnknownVaultMock' -import { UnknownVaultMock__factory } from '../../typechain-types/factories/contracts/mocks/UnknownVaultMock__factory' -import { MulticallMock__factory } from '../../typechain-types/factories/contracts/mocks/MulticallMock__factory' -import { MulticallMock } from '../../typechain-types/contracts/mocks/MulticallMock' -import { extractVaultAddress, setBalance } from './utils' -import { MAINNET_FORK, NETWORKS } from '../../helpers/constants' -import mainnetDeployment from '../../deployments/mainnet.json' - -export const transferOwnership = async function ( - contract: Keeper | VaultsRegistry | OsTokenVaultController | OsToken | OsTokenConfig, - newOwner: Signer -) { - const currentOwnerAddr = await contract.owner() - const newOwnerAddr = await newOwner.getAddress() - if (currentOwnerAddr == newOwnerAddr) return - - await impersonateAccount(currentOwnerAddr) - const currentOwner = await ethers.provider.getSigner(currentOwnerAddr) - - await setBalance(currentOwnerAddr, ethers.parseEther('100')) - await contract.connect(currentOwner).transferOwnership(newOwnerAddr) - await stopImpersonatingAccount(currentOwnerAddr) - - await contract.connect(newOwner).acceptOwnership() -} - -export const upgradeVault = async function ( - vault: EthVaultType, - implementation: string -): Promise { - const adminAddr = await vault.admin() - const admin = await ethers.getImpersonatedSigner(adminAddr) - await setBalance(adminAddr, ethers.parseEther('1')) - - if ((await vault.version()) == 1n) { - // load v3 implementations - const vaultId = await vault.vaultId() - const fileName = '../../deployments/mainnet-vault-v3-upgrades.json' - - // eslint-disable-next-line @typescript-eslint/no-require-imports - const upgrades = require(fileName) - const v3Implementation = upgrades[vaultId]['3'] - await vault.connect(admin).upgradeToAndCall(v3Implementation, '0x') - } - await vault.connect(admin).upgradeToAndCall(implementation, '0x') - return vault -} - -export const updateVaultState = async function ( - keeper: Keeper, - vault: EthVaultType, - harvestParams: IKeeperRewards.HarvestParamsStruct -) { - if (!(await keeper.canHarvest(await vault.getAddress()))) { - return - } - await vault.updateState(harvestParams) -} - -export const createDepositorMock = async function (vault: EthVaultType): Promise { - const depositorMockFactory = await ethers.getContractFactory('DepositorMock') - const contract = await depositorMockFactory.deploy(await vault.getAddress()) - return DepositorMock__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} - -export const createUnknownVaultMock = async function ( - osTokenVaultController: OsTokenVaultController, - implementation: string -): Promise { - const factory = await ethers.getContractFactory('UnknownVaultMock') - const contract = await factory.deploy(await osTokenVaultController.getAddress(), implementation) - return UnknownVaultMock__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} - -export const createMulticallMock = async function (): Promise { - const contract = await ethers.deployContract('MulticallMock') - return MulticallMock__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} -export const createEthValidatorsRegistry = async function (): Promise { - const validatorsRegistryFactory = await getEthValidatorsRegistryFactory() - const signer = await ethers.provider.getSigner() - - if (MAINNET_FORK.enabled) { - return new Contract( - NETWORKS.mainnet.validatorsRegistry, - validatorsRegistryFactory.interface, - signer - ) - } - const contract = await validatorsRegistryFactory.deploy() - return new Contract(await contract.getAddress(), validatorsRegistryFactory.interface, signer) -} - -export const createPoolEscrow = async function ( - stakedEthTokenAddress: string, - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - - if (MAINNET_FORK.enabled && !skipFork) { - return PoolEscrowMock__factory.connect(NETWORKS.mainnet.genesisVault.poolEscrow, signer) - } - const factory = await ethers.getContractFactory('PoolEscrowMock') - const contract = await factory.deploy(stakedEthTokenAddress) - return PoolEscrowMock__factory.connect(await contract.getAddress(), signer) -} - -export const createVaultsRegistry = async function ( - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - - if (MAINNET_FORK.enabled && !skipFork) { - const contract = VaultsRegistry__factory.connect(mainnetDeployment.VaultsRegistry, signer) - await transferOwnership(contract, signer) - return contract - } - const factory = await ethers.getContractFactory('VaultsRegistry') - const contract = await factory.deploy() - const registry = VaultsRegistry__factory.connect(await contract.getAddress(), signer) - await registry.initialize(signer.address) - return registry -} - -export const createEthSharedMevEscrow = async function ( - vaultsRegistry: VaultsRegistry -): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled) { - return SharedMevEscrow__factory.connect(mainnetDeployment.SharedMevEscrow, signer) - } - const factory = await ethers.getContractFactory('SharedMevEscrow') - const contract = await factory.deploy(await vaultsRegistry.getAddress()) - return SharedMevEscrow__factory.connect(await contract.getAddress(), signer) -} - -export const createPriceFeed = async function ( - osTokenVaultController: OsTokenVaultController, - description: string -): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled) { - return PriceFeed__factory.connect(mainnetDeployment.PriceFeed, signer) - } - const factory = await ethers.getContractFactory('PriceFeed') - const contract = await factory.deploy(await osTokenVaultController.getAddress(), description) - return PriceFeed__factory.connect(await contract.getAddress(), signer) -} - -export const createRewardSplitterFactory = async function (): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled) { - return RewardSplitterFactory__factory.connect(mainnetDeployment.RewardSplitterFactory, signer) - } - let factory = await ethers.getContractFactory('RewardSplitter') - const rewardSplitterImpl = await factory.deploy() - - factory = await ethers.getContractFactory('RewardSplitterFactory') - const contract = await factory.deploy(await rewardSplitterImpl.getAddress()) - return RewardSplitterFactory__factory.connect(await contract.getAddress(), signer) -} - -export const createDepositDataRegistry = async function ( - vaultsRegistry: VaultsRegistry, - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled && !skipFork) { - return DepositDataRegistry__factory.connect(mainnetDeployment.DepositDataRegistry, signer) - } - const factory = await ethers.getContractFactory('DepositDataRegistry') - const contract = await factory.deploy(await vaultsRegistry.getAddress()) - return DepositDataRegistry__factory.connect(await contract.getAddress(), signer) -} - -export const createEthValidatorsChecker = async function ( - validatorsRegistry: Contract, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - depositDataRegistry: DepositDataRegistry -) { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled) { - return EthValidatorsChecker__factory.connect(mainnetDeployment.EthValidatorsChecker, signer) - } - const factory = await ethers.getContractFactory('EthValidatorsChecker') - const contract = await factory.deploy( - await validatorsRegistry.getAddress(), - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await depositDataRegistry.getAddress() - ) - return EthValidatorsChecker__factory.connect(await contract.getAddress(), signer) -} - -export const createOsTokenVaultController = async function ( - keeperAddress: string, - registry: VaultsRegistry, - osTokenAddress: string, - treasury: Wallet, - governor: Wallet, - feePercent: BigNumberish, - capacity: BigNumberish, - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled && !skipFork) { - const contract = OsTokenVaultController__factory.connect( - mainnetDeployment.OsTokenVaultController, - signer - ) - await transferOwnership(contract, governor) - await contract.connect(governor).setTreasury(treasury.address) - return contract - } - const factory = await ethers.getContractFactory('OsTokenVaultController') - const contract = await factory.deploy( - keeperAddress, - await registry.getAddress(), - osTokenAddress, - treasury.address, - governor.address, - feePercent, - capacity - ) - return OsTokenVaultController__factory.connect(await contract.getAddress(), signer) -} - -export const createOsToken = async function ( - governor: Wallet, - vaultController: OsTokenVaultController, - name: string, - symbol: string, - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled && !skipFork) { - const contract = OsToken__factory.connect(mainnetDeployment.OsToken, signer) - await transferOwnership(contract, governor) - return contract - } - const factory = await ethers.getContractFactory('OsToken') - const contract = await factory.deploy( - governor.address, - await vaultController.getAddress(), - name, - symbol - ) - return OsToken__factory.connect(await contract.getAddress(), signer) -} - -export const createOsTokenConfig = async function ( - owner: Wallet, - liqThresholdPercent: BigNumberish, - liqBonusPercent: BigNumberish, - ltvPercent: BigNumberish, - redeemer: Wallet, - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - if (MAINNET_FORK.enabled && !skipFork) { - const contract = OsTokenConfig__factory.connect(mainnetDeployment.OsTokenConfig, signer) - await transferOwnership(contract, owner) - return contract - } - const factory = await ethers.getContractFactory('OsTokenConfig') - const contract = await factory.deploy( - owner.address, - { - liqBonusPercent, - liqThresholdPercent, - ltvPercent, - }, - await redeemer.getAddress() - ) - return OsTokenConfig__factory.connect(await contract.getAddress(), signer) -} - -export const createOsTokenVaultEscrowAuthMock = async function ( - owner: Wallet -): Promise { - const signer = await ethers.provider.getSigner() - const factory = await ethers.getContractFactory('OsTokenVaultEscrowAuthMock') - const contract = await factory.deploy(owner.address) - return OsTokenVaultEscrowAuthMock__factory.connect(await contract.getAddress(), signer) -} - -export const createOsTokenVaultEscrow = async function ( - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - owner: Wallet, - escrowAuth: OsTokenVaultEscrowAuthMock, - liqThresholdPercent: BigNumberish, - liqBonusPercent: BigNumberish -): Promise { - const signer = await ethers.provider.getSigner() - const factory = await ethers.getContractFactory('EthOsTokenVaultEscrow') - const contract = await factory.deploy( - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - owner.address, - await escrowAuth.getAddress(), - liqThresholdPercent, - liqBonusPercent - ) - return OsTokenVaultEscrow__factory.connect(await contract.getAddress(), signer) -} - -export const createOsTokenFlashLoans = async function ( - osToken: OsToken -): Promise { - const signer = await ethers.provider.getSigner() - const factory = await ethers.getContractFactory('OsTokenFlashLoans') - const contract = await factory.deploy(await osToken.getAddress()) - return OsTokenFlashLoans__factory.connect(await contract.getAddress(), signer) -} - -export const createKeeper = async function ( - initialOracles: string[], - configIpfsHash: string, - sharedMevEscrow: SharedMevEscrow, - vaultsRegistry: VaultsRegistry, - osTokenVaultController: OsTokenVaultController, - rewardsDelay: BigNumberish, - maxAvgRewardPerSecond: BigNumberish, - rewardsMinOracles: BigNumberish, - validatorsRegistry: Contract, - validatorsMinOracles: BigNumberish, - skipFork: boolean = false -): Promise { - const signer = await ethers.provider.getSigner() - let keeper: Keeper - if (MAINNET_FORK.enabled && !skipFork) { - keeper = Keeper__factory.connect(mainnetDeployment.Keeper, signer) - } else { - const factory = await ethers.getContractFactory('Keeper') - const contract = await factory.deploy( - await sharedMevEscrow.getAddress(), - await vaultsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - rewardsDelay, - maxAvgRewardPerSecond, - await validatorsRegistry.getAddress() - ) - keeper = Keeper__factory.connect(await contract.getAddress(), signer) - await keeper.connect(signer).initialize(signer.address) - } - - if (MAINNET_FORK.enabled && !skipFork) { - // transfer dao ownership - await transferOwnership(keeper, signer) - - // drop mainnet oracles - for (const oracleAddr of MAINNET_FORK.oracles) { - await keeper.removeOracle(oracleAddr) - } - } - - for (let i = 0; i < initialOracles.length; i++) { - await keeper.addOracle(initialOracles[i]) - } - - await keeper.updateConfig(configIpfsHash) - await keeper.setRewardsMinOracles(rewardsMinOracles) - await keeper.setValidatorsMinOracles(validatorsMinOracles) - return keeper -} - -export const createEthVaultFactory = async function ( - implementation: string, - vaultsRegistry: VaultsRegistry -): Promise { - const factory = await ethers.getContractFactory('EthVaultFactory') - const contract = await factory.deploy(implementation, await vaultsRegistry.getAddress()) - return EthVaultFactory__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} - -export const deployEthGenesisVaultImpl = async function ( - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - osTokenVaultEscrow: OsTokenVaultEscrow, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - poolEscrow: PoolEscrowMock, - rewardEthToken: LegacyRewardTokenMock -): Promise { - const factory = await ethers.getContractFactory('EthGenesisVault') - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await osTokenVaultEscrow.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - await poolEscrow.getAddress(), - await rewardEthToken.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const contract = await factory.deploy(...constructorArgs) - const vaultImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, vaultImpl) - return vaultImpl -} - -export const deployEthVaultImplementation = async function ( - vaultType: string, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: string, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - osTokenVaultEscrow: OsTokenVaultEscrow, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - exitingAssetsMinDelay: number -): Promise { - const factory = await ethers.getContractFactory(vaultType) - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - validatorsRegistry, - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await osTokenVaultEscrow.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - exitingAssetsMinDelay, - ] - const contract = await factory.deploy(...constructorArgs) - const vaultImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, vaultImpl) - return vaultImpl -} - -export async function deployEthVaultV1( - implFactory: ContractFactory, - admin: Signer, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: Contract, - sharedMevEscrow: SharedMevEscrow, - encodedParams: string, - isOwnMevEscrow = false -): Promise { - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await sharedMevEscrow.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const vaultImpl = await implFactory.deploy(...constructorArgs) - const vaultImplAddr = await vaultImpl.getAddress() - await vaultsRegistry.addVaultImpl(vaultImplAddr) - - const vaultFactory = await createEthVaultFactory(vaultImplAddr, vaultsRegistry) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - - const tx = await vaultFactory.connect(admin).createVault(encodedParams, isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - return new Contract( - await extractVaultAddress(tx), - implFactory.interface, - await ethers.provider.getSigner() - ) -} - -export async function deployEthVaultV3( - implFactory: ContractFactory, - admin: Signer, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - osTokenVaultEscrow: OsTokenVaultEscrow, - encodedParams: string, - isOwnMevEscrow = false -): Promise { - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await osTokenVaultEscrow.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const vaultImpl = await implFactory.deploy(...constructorArgs) - const vaultImplAddr = await vaultImpl.getAddress() - await vaultsRegistry.addVaultImpl(vaultImplAddr) - - const vaultFactory = await createEthVaultFactory(vaultImplAddr, vaultsRegistry) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - - const tx = await vaultFactory.connect(admin).createVault(encodedParams, isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - return new Contract( - await extractVaultAddress(tx), - implFactory.interface, - await ethers.provider.getSigner() - ) -} - -export const encodeEthVaultInitParams = function (vaultParams: EthVaultInitParamsStruct): string { - return ethers.AbiCoder.defaultAbiCoder().encode( - ['tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [[vaultParams.capacity, vaultParams.feePercent, vaultParams.metadataIpfsHash]] - ) -} - -export const encodeEthErc20VaultInitParams = function ( - vaultParams: EthErc20VaultInitParamsStruct -): string { - return ethers.AbiCoder.defaultAbiCoder().encode( - [ - 'tuple(uint256 capacity, uint16 feePercent, string name, string symbol, string metadataIpfsHash)', - ], - [ - [ - vaultParams.capacity, - vaultParams.feePercent, - vaultParams.name, - vaultParams.symbol, - vaultParams.metadataIpfsHash, - ], - ] - ) -} - -export const getOraclesSignatures = function ( - typedData: any, - count: number = REWARDS_MIN_ORACLES -): Buffer { - const sortedOracles = ORACLES.sort((oracle1, oracle2) => { - const oracle1Addr = new EthereumWallet(oracle1).getAddressString() - const oracle2Addr = new EthereumWallet(oracle2).getAddressString() - return oracle1Addr > oracle2Addr ? 1 : -1 - }) - const signatures: Buffer[] = [] - for (let i = 0; i < count; i++) { - signatures.push( - Buffer.from( - ethers.getBytes( - signTypedData({ - privateKey: sortedOracles[i], - data: typedData, - version: SignTypedDataVersion.V4, - }) - ) - ) - ) - } - return Buffer.concat(signatures) -} - -interface EthVaultFixture { - vaultsRegistry: VaultsRegistry - keeper: Keeper - sharedMevEscrow: SharedMevEscrow - depositDataRegistry: DepositDataRegistry - validatorsRegistry: Contract - ethVaultFactory: EthVaultFactory - ethPrivVaultFactory: EthVaultFactory - ethErc20VaultFactory: EthVaultFactory - ethPrivErc20VaultFactory: EthVaultFactory - ethBlocklistVaultFactory: EthVaultFactory - ethBlocklistErc20VaultFactory: EthVaultFactory - osToken: OsToken - osTokenVaultController: OsTokenVaultController - osTokenConfig: OsTokenConfig - osTokenVaultEscrow: OsTokenVaultEscrow - osTokenFlashLoans: OsTokenFlashLoans - - createEthVault( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow?: boolean, - skipFork?: boolean - ): Promise - - createEthFoxVault(admin: Signer, vaultParams: EthVaultInitParamsStruct): Promise - - createEthVaultMock( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthPrivVault( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthBlocklistVault( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthErc20Vault( - admin: Signer, - vaultParams: EthErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean, - skipFork?: boolean - ): Promise - - createEthPrivErc20Vault( - admin: Signer, - vaultParams: EthErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthBlocklistErc20Vault( - admin: Signer, - vaultParams: EthErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createEthGenesisVault( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - skipFork?: boolean - ): Promise<[EthGenesisVault, LegacyRewardTokenMock, PoolEscrowMock]> -} - -export const ethVaultFixture = async function (): Promise { - const dao = await (ethers as any).provider.getSigner() - const vaultsRegistry = await createVaultsRegistry() - const validatorsRegistry = await createEthValidatorsRegistry() - - const sharedMevEscrow = await createEthSharedMevEscrow(vaultsRegistry) - - // 1. calc osToken address - const _osTokenAddress = ethers.getCreateAddress({ - from: dao.address, - nonce: (await ethers.provider.getTransactionCount(dao.address)) + 1, - }) - - // 2. calc keeper address - const _keeperAddress = ethers.getCreateAddress({ - from: dao.address, - nonce: (await ethers.provider.getTransactionCount(dao.address)) + 2, - }) - - // 3. deploy osTokenVaultController - const osTokenVaultController = await createOsTokenVaultController( - _keeperAddress, - vaultsRegistry, - _osTokenAddress, - dao, - dao, - OSTOKEN_FEE, - OSTOKEN_CAPACITY - ) - - // 4. deploy osToken - const osToken = await createOsToken(dao, osTokenVaultController, OSTOKEN_NAME, OSTOKEN_SYMBOL) - if (!MAINNET_FORK.enabled && _osTokenAddress != (await osToken.getAddress())) { - throw new Error('Invalid calculated OsToken address') - } - - // 5. deploy keeper - const sortedOracles = ORACLES.sort((oracle1, oracle2) => { - const oracle1Addr = new EthereumWallet(oracle1).getAddressString() - const oracle2Addr = new EthereumWallet(oracle2).getAddressString() - return oracle1Addr > oracle2Addr ? 1 : -1 - }) - const keeper = await createKeeper( - sortedOracles.map((s) => new EthereumWallet(s).getAddressString()), - ORACLES_CONFIG, - sharedMevEscrow, - vaultsRegistry, - osTokenVaultController, - REWARDS_DELAY, - MAX_AVG_REWARD_PER_SECOND, - REWARDS_MIN_ORACLES, - validatorsRegistry, - VALIDATORS_MIN_ORACLES - ) - if (!MAINNET_FORK.enabled && _keeperAddress != (await keeper.getAddress())) { - throw new Error('Invalid calculated Keeper address') - } - - // 6. deploy osTokenConfig - const osTokenConfig = await createOsTokenConfig( - dao, - OSTOKEN_LIQ_THRESHOLD, - OSTOKEN_LIQ_BONUS, - OSTOKEN_LTV, - dao - ) - - // 7. deploys osTokenVaultEscrowAuthMock - const osTokenVaultEscrowAuthMock = await createOsTokenVaultEscrowAuthMock(dao) - - // 8. deploys osTokenVaultEscrow - const osTokenVaultEscrow = await createOsTokenVaultEscrow( - osTokenVaultController, - osTokenConfig, - dao, - osTokenVaultEscrowAuthMock, - OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD, - OSTOKEN_VAULT_ESCROW_LIQ_BONUS - ) - // add to the vaults registry - await vaultsRegistry.addVault(await osTokenVaultEscrow.getAddress()) - - // 8. deploy OsTokenFlashLoans - const osTokenFlashLoans = await createOsTokenFlashLoans(osToken) - await osToken.setController(await osTokenFlashLoans.getAddress(), true) - - // 9. deploy depositDataRegistry - const depositDataRegistry = await createDepositDataRegistry(vaultsRegistry) - - // 10. deploy implementations and factories - const factories = {} - const implementations = {} - - for (const vaultType of [ - 'EthVault', - 'EthPrivVault', - 'EthErc20Vault', - 'EthPrivErc20Vault', - 'EthBlocklistVault', - 'EthBlocklistErc20Vault', - 'EthVaultMock', - ]) { - const vaultImpl = await deployEthVaultImplementation( - vaultType, - keeper, - vaultsRegistry, - await validatorsRegistry.getAddress(), - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - EXITING_ASSETS_MIN_DELAY - ) - await vaultsRegistry.addVaultImpl(vaultImpl) - implementations[vaultType] = vaultImpl - - const vaultFactory = await createEthVaultFactory(vaultImpl, vaultsRegistry) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - factories[vaultType] = vaultFactory - } - - // change ownership - await transferOwnership(vaultsRegistry, dao) - await transferOwnership(keeper, dao) - - const ethVaultFactory = factories['EthVault'] - const ethPrivVaultFactory = factories['EthPrivVault'] - const ethErc20VaultFactory = factories['EthErc20Vault'] - const ethPrivErc20VaultFactory = factories['EthPrivErc20Vault'] - const ethBlocklistVaultFactory = factories['EthBlocklistVault'] - const ethBlocklistErc20VaultFactory = factories['EthBlocklistErc20Vault'] - - return { - vaultsRegistry, - sharedMevEscrow, - depositDataRegistry, - keeper, - validatorsRegistry, - ethVaultFactory, - ethPrivVaultFactory, - ethErc20VaultFactory, - ethPrivErc20VaultFactory, - ethBlocklistVaultFactory, - ethBlocklistErc20VaultFactory, - osTokenVaultController, - osTokenConfig, - osToken, - osTokenVaultEscrow, - osTokenFlashLoans, - createEthVault: async ( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow = false, - skipFork = false - ): Promise => { - let vaultAddress: string - if (!MAINNET_FORK.enabled || skipFork) { - const tx = await ethVaultFactory - .connect(admin) - .createVault(encodeEthVaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - vaultAddress = await extractVaultAddress(tx) - return EthVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - } else if (isOwnMevEscrow) { - vaultAddress = MAINNET_FORK.vaults.ethVaultOwnMevEscrow - } else { - vaultAddress = MAINNET_FORK.vaults.ethVaultSharedMevEscrow - } - const vault = EthVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - await upgradeVault(vault, implementations['EthVault']) - await updateVaultState(keeper, vault, MAINNET_FORK.harvestParams[vaultAddress]) - await setBalance(await vault.admin(), parseEther('1000')) - return vault - }, - createEthFoxVault: async ( - admin: Signer, - vaultParams: EthVaultInitParamsStruct - ): Promise => { - const factory = await ethers.getContractFactory('EthFoxVault') - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const contract = await factory.deploy(...constructorArgs) - const vaultImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, vaultImpl) - - const proxyFactory = await ethers.getContractFactory('ERC1967Proxy') - const proxy = await proxyFactory.deploy(vaultImpl, '0x') - const vault = EthFoxVault__factory.connect( - await proxy.getAddress(), - await ethers.provider.getSigner() - ) - const adminAddr = await admin.getAddress() - - const ownMevEscrowFactory = await ethers.getContractFactory('OwnMevEscrow') - const ownMevEscrow = await ownMevEscrowFactory.deploy(await vault.getAddress()) - - await vault.initialize( - ethers.AbiCoder.defaultAbiCoder().encode( - [ - 'tuple(address admin, address ownMevEscrow, uint256 capacity, uint16 feePercent, string metadataIpfsHash)', - ], - [ - [ - adminAddr, - await ownMevEscrow.getAddress(), - vaultParams.capacity, - vaultParams.feePercent, - vaultParams.metadataIpfsHash, - ], - ] - ), - { value: SECURITY_DEPOSIT } - ) - await vaultsRegistry.addVault(await proxy.getAddress()) - return vault - }, - createEthVaultMock: async ( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await factories['EthVaultMock'] - .connect(admin) - .createVault(encodeEthVaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - const vaultAddress = await extractVaultAddress(tx) - return EthVaultMock__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createEthPrivVault: async ( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - let vaultAddress: string - if (!MAINNET_FORK.enabled) { - const tx = await ethPrivVaultFactory - .connect(admin) - .createVault(encodeEthVaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - vaultAddress = await extractVaultAddress(tx) - return EthPrivVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - } else if (isOwnMevEscrow) { - vaultAddress = MAINNET_FORK.vaults.ethPrivVaultOwnMevEscrow - } else { - vaultAddress = MAINNET_FORK.vaults.ethPrivVaultSharedMevEscrow - } - const vault = EthPrivVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - await upgradeVault(vault, implementations['EthPrivVault']) - await updateVaultState(keeper, vault, MAINNET_FORK.harvestParams[vaultAddress]) - await setBalance(await vault.admin(), parseEther('1000')) - return vault - }, - createEthBlocklistVault: async ( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethBlocklistVaultFactory - .connect(admin) - .createVault(encodeEthVaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - const vaultAddress = await extractVaultAddress(tx) - return EthBlocklistVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createEthErc20Vault: async ( - admin: Signer, - vaultParams: EthErc20VaultInitParamsStruct, - isOwnMevEscrow = false, - skipFork = false - ): Promise => { - let vaultAddress: string - if (!MAINNET_FORK.enabled || skipFork) { - const tx = await ethErc20VaultFactory - .connect(admin) - .createVault(encodeEthErc20VaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - vaultAddress = await extractVaultAddress(tx) - return EthErc20Vault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - } else if (isOwnMevEscrow) { - vaultAddress = MAINNET_FORK.vaults.ethErc20VaultOwnMevEscrow - } else { - vaultAddress = MAINNET_FORK.vaults.ethErc20VaultSharedMevEscrow - } - const vault = EthErc20Vault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - await upgradeVault(vault, implementations['EthErc20Vault']) - await updateVaultState(keeper, vault, MAINNET_FORK.harvestParams[vaultAddress]) - await setBalance(await vault.admin(), parseEther('1000')) - return vault - }, - createEthPrivErc20Vault: async ( - admin: Signer, - vaultParams: EthErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - let vaultAddress: string - if (!MAINNET_FORK.enabled) { - const tx = await ethPrivErc20VaultFactory - .connect(admin) - .createVault(encodeEthErc20VaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - vaultAddress = await extractVaultAddress(tx) - return EthPrivErc20Vault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - } else if (isOwnMevEscrow) { - vaultAddress = MAINNET_FORK.vaults.ethPrivErc20VaultOwnMevEscrow - } else { - vaultAddress = MAINNET_FORK.vaults.ethPrivErc20VaultSharedMevEscrow - } - const vault = EthPrivErc20Vault__factory.connect( - vaultAddress, - await ethers.provider.getSigner() - ) - await upgradeVault(vault, implementations['EthPrivErc20Vault']) - await setBalance(await vault.admin(), parseEther('1000')) - return vault - }, - createEthBlocklistErc20Vault: async ( - admin: Wallet, - vaultParams: EthErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - const tx = await ethBlocklistErc20VaultFactory - .connect(admin) - .createVault(encodeEthErc20VaultInitParams(vaultParams), isOwnMevEscrow, { - value: SECURITY_DEPOSIT, - }) - const vaultAddress = await extractVaultAddress(tx) - return EthBlocklistErc20Vault__factory.connect( - vaultAddress, - await ethers.provider.getSigner() - ) - }, - createEthGenesisVault: async ( - admin: Signer, - vaultParams: EthVaultInitParamsStruct, - skipFork: boolean = false - ): Promise<[EthGenesisVault, LegacyRewardTokenMock, PoolEscrowMock]> => { - let poolEscrow: PoolEscrowMock, rewardEthToken: LegacyRewardTokenMock - if (!MAINNET_FORK.enabled || skipFork) { - poolEscrow = await createPoolEscrow(dao.address, skipFork) - const legacyRewardTokenMockFactory = - await ethers.getContractFactory('LegacyRewardTokenMock') - const legacyRewardTokenMock = await legacyRewardTokenMockFactory.deploy() - rewardEthToken = LegacyRewardTokenMock__factory.connect( - await legacyRewardTokenMock.getAddress(), - dao - ) - } else { - poolEscrow = PoolEscrowMock__factory.connect(NETWORKS.mainnet.genesisVault.poolEscrow, dao) - rewardEthToken = LegacyRewardTokenMock__factory.connect( - NETWORKS.mainnet.genesisVault.rewardToken, - dao - ) - } - - const vaultImpl = await deployEthGenesisVaultImpl( - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - poolEscrow, - rewardEthToken - ) - await vaultsRegistry.addVaultImpl(vaultImpl) - - let vault: EthGenesisVault - if (!MAINNET_FORK.enabled || skipFork) { - const proxyFactory = await ethers.getContractFactory('ERC1967Proxy') - const proxy = await proxyFactory.deploy(vaultImpl, '0x') - const proxyAddress = await proxy.getAddress() - vault = EthGenesisVault__factory.connect(proxyAddress, await ethers.provider.getSigner()) - await rewardEthToken.connect(dao).setVault(proxyAddress) - await poolEscrow.connect(dao).commitOwnershipTransfer(proxyAddress) - const adminAddr = await admin.getAddress() - await vault.initialize( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [ - adminAddr, - [vaultParams.capacity, vaultParams.feePercent, vaultParams.metadataIpfsHash], - ] - ), - { value: SECURITY_DEPOSIT } - ) - await vaultsRegistry.addVault(proxyAddress) - } else { - vault = EthGenesisVault__factory.connect( - mainnetDeployment.EthGenesisVault, - await ethers.provider.getSigner() - ) - await upgradeVault(vault, vaultImpl) - await updateVaultState( - keeper, - vault, - MAINNET_FORK.harvestParams[mainnetDeployment.EthGenesisVault] - ) - } - await setBalance(await vault.admin(), parseEther('1000')) - return [vault, rewardEthToken, poolEscrow] - }, - } -} diff --git a/test/shared/gnoFixtures.ts b/test/shared/gnoFixtures.ts deleted file mode 100644 index cc3c2237..00000000 --- a/test/shared/gnoFixtures.ts +++ /dev/null @@ -1,855 +0,0 @@ -import hre, { ethers } from 'hardhat' -import { - BigNumberish, - Contract, - ContractFactory, - ContractTransactionResponse, - parseEther, - Signer, - Wallet, -} from 'ethers' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import EthereumWallet from 'ethereumjs-wallet' -import { - BalancerVaultMock, - BalancerVaultMock__factory, - DepositDataRegistry, - ERC20Mock, - ERC20Mock__factory, - GnoBlocklistErc20Vault, - GnoBlocklistErc20Vault__factory, - GnoBlocklistVault, - GnoBlocklistVault__factory, - GnoErc20Vault, - GnoErc20Vault__factory, - GnoGenesisVault, - GnoGenesisVault__factory, - GnoPrivErc20Vault, - GnoPrivErc20Vault__factory, - GnoPrivVault, - GnoPrivVault__factory, - GnoSharedMevEscrow, - GnoValidatorsChecker__factory, - GnoVault, - GnoVault__factory, - GnoVaultFactory, - GnoVaultFactory__factory, - Keeper, - LegacyRewardTokenMock, - LegacyRewardTokenMock__factory, - OsToken, - OsTokenConfig, - OsTokenVaultController, - OsTokenVaultEscrow, - OsTokenVaultEscrow__factory, - OsTokenVaultEscrowAuthMock, - PoolEscrowMock, - PriceFeedMock, - PriceFeedMock__factory, - SharedMevEscrow, - SharedMevEscrow__factory, - VaultsRegistry, - XdaiExchange, - XdaiExchange__factory, -} from '../../typechain-types' -import { getGnoValidatorsRegistryFactory } from './contracts' -import { - EXITING_ASSETS_MIN_DELAY, - MAX_AVG_REWARD_PER_SECOND, - ONE_DAY, - ORACLES, - ORACLES_CONFIG, - OSTOKEN_CAPACITY, - OSTOKEN_FEE, - OSTOKEN_LIQ_BONUS, - OSTOKEN_LIQ_THRESHOLD, - OSTOKEN_LTV, - OSTOKEN_NAME, - OSTOKEN_SYMBOL, - OSTOKEN_VAULT_ESCROW_LIQ_BONUS, - OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD, - REWARDS_DELAY, - REWARDS_MIN_ORACLES, - SECURITY_DEPOSIT, - VALIDATORS_MIN_ORACLES, - XDAI_EXCHANGE_MAX_SLIPPAGE, - XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA, - ZERO_ADDRESS, - ZERO_BYTES32, -} from './constants' -import { GnoErc20VaultInitParamsStruct, GnoVaultInitParamsStruct, GnoVaultType } from './types' -import { - extractDepositShares, - extractExitPositionTicket, - extractVaultAddress, - getBlockTimestamp, - getLatestBlockTimestamp, - increaseTime, - setBalance, -} from './utils' -import { - createDepositDataRegistry, - createKeeper, - createOsToken, - createOsTokenConfig, - createOsTokenVaultController, - createOsTokenVaultEscrowAuthMock, - createPoolEscrow, - createVaultsRegistry, - transferOwnership, -} from './fixtures' -import { registerEthValidator } from './validators' -import { getHarvestParams, getRewardsRootProof, updateRewards } from './rewards' - -export const setGnoWithdrawals = async function ( - validatorsRegistry: Contract, - gnoToken: ERC20Mock, - vault: GnoVault | PoolEscrowMock, - withdrawals: bigint -): Promise { - const systemAddr = '0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE' - const system = await ethers.getImpersonatedSigner(systemAddr) - await setBalance(systemAddr, ethers.parseEther('1')) - await gnoToken.mint(await validatorsRegistry.getAddress(), withdrawals) - await validatorsRegistry - .connect(system) - .executeSystemWithdrawals( - [(withdrawals * parseEther('32')) / parseEther('1') / 1000000000n], - [await vault.getAddress()] - ) -} - -export async function collateralizeGnoVault( - vault: GnoVaultType, - gnoToken: ERC20Mock, - keeper: Keeper, - depositDataRegistry: DepositDataRegistry, - admin: Wallet, - validatorsRegistry: Contract -) { - const signer = (await ethers.getSigners())[0] - try { - await (vault).connect(admin).updateWhitelist(await signer.getAddress(), true) - } catch { - /* empty */ - } - const vaultAddress = await vault.getAddress() - const balanceBefore = await ethers.provider.getBalance(vaultAddress) - - // register validator - const validatorDeposit = ethers.parseEther('1') - const tx = await depositGno(vault, gnoToken, validatorDeposit, signer, signer, ZERO_ADDRESS) - const receivedShares = await extractDepositShares(tx) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - // update rewards tree - const vaultReward = getHarvestParams(vaultAddress, 0n, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - - // exit validator - const response = await vault - .connect(signer) - .enterExitQueue(receivedShares, await signer.getAddress()) - const positionTicket = await extractExitPositionTicket(response) - const timestamp = await getBlockTimestamp(response) - - await increaseTime(EXITING_ASSETS_MIN_DELAY) - await setGnoWithdrawals(validatorsRegistry, gnoToken, vault, validatorDeposit) - - await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - // claim exited assets - const exitQueueIndex = await vault.getExitQueueIndex(positionTicket) - await vault.connect(signer).claimExitedAssets(positionTicket, timestamp, exitQueueIndex) - - await increaseTime(ONE_DAY) - await setBalance(vaultAddress, balanceBefore) -} - -export const depositGno = async function ( - vault: GnoVault, - gnoToken: ERC20Mock, - assets: bigint, - sender: Wallet, - receiver: Wallet, - referrer: string -): Promise { - await gnoToken.mint(await sender.getAddress(), assets) - await gnoToken.connect(sender).approve(await vault.getAddress(), assets) - return await vault.connect(sender).deposit(assets, await receiver.getAddress(), referrer) -} - -export const createGnoValidatorsRegistry = async function (gnoToken: ERC20Mock): Promise { - const validatorsRegistryFactory = await getGnoValidatorsRegistryFactory() - const signer = await ethers.provider.getSigner() - const contract = await validatorsRegistryFactory.deploy(await gnoToken.getAddress()) - return new Contract(await contract.getAddress(), validatorsRegistryFactory.interface, signer) -} - -export const approveSecurityDeposit = async function ( - approvedAddr: string, - gnoToken: ERC20Mock, - admin: Signer -): Promise { - await gnoToken.mint(await admin.getAddress(), SECURITY_DEPOSIT) - await gnoToken.connect(admin).approve(approvedAddr, SECURITY_DEPOSIT) -} - -export const createGnoSharedMevEscrow = async function ( - vaultsRegistry: VaultsRegistry -): Promise { - const signer = await ethers.provider.getSigner() - const factory = await ethers.getContractFactory('GnoSharedMevEscrow') - const contract = await factory.deploy(await vaultsRegistry.getAddress()) - return SharedMevEscrow__factory.connect(await contract.getAddress(), signer) -} - -export const createOsTokenVaultEscrow = async function ( - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - owner: Wallet, - escrowAuth: OsTokenVaultEscrowAuthMock, - gnoToken: ERC20Mock, - liqThresholdPercent: BigNumberish, - liqBonusPercent: BigNumberish -): Promise { - const signer = await ethers.provider.getSigner() - const factory = await ethers.getContractFactory('GnoOsTokenVaultEscrow') - const contract = await factory.deploy( - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - owner.address, - await escrowAuth.getAddress(), - liqThresholdPercent, - liqBonusPercent, - await gnoToken.getAddress() - ) - return OsTokenVaultEscrow__factory.connect(await contract.getAddress(), signer) -} - -export const createBalancerVaultMock = async function ( - gnoToken: ERC20Mock, - daiGnoRate: BigNumberish, - dao: Signer -): Promise { - const factory = await ethers.getContractFactory('BalancerVaultMock') - const contract = await factory.deploy( - await gnoToken.getAddress(), - daiGnoRate, - await dao.getAddress() - ) - return BalancerVaultMock__factory.connect(await contract.getAddress(), dao) -} - -export const createPriceFeedMock = async function ( - dao: Signer, - description: string -): Promise { - const factory = await ethers.getContractFactory('PriceFeedMock') - const contract = await factory.connect(dao).deploy(description) - return PriceFeedMock__factory.connect(await contract.getAddress(), dao) -} - -export const createXdaiExchange = async function ( - gnoToken: ERC20Mock, - daiPriceFeed: PriceFeedMock, - gnoPriceFeed: PriceFeedMock, - balancerVault: BalancerVaultMock, - balancerPoolId: string, - maxSlippage: number, - stalePriceTimeDelta: number, - vaultsRegistry: VaultsRegistry, - dao: Signer -): Promise { - const factory = await ethers.getContractFactory('XdaiExchange') - - const constructorArgs = [ - await gnoToken.getAddress(), - await balancerVault.getAddress(), - await vaultsRegistry.getAddress(), - await daiPriceFeed.getAddress(), - await gnoPriceFeed.getAddress(), - ] - const contract = await factory.deploy(...constructorArgs) - const impl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, impl) - - const proxyFactory = await ethers.getContractFactory('ERC1967Proxy') - const proxy = await proxyFactory.deploy(impl, '0x') - const proxyAddress = await proxy.getAddress() - const xdaiExchange = XdaiExchange__factory.connect(proxyAddress, dao) - await xdaiExchange.initialize( - await dao.getAddress(), - maxSlippage, - stalePriceTimeDelta, - balancerPoolId - ) - return xdaiExchange -} - -export const createGnoVaultFactory = async function ( - implementation: string, - vaultsRegistry: VaultsRegistry, - gnoToken: ERC20Mock -): Promise { - const factory = await ethers.getContractFactory('GnoVaultFactory') - const contract = await factory.deploy( - implementation, - await vaultsRegistry.getAddress(), - await gnoToken.getAddress() - ) - return GnoVaultFactory__factory.connect( - await contract.getAddress(), - await ethers.provider.getSigner() - ) -} - -export const deployGnoGenesisVaultImpl = async function ( - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - osTokenVaultEscrow: OsTokenVaultEscrow, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - gnoToken: ERC20Mock, - xdaiExchange: XdaiExchange, - poolEscrow: PoolEscrowMock, - rewardGnoToken: LegacyRewardTokenMock -): Promise { - const factory = await ethers.getContractFactory('GnoGenesisVault') - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await osTokenVaultEscrow.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - await gnoToken.getAddress(), - await xdaiExchange.getAddress(), - await poolEscrow.getAddress(), - await rewardGnoToken.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const contract = await factory.deploy(...constructorArgs) - const vaultImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, vaultImpl) - return vaultImpl -} - -export const deployGnoVaultImplementation = async function ( - vaultType: string, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: string, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - osTokenVaultEscrow: OsTokenVaultEscrow, - sharedMevEscrow: GnoSharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - gnoToken: ERC20Mock, - xdaiExchange: XdaiExchange, - exitingAssetsMinDelay: number -): Promise { - const factory = await ethers.getContractFactory(vaultType) - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - validatorsRegistry, - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await osTokenVaultEscrow.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - await gnoToken.getAddress(), - await xdaiExchange.getAddress(), - exitingAssetsMinDelay, - ] - const contract = await factory.deploy(...constructorArgs) - const vaultImpl = await contract.getAddress() - await simulateDeployImpl(hre, factory, { constructorArgs }, vaultImpl) - return vaultImpl -} - -export async function deployGnoVaultV2( - implFactory: ContractFactory, - admin: Signer, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - validatorsRegistry: Contract, - osTokenVaultController: OsTokenVaultController, - osTokenConfig: OsTokenConfig, - sharedMevEscrow: SharedMevEscrow, - depositDataRegistry: DepositDataRegistry, - gnoToken: ERC20Mock, - xdaiExchange: XdaiExchange, - encodedParams: string, - isOwnMevEscrow = false -): Promise { - const constructorArgs = [ - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await validatorsRegistry.getAddress(), - await osTokenVaultController.getAddress(), - await osTokenConfig.getAddress(), - await sharedMevEscrow.getAddress(), - await depositDataRegistry.getAddress(), - await gnoToken.getAddress(), - await xdaiExchange.getAddress(), - EXITING_ASSETS_MIN_DELAY, - ] - const vaultImpl = await implFactory.deploy(...constructorArgs) - const vaultImplAddr = await vaultImpl.getAddress() - await vaultsRegistry.addVaultImpl(vaultImplAddr) - - const vaultFactory = await createGnoVaultFactory(vaultImplAddr, vaultsRegistry, gnoToken) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - - await approveSecurityDeposit(await vaultFactory.getAddress(), gnoToken, admin) - const tx = await vaultFactory.connect(admin).createVault(encodedParams, isOwnMevEscrow) - return new Contract( - await extractVaultAddress(tx), - implFactory.interface, - await ethers.provider.getSigner() - ) -} - -export const encodeGnoVaultInitParams = function (vaultParams: GnoVaultInitParamsStruct): string { - return ethers.AbiCoder.defaultAbiCoder().encode( - ['tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [[vaultParams.capacity, vaultParams.feePercent, vaultParams.metadataIpfsHash]] - ) -} - -export const encodeGnoErc20VaultInitParams = function ( - vaultParams: GnoErc20VaultInitParamsStruct -): string { - return ethers.AbiCoder.defaultAbiCoder().encode( - [ - 'tuple(uint256 capacity, uint16 feePercent, string name, string symbol, string metadataIpfsHash)', - ], - [ - [ - vaultParams.capacity, - vaultParams.feePercent, - vaultParams.name, - vaultParams.symbol, - vaultParams.metadataIpfsHash, - ], - ] - ) -} - -interface GnoVaultFixture { - vaultsRegistry: VaultsRegistry - keeper: Keeper - sharedMevEscrow: SharedMevEscrow - depositDataRegistry: DepositDataRegistry - validatorsRegistry: Contract - gnoVaultFactory: GnoVaultFactory - gnoPrivVaultFactory: GnoVaultFactory - gnoErc20VaultFactory: GnoVaultFactory - gnoPrivErc20VaultFactory: GnoVaultFactory - gnoBlocklistVaultFactory: GnoVaultFactory - gnoBlocklistErc20VaultFactory: GnoVaultFactory - osToken: OsToken - osTokenVaultEscrow: OsTokenVaultEscrow - osTokenVaultController: OsTokenVaultController - osTokenConfig: OsTokenConfig - xdaiExchange: XdaiExchange - gnoPriceFeed: PriceFeedMock - daiPriceFeed: PriceFeedMock - gnoToken: ERC20Mock - balancerVault: BalancerVaultMock - - createGnoVault( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createGnoPrivVault( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createGnoBlocklistVault( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createGnoErc20Vault( - admin: Signer, - vaultParams: GnoErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createGnoPrivErc20Vault( - admin: Signer, - vaultParams: GnoErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createGnoBlocklistErc20Vault( - admin: Signer, - vaultParams: GnoErc20VaultInitParamsStruct, - isOwnMevEscrow?: boolean - ): Promise - - createGnoGenesisVault( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct - ): Promise<[GnoGenesisVault, LegacyRewardTokenMock, PoolEscrowMock]> -} - -export const gnoVaultFixture = async function (): Promise { - const dao = await (ethers as any).provider.getSigner() - const vaultsRegistry = await createVaultsRegistry(true) - - const factory = await ethers.getContractFactory('ERC20Mock') - const contract = await factory.connect(dao).deploy() - const gnoToken = ERC20Mock__factory.connect(await contract.getAddress(), dao) - const validatorsRegistry = await createGnoValidatorsRegistry(gnoToken) - - const sharedMevEscrow = await createGnoSharedMevEscrow(vaultsRegistry) - - // 1. calc osToken address - const _osTokenAddress = ethers.getCreateAddress({ - from: dao.address, - nonce: (await ethers.provider.getTransactionCount(dao.address)) + 1, - }) - - // 2. calc keeper address - const _keeperAddress = ethers.getCreateAddress({ - from: dao.address, - nonce: (await ethers.provider.getTransactionCount(dao.address)) + 2, - }) - - // 3. deploy osTokenVaultController - const osTokenVaultController = await createOsTokenVaultController( - _keeperAddress, - vaultsRegistry, - _osTokenAddress, - dao, - dao, - OSTOKEN_FEE, - OSTOKEN_CAPACITY, - true - ) - - // 4. deploy osToken - const osToken = await createOsToken( - dao, - osTokenVaultController, - OSTOKEN_NAME, - OSTOKEN_SYMBOL, - true - ) - if (_osTokenAddress != (await osToken.getAddress())) { - throw new Error('Invalid calculated OsToken address') - } - - // 5. deploy keeper - const sortedOracles = ORACLES.sort((oracle1, oracle2) => { - const oracle1Addr = new EthereumWallet(oracle1).getAddressString() - const oracle2Addr = new EthereumWallet(oracle2).getAddressString() - return oracle1Addr > oracle2Addr ? 1 : -1 - }) - const keeper = await createKeeper( - sortedOracles.map((s) => new EthereumWallet(s).getAddressString()), - ORACLES_CONFIG, - sharedMevEscrow, - vaultsRegistry, - osTokenVaultController, - REWARDS_DELAY, - MAX_AVG_REWARD_PER_SECOND, - REWARDS_MIN_ORACLES, - validatorsRegistry, - VALIDATORS_MIN_ORACLES, - true - ) - if (_keeperAddress != (await keeper.getAddress())) { - throw new Error('Invalid calculated Keeper address') - } - - // 6. deploy osTokenConfig - const osTokenConfig = await createOsTokenConfig( - dao, - OSTOKEN_LIQ_THRESHOLD, - OSTOKEN_LIQ_BONUS, - OSTOKEN_LTV, - dao, - true - ) - - // 7. deploys osTokenVaultEscrowAuthMock - const osTokenVaultEscrowAuthMock = await createOsTokenVaultEscrowAuthMock(dao) - - // 8. deploys osTokenVaultEscrow - const osTokenVaultEscrow = await createOsTokenVaultEscrow( - osTokenVaultController, - osTokenConfig, - dao, - osTokenVaultEscrowAuthMock, - gnoToken, - OSTOKEN_VAULT_ESCROW_LIQ_THRESHOLD, - OSTOKEN_VAULT_ESCROW_LIQ_BONUS - ) - // add to the vaults registry - await vaultsRegistry.addVault(await osTokenVaultEscrow.getAddress()) - - // 9. deploy Balancer vault - const balancerVault = await createBalancerVaultMock(gnoToken, parseEther('0.0025'), dao) - - // 10. deploy GNO, XDAI price feeds, XdaiExchange - const gnoPriceFeed = await createPriceFeedMock(dao, 'GNO / USD') - const latestTimestamp = await getLatestBlockTimestamp() - await gnoPriceFeed.setLatestAnswer(parseEther('0.00000004')) - await gnoPriceFeed.setLatestTimestamp(latestTimestamp) - const daiPriceFeed = await createPriceFeedMock(dao, 'DAI / USD') - await daiPriceFeed.setLatestAnswer(parseEther('0.0000000001')) - await daiPriceFeed.setLatestTimestamp(latestTimestamp) - const xdaiExchange = await createXdaiExchange( - gnoToken, - daiPriceFeed, - gnoPriceFeed, - balancerVault, - ZERO_BYTES32, - XDAI_EXCHANGE_MAX_SLIPPAGE, - XDAI_EXCHANGE_STALE_PRICE_TIME_DELTA, - vaultsRegistry, - dao - ) - - // 11. deploy DepositDataRegistry - const depositDataRegistry = await createDepositDataRegistry(vaultsRegistry, true) - - // 12. deploy implementations and factories - const factories = {} - const implementations = {} - - for (const vaultType of [ - 'GnoVault', - 'GnoPrivVault', - 'GnoErc20Vault', - 'GnoPrivErc20Vault', - 'GnoBlocklistVault', - 'GnoBlocklistErc20Vault', - ]) { - const vaultImpl = await deployGnoVaultImplementation( - vaultType, - keeper, - vaultsRegistry, - await validatorsRegistry.getAddress(), - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - EXITING_ASSETS_MIN_DELAY - ) - await vaultsRegistry.addVaultImpl(vaultImpl) - implementations[vaultType] = vaultImpl - - const vaultFactory = await createGnoVaultFactory(vaultImpl, vaultsRegistry, gnoToken) - await vaultsRegistry.addFactory(await vaultFactory.getAddress()) - factories[vaultType] = vaultFactory - } - - // change ownership - await transferOwnership(vaultsRegistry, dao) - await transferOwnership(keeper, dao) - - const gnoVaultFactory = factories['GnoVault'] - const gnoPrivVaultFactory = factories['GnoPrivVault'] - const gnoErc20VaultFactory = factories['GnoErc20Vault'] - const gnoPrivErc20VaultFactory = factories['GnoPrivErc20Vault'] - const gnoBlocklistVaultFactory = factories['GnoBlocklistVault'] - const gnoBlocklistErc20VaultFactory = factories['GnoBlocklistErc20Vault'] - - return { - vaultsRegistry, - sharedMevEscrow, - depositDataRegistry, - keeper, - validatorsRegistry, - gnoVaultFactory, - gnoPrivVaultFactory, - gnoErc20VaultFactory, - gnoPrivErc20VaultFactory, - gnoBlocklistVaultFactory, - gnoBlocklistErc20VaultFactory, - osTokenVaultController, - osTokenConfig, - osToken, - osTokenVaultEscrow, - gnoPriceFeed, - daiPriceFeed, - xdaiExchange, - gnoToken, - balancerVault, - createGnoVault: async ( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - await approveSecurityDeposit(await gnoVaultFactory.getAddress(), gnoToken, admin) - const tx = await gnoVaultFactory - .connect(admin) - .createVault(encodeGnoVaultInitParams(vaultParams), isOwnMevEscrow) - const vaultAddress = await extractVaultAddress(tx) - return GnoVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createGnoPrivVault: async ( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - await approveSecurityDeposit(await gnoPrivVaultFactory.getAddress(), gnoToken, admin) - const tx = await gnoPrivVaultFactory - .connect(admin) - .createVault(encodeGnoVaultInitParams(vaultParams), isOwnMevEscrow) - const vaultAddress = await extractVaultAddress(tx) - return GnoPrivVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createGnoBlocklistVault: async ( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - await approveSecurityDeposit(await gnoBlocklistVaultFactory.getAddress(), gnoToken, admin) - const tx = await gnoBlocklistVaultFactory - .connect(admin) - .createVault(encodeGnoVaultInitParams(vaultParams), isOwnMevEscrow) - const vaultAddress = await extractVaultAddress(tx) - return GnoBlocklistVault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createGnoErc20Vault: async ( - admin: Signer, - vaultParams: GnoErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - await approveSecurityDeposit(await gnoErc20VaultFactory.getAddress(), gnoToken, admin) - const tx = await gnoErc20VaultFactory - .connect(admin) - .createVault(encodeGnoErc20VaultInitParams(vaultParams), isOwnMevEscrow) - const vaultAddress = await extractVaultAddress(tx) - return GnoErc20Vault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createGnoPrivErc20Vault: async ( - admin: Signer, - vaultParams: GnoErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - await approveSecurityDeposit(await gnoPrivErc20VaultFactory.getAddress(), gnoToken, admin) - const tx = await gnoPrivErc20VaultFactory - .connect(admin) - .createVault(encodeGnoErc20VaultInitParams(vaultParams), isOwnMevEscrow) - const vaultAddress = await extractVaultAddress(tx) - return GnoPrivErc20Vault__factory.connect(vaultAddress, await ethers.provider.getSigner()) - }, - createGnoBlocklistErc20Vault: async ( - admin: Wallet, - vaultParams: GnoErc20VaultInitParamsStruct, - isOwnMevEscrow = false - ): Promise => { - await approveSecurityDeposit( - await gnoBlocklistErc20VaultFactory.getAddress(), - gnoToken, - admin - ) - const tx = await gnoBlocklistErc20VaultFactory - .connect(admin) - .createVault(encodeGnoErc20VaultInitParams(vaultParams), isOwnMevEscrow) - const vaultAddress = await extractVaultAddress(tx) - return GnoBlocklistErc20Vault__factory.connect( - vaultAddress, - await ethers.provider.getSigner() - ) - }, - createGnoGenesisVault: async ( - admin: Signer, - vaultParams: GnoVaultInitParamsStruct - ): Promise<[GnoGenesisVault, LegacyRewardTokenMock, PoolEscrowMock]> => { - const poolEscrow = await createPoolEscrow(dao.address, true) - const legacyRewardTokenMockFactory = await ethers.getContractFactory('LegacyRewardTokenMock') - const legacyRewardTokenMock = await legacyRewardTokenMockFactory.deploy() - const rewardGnoToken = LegacyRewardTokenMock__factory.connect( - await legacyRewardTokenMock.getAddress(), - dao - ) - - const vaultImpl = await deployGnoGenesisVaultImpl( - keeper, - vaultsRegistry, - validatorsRegistry, - osTokenVaultController, - osTokenConfig, - osTokenVaultEscrow, - sharedMevEscrow, - depositDataRegistry, - gnoToken, - xdaiExchange, - poolEscrow, - rewardGnoToken - ) - await vaultsRegistry.addVaultImpl(vaultImpl) - - const proxyFactory = await ethers.getContractFactory('ERC1967Proxy') - const proxy = await proxyFactory.deploy(vaultImpl, '0x') - const proxyAddress = await proxy.getAddress() - const vault = GnoGenesisVault__factory.connect( - proxyAddress, - await ethers.provider.getSigner() - ) - await rewardGnoToken.connect(dao).setVault(proxyAddress) - await poolEscrow.connect(dao).commitOwnershipTransfer(proxyAddress) - const adminAddr = await admin.getAddress() - await approveSecurityDeposit(await vault.getAddress(), gnoToken, admin) - - await vault - .connect(admin) - .initialize( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [ - adminAddr, - [vaultParams.capacity, vaultParams.feePercent, vaultParams.metadataIpfsHash], - ] - ) - ) - await vaultsRegistry.addVault(proxyAddress) - return [vault, rewardGnoToken, poolEscrow] - }, - } -} - -export const createGnoValidatorsChecker = async function ( - validatorsRegistry: Contract, - keeper: Keeper, - vaultsRegistry: VaultsRegistry, - depositDataRegistry: DepositDataRegistry -) { - const signer = await ethers.provider.getSigner() - const factory = await ethers.getContractFactory('GnoValidatorsChecker') - const contract = await factory.deploy( - await validatorsRegistry.getAddress(), - await keeper.getAddress(), - await vaultsRegistry.getAddress(), - await depositDataRegistry.getAddress() - ) - return GnoValidatorsChecker__factory.connect(await contract.getAddress(), signer) -} diff --git a/test/shared/rewards.ts b/test/shared/rewards.ts deleted file mode 100644 index 403cedac..00000000 --- a/test/shared/rewards.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { ethers, network } from 'hardhat' -import { Contract, Signer } from 'ethers' -import { StandardMerkleTree } from '@openzeppelin/merkle-tree' -import { - EthVault, - IKeeperRewards, - Keeper, - DepositDataRegistry, - EthPrivVault, -} from '../../typechain-types' -import { - EIP712Domain, - EXITING_ASSETS_MIN_DELAY, - KeeperRewardsSig, - MAX_AVG_REWARD_PER_SECOND, - ONE_DAY, - ORACLES, - REWARDS_DELAY, - ZERO_ADDRESS, -} from './constants' -import { registerEthValidator } from './validators' -import { - extractDepositShares, - extractExitPositionTicket, - getBlockTimestamp, - increaseTime, - setBalance, -} from './utils' -import { getOraclesSignatures } from './fixtures' -import { MAINNET_FORK } from '../../helpers/constants' -import { EthVaultType } from './types' - -export type RewardsTree = StandardMerkleTree<[string, bigint, bigint]> - -export type RewardsUpdate = { - root: string - ipfsHash: string - updateTimestamp: number - avgRewardPerSecond: number - tree: RewardsTree - signingData: any -} - -export type VaultReward = { - vault: string - reward: bigint - unlockedMevReward: bigint -} - -function randomIntFromInterval(min, max): number { - return Math.floor(Math.random() * (max - min + 1) + min) -} - -export async function getKeeperRewardsUpdateData( - rewards: VaultReward[], - keeper: Keeper, - { nonce = 1, updateTimestamp = 1670255895, avgRewardPerSecond = 1585489600 } = {} -): Promise { - const tree = StandardMerkleTree.of( - rewards.map((r) => [r.vault, r.reward, r.unlockedMevReward]), - ['address', 'int160', 'uint160'] - ) as RewardsTree - - const treeRoot = tree.root - // mock IPFS hash - const ipfsHash = '/ipfs/' + treeRoot - - return { - root: treeRoot, - ipfsHash, - updateTimestamp, - avgRewardPerSecond, - tree, - signingData: { - primaryType: 'KeeperRewards', - types: { EIP712Domain, KeeperRewards: KeeperRewardsSig }, - domain: { - name: 'KeeperOracles', - version: '1', - chainId: network.config.chainId, - verifyingContract: await keeper.getAddress(), - }, - message: { - rewardsRoot: treeRoot, - rewardsIpfsHash: ipfsHash, - avgRewardPerSecond, - updateTimestamp, - nonce, - }, - }, - } -} - -export function getHarvestParams( - vault: string, - reward: bigint, - unlockedMevReward: bigint -): VaultReward { - const harvestParams = MAINNET_FORK.harvestParams[vault] - if (harvestParams) { - return { - vault, - reward: reward + harvestParams.reward, - unlockedMevReward: unlockedMevReward + harvestParams.unlockedMevReward, - } - } - return { - vault, - reward, - unlockedMevReward, - } -} - -export async function updateRewards( - keeper: Keeper, - rewards: VaultReward[], - avgRewardPerSecond: number = randomIntFromInterval(1, MAX_AVG_REWARD_PER_SECOND) -): Promise { - const rewardsNonce = await keeper.rewardsNonce() - const rewardsUpdate = await getKeeperRewardsUpdateData(rewards, keeper, { - nonce: Number(rewardsNonce), - avgRewardPerSecond, - }) - await increaseTime(REWARDS_DELAY) - const oracle = new ethers.Wallet(ORACLES[0].toString('hex'), ethers.provider) - await setBalance(oracle.address, ethers.parseEther('2000')) - - await keeper.connect(oracle).updateRewards({ - rewardsRoot: rewardsUpdate.root, - avgRewardPerSecond: rewardsUpdate.avgRewardPerSecond, - updateTimestamp: rewardsUpdate.updateTimestamp, - rewardsIpfsHash: rewardsUpdate.ipfsHash, - signatures: getOraclesSignatures(rewardsUpdate.signingData), - }) - return rewardsUpdate.tree -} - -export function getRewardsRootProof(tree: RewardsTree, vaultReward: VaultReward): string[] { - return tree.getProof([vaultReward.vault, vaultReward.reward, vaultReward.unlockedMevReward]) -} - -export async function collateralizeEthVault( - vault: EthVaultType, - keeper: Keeper, - depositDataRegistry: DepositDataRegistry, - admin: Signer, - validatorsRegistry: Contract -) { - const signer = (await ethers.getSigners())[0] - try { - await (vault).connect(admin).updateWhitelist(await signer.getAddress(), true) - } catch { - /* empty */ - } - const vaultAddress = await vault.getAddress() - const balanceBefore = await ethers.provider.getBalance(vaultAddress) - - // register validator - const validatorDeposit = ethers.parseEther('32') - const tx = await vault - .connect(signer) - .deposit(await signer.getAddress(), ZERO_ADDRESS, { value: validatorDeposit }) - const receivedShares = await extractDepositShares(tx) - await registerEthValidator(vault, keeper, depositDataRegistry, admin, validatorsRegistry) - - // update rewards tree - const vaultReward = getHarvestParams(vaultAddress, 0n, 0n) - const rewardsTree = await updateRewards(keeper, [vaultReward]) - const proof = getRewardsRootProof(rewardsTree, vaultReward) - - // exit validator - const response = await vault - .connect(signer) - .enterExitQueue(receivedShares, await signer.getAddress()) - const positionTicket = await extractExitPositionTicket(response) - const timestamp = await getBlockTimestamp(response) - - await increaseTime(EXITING_ASSETS_MIN_DELAY) - await setBalance(vaultAddress, validatorDeposit) - - await vault.updateState({ - rewardsRoot: rewardsTree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof, - }) - - // claim exited assets - const exitQueueIndex = await vault.getExitQueueIndex(positionTicket) - await vault.connect(signer).claimExitedAssets(positionTicket, timestamp, exitQueueIndex) - - await increaseTime(ONE_DAY) - await setBalance(vaultAddress, balanceBefore) -} - -export async function setAvgRewardPerSecond( - dao: Signer, - vault: EthVault, - keeper: Keeper, - avgRewardPerSecond: number -) { - const vaultAddress = await vault.getAddress() - const vaultReward = getHarvestParams(vaultAddress, 0n, 0n) - const tree = await updateRewards(keeper, [vaultReward], avgRewardPerSecond) - const harvestParams: IKeeperRewards.HarvestParamsStruct = { - rewardsRoot: tree.root, - reward: vaultReward.reward, - unlockedMevReward: vaultReward.unlockedMevReward, - proof: getRewardsRootProof(tree, { - vault: vaultAddress, - unlockedMevReward: vaultReward.unlockedMevReward, - reward: vaultReward.reward, - }), - } - await vault.connect(dao).updateState(harvestParams) -} diff --git a/test/shared/snapshotGasCost.ts b/test/shared/snapshotGasCost.ts deleted file mode 100644 index 2c7b5795..00000000 --- a/test/shared/snapshotGasCost.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider' -import { BigNumber } from '@ethersproject/bignumber' -import { ContractTransaction } from '@ethersproject/contracts' -import { ContractTransactionResponse } from 'ethers' -import { expect } from './expect' -import { MAINNET_FORK } from '../../helpers/constants' - -const COVERAGE = process.env.COVERAGE === 'true' - -// Inspired by https://github.com/Uniswap/snapshot-gas-cost -export default async function snapshotGasCost( - x: - | TransactionResponse - | ContractTransactionResponse - | Promise - | Promise - | TransactionResponse[] - | Promise[] - | ContractTransaction - | Promise - | TransactionReceipt - | Promise - | BigNumber - | Promise - | number - | bigint -): Promise { - if (COVERAGE || MAINNET_FORK.enabled) return Promise.resolve() - - const unpromised = await x - if (Array.isArray(unpromised)) { - const unpromisedDeep = await Promise.all(unpromised.map(async (p) => await p)) - const waited = await Promise.all(unpromisedDeep.map(async (p) => p.wait())) - expect({ - gasUsed: waited.reduce((m, v) => m + Number(v.gasUsed), 0), - calldataByteLength: unpromisedDeep.reduce((m, v) => m + v.data.length / 2 - 1, 0), - }).toMatchSnapshot() - } else if (typeof unpromised === 'number') { - expect(unpromised).toMatchSnapshot() - } else if (typeof unpromised === 'bigint') { - expect(Number(unpromised)).toMatchSnapshot() - } else if ('wait' in unpromised) { - const waited = (await unpromised.wait()) as TransactionReceipt - expect({ - gasUsed: Number(waited.gasUsed), - calldataByteLength: unpromised.data.length / 2 - 1, - }).toMatchSnapshot() - } else if (BigNumber.isBigNumber(unpromised)) { - expect(Number(unpromised)).toMatchSnapshot() - } -} diff --git a/test/shared/types.ts b/test/shared/types.ts deleted file mode 100644 index 0fc97075..00000000 --- a/test/shared/types.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - EthErc20Vault, - EthFoxVault, - EthGenesisVault, - EthPrivErc20Vault, - EthPrivVault, - EthVault, - EthBlocklistErc20Vault, - EthBlocklistVault, - GnoVault, - GnoPrivVault, - GnoErc20Vault, - GnoPrivErc20Vault, - GnoGenesisVault, -} from '../../typechain-types' - -export type EthVaultInitParamsStruct = { - capacity: bigint - feePercent: number - metadataIpfsHash: string -} - -export type GnoVaultInitParamsStruct = { - capacity: bigint - feePercent: number - metadataIpfsHash: string -} - -export type EthErc20VaultInitParamsStruct = { - capacity: bigint - feePercent: number - name: string - symbol: string - metadataIpfsHash: string -} - -export type GnoErc20VaultInitParamsStruct = { - capacity: bigint - feePercent: number - name: string - symbol: string - metadataIpfsHash: string -} - -export type EthVaultType = - | EthVault - | EthPrivVault - | EthBlocklistVault - | EthErc20Vault - | EthPrivErc20Vault - | EthBlocklistErc20Vault - | EthGenesisVault - | EthFoxVault - -export type GnoVaultType = - | GnoVault - | GnoPrivVault - | GnoErc20Vault - | GnoPrivErc20Vault - | GnoGenesisVault diff --git a/test/shared/utils.ts b/test/shared/utils.ts deleted file mode 100644 index 91461ffd..00000000 --- a/test/shared/utils.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { ECDSASignature, fromRpcSig } from 'ethereumjs-util' -import { signTypedData, SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util' -import { ethers } from 'hardhat' -import { ContractTransactionReceipt, ContractTransactionResponse } from 'ethers' -import { EIP712Domain } from './constants' - -export const getSignatureFromTypedData = (privateKey: Buffer, data: any): ECDSASignature => { - const signature = signTypedData({ privateKey, data, version: SignTypedDataVersion.V4 }) - return fromRpcSig(signature) -} - -export const extractVaultAddress = async ( - response: ContractTransactionResponse -): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - const log = receipt.logs?.[receipt.logs.length - 1] - if (!('args' in log)) { - throw new Error('No logs found') - } - return log.args?.vault as string -} - -export const extractMevEscrowAddress = async ( - response: ContractTransactionResponse -): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - const log = receipt.logs?.[receipt.logs.length - 1] - if (!('args' in log)) { - throw new Error('No logs found') - } - return log.args?.ownMevEscrow as string -} - -export const getBlockTimestamp = async (response: ContractTransactionResponse): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - const block = await ethers.provider.getBlock(receipt.blockNumber) - return block?.timestamp as number -} - -export const getGasUsed = async (response: ContractTransactionResponse): Promise => { - const tx = (await response.wait()) as any - return BigInt(tx.cumulativeGasUsed * tx.gasPrice) -} - -export const extractExitPositionTicket = async ( - response: ContractTransactionResponse -): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - if (receipt.logs?.length == 0) { - throw new Error('No logs found') - } - for (const log of receipt.logs) { - if (!('args' in log)) { - continue - } - if (log.args?.positionTicket != undefined) { - return log.args.positionTicket as bigint - } - } - - throw new Error('No logs found') -} - -export const extractDepositShares = async ( - response: ContractTransactionResponse -): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - const log = receipt.logs?.[receipt.logs.length - 1] - if (!('args' in log)) { - throw new Error('No logs found') - } - return log.args?.shares as bigint -} - -export const extractCheckpointAssets = async ( - response: ContractTransactionResponse -): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - const log = receipt.logs?.[receipt.logs.length - 1] - if (log?.fragment?.name != 'CheckpointCreated') { - return 0n - } - return log.args?.assets as bigint -} - -export const extractEigenPodOwner = async ( - response: ContractTransactionResponse -): Promise => { - const receipt = (await response.wait()) as ContractTransactionReceipt - const log = receipt.logs?.[receipt.logs.length - 1] - if (!('args' in log)) { - throw new Error('No logs found') - } - return log.args?.eigenPodOwner as string -} - -export async function domainSeparator(name, version, chainId, verifyingContract) { - return ( - '0x' + - TypedDataUtils.hashStruct( - 'EIP712Domain', - { - name, - version, - chainId, - verifyingContract, - }, - { EIP712Domain }, - SignTypedDataVersion.V4 - ).toString('hex') - ) -} - -export async function getLatestBlockTimestamp(): Promise { - const block = await ethers.provider.getBlock('latest') - if (!block) { - throw new Error('No block found') - } - return block.timestamp -} - -export async function setBalance(address: string, value: bigint): Promise { - return ethers.provider.send('hardhat_setBalance', [address, '0x' + value.toString(16)]) -} - -export async function increaseTime(seconds: number): Promise { - await ethers.provider.send('evm_increaseTime', [seconds]) - return ethers.provider.send('evm_mine', []) -} - -export function toHexString(data: Buffer | Uint8Array): string { - return '0x' + data.toString('hex') -} diff --git a/test/shared/validators.ts b/test/shared/validators.ts deleted file mode 100644 index aca27b59..00000000 --- a/test/shared/validators.ts +++ /dev/null @@ -1,368 +0,0 @@ -import { ByteVectorType, ContainerType, Type, UintNumberType } from '@chainsafe/ssz' -import { StandardMerkleTree } from '@openzeppelin/merkle-tree' -import { ethers, network } from 'hardhat' -import { Buffer } from 'buffer' -import { BytesLike, Contract, ContractTransactionResponse, Signer } from 'ethers' -import bls from 'bls-eth-wasm' -import { DepositDataRegistry, EthVault, Keeper } from '../../typechain-types' -import { - EIP712Domain, - KeeperUpdateExitSignaturesSig, - KeeperValidatorsSig, - VaultValidatorsSig, - VALIDATORS_DEADLINE, - VALIDATORS_MIN_ORACLES, - ZERO_BYTES32, -} from './constants' -import { getOraclesSignatures } from './fixtures' -import { EthVaultType, GnoVaultType } from './types' - -export const secretKeys = [ - '0x2c66340f2d886f3fc4cfef10a802ddbaf4a37ffb49533b604f8a50804e8d198f', - '0x2c414222bc55f3a3627e20f2eb879b4019ffc44498ffbfb277725186954b714d', - '0x51017d92e2691f20907a62a2ec91764be253b317d2f7fba42a8ac7f0290880de', - '0x62ff87f6e66e9f2d8b382bd91fce8f31e46cceb32a84fb2d1ee1859b46399df7', - '0x161830b452d394152b53a2b04cea5ff3312e0165628081404542c127220deea7', - '0x64821642c5654f620bdbe72c641a3c3607aadaeb0af14311ff3588228135cc6e', - '0x3ee3c3001ff2a6eb2830dc44031dad1a1af8906fd8e1c4a6073cbb42deadeebd', - '0x4bbeb944e4abb46d929e6c2b7c6fea0adbdb72f942f8fa825bfb375e175e2762', - '0x047a48f9d1790ebe3f9cde4e93f1e135beef0406f68d6c8dae42b0adef2ad8d2', - '0x0d5b3814d2242c03bef667daf6823c866e9f458617667043a30fe5f5f3996f4b', -] - -export const exitSignatureIpfsHashes = [ - 'QmUFSdZoQUqkRkAgDEtFa2fMmWhQLC7tx8J3ckCL7XkZ1T', - 'QmUE7ixjUY9A3hK13HWDNztJ6SyPDutUEmFBSjj5XJfGa8', - 'QmWeQTjiM5UZrNtqiBe5VynNitHADSoCny8z1i4aMGTi6C', - 'QmbkxyF2xNibmwMds3dmvqAMn6RK7UbWwG4Y8Lz5meZUu5', - 'QmS7TDL3ATbiQySsVTasJ4Luw3WMHgYBaGw2eBJb9t9t2A', - 'QmRWw7QHKy72pKrJkukG5xxPqEr9XHktyhCmyf33wMUZzS', - 'QmbBRfY6xgBsHU2f3YitqB5ay1xJaAPEekcG1tW51tD3wD', - 'QmSPpB4TEEW8JjfuzhzFqsPnkMSVyfwMxqHhoGC5hTQL8s', - 'Qmccn5jxLqDMdY3c5nibVUtRtx3Vt7sGfMxCUD2jUSmBa1', - 'QmemVbNEhXugNCG3sjWHFS6wSH74wBvKBfiW86H1dBnwfV', -] - -const DOMAIN_DEPOSIT = Uint8Array.from([3, 0, 0, 0]) -const ETH1_ADDRESS_WITHDRAWAL_PREFIX = Uint8Array.from([1]) -const GENESIS_FORK_VERSION = ethers.getBytes('0x00000000') -const ZERO_HASH = Buffer.alloc(32, 0) - -// SSZ types -const Bytes4 = new ByteVectorType(4) -const Bytes32 = new ByteVectorType(32) -const Bytes48 = new ByteVectorType(48) -const Bytes96 = new ByteVectorType(96) -const UintNum64 = new UintNumberType(8) - -const SigningData = new ContainerType( - { - objectRoot: Bytes32, - domain: Bytes32, - }, - { typeName: 'SigningData', jsonCase: 'eth2' } -) -const ForkData = new ContainerType( - { - currentVersion: Bytes4, - genesisValidatorsRoot: Bytes32, - }, - { typeName: 'ForkData', jsonCase: 'eth2' } -) - -const DepositMessage = new ContainerType( - { - pubkey: Bytes48, - withdrawalCredentials: Bytes32, - amount: UintNum64, - }, - { typeName: 'DepositMessage', jsonCase: 'eth2' } -) -const DepositData = new ContainerType( - { - pubkey: Bytes48, - withdrawalCredentials: Bytes32, - amount: UintNum64, - signature: Bytes96, - }, - { typeName: 'DepositData', jsonCase: 'eth2' } -) - -export type ValidatorsMultiProof = { - proofFlags: boolean[] - proof: string[] - leaves: [Buffer, number][] -} - -export type ValidatorsTree = StandardMerkleTree<[Buffer, number]> - -export type EthValidatorsData = { - root: string - tree: ValidatorsTree - validators: Buffer[] -} - -// Only used by processDeposit + lightclient -/** - * Return the domain for the [[domainType]] and [[forkVersion]]. - */ -function computeDomain(domainType, forkVersion, genesisValidatorRoot): Uint8Array { - const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorRoot) - const domain = new Uint8Array(32) - domain.set(domainType, 0) - domain.set(forkDataRoot.slice(0, 28), 4) - return domain -} - -/** - * Used primarily in signature domains to avoid collisions across forks/chains. - */ -function computeForkDataRoot(currentVersion, genesisValidatorsRoot): Uint8Array { - const forkData = { - currentVersion, - genesisValidatorsRoot, - } - return ForkData.hashTreeRoot(forkData) -} - -/** - * Return the signing root of an object by calculating the root of the object-domain tree. - */ -function computeSigningRoot(type: Type, sszObject: T, domain): Uint8Array { - const domainWrappedObject = { - objectRoot: type.hashTreeRoot(sszObject), - domain, - } - return SigningData.hashTreeRoot(domainWrappedObject) -} - -export function getWithdrawalCredentials(vaultAddress: string): Buffer { - return Buffer.concat([ - ETH1_ADDRESS_WITHDRAWAL_PREFIX, - Buffer.alloc(11), - ethers.getBytes(vaultAddress), - ]) -} - -export async function createValidators( - depositAmount: bigint, - withdrawalCredentials: Buffer -): Promise { - await bls.init(bls.BLS12_381) - - const validators: Buffer[] = [] - for (let i = 0; i < secretKeys.length; i++) { - const secretKey = new bls.SecretKey() - secretKey.deserialize(ethers.getBytes(secretKeys[i])) - const publicKey = secretKey.getPublicKey().serialize() - - // create DepositData - const depositData = { - pubkey: publicKey, - withdrawalCredentials, - amount: Number(depositAmount / 1000000000n), // convert to gwei - signature: Buffer.alloc(0), - } - const domain = computeDomain(DOMAIN_DEPOSIT, GENESIS_FORK_VERSION, ZERO_HASH) - const signingRoot = computeSigningRoot(DepositMessage, depositData, domain) - const signature = secretKey.sign(signingRoot).serialize() - depositData.signature = Buffer.from(signature) - validators.push(Buffer.concat([publicKey, signature, DepositData.hashTreeRoot(depositData)])) - } - return validators -} - -export function appendDepositData( - validator: Buffer, - depositAmount: bigint, - vaultAddress: string -): Buffer { - const withdrawalCredentials = getWithdrawalCredentials(vaultAddress) - - // create DepositData - const depositData = { - pubkey: validator.subarray(0, 48), - withdrawalCredentials, - amount: Number(depositAmount / 1000000000n), // convert to gwei - signature: validator.subarray(48, 144), - } - return Buffer.concat([validator, DepositData.hashTreeRoot(depositData)]) -} - -export async function createEthValidatorsData( - vault: EthVaultType | GnoVaultType, - genesisVaultPoolEscrow: string | null = null -): Promise { - const validatorDeposit = ethers.parseEther('32') - - let withdrawalAddress: string - if (genesisVaultPoolEscrow !== null) { - withdrawalAddress = genesisVaultPoolEscrow - } else { - withdrawalAddress = await vault.getAddress() - } - - const withdrawalCredentials = getWithdrawalCredentials(withdrawalAddress) - const validators = await createValidators(validatorDeposit, withdrawalCredentials) - const tree = StandardMerkleTree.of( - validators.map((v, i) => [v, i]), - ['bytes', 'uint256'] - ) as ValidatorsTree - const treeRoot = tree.root - - return { - root: treeRoot, - tree, - validators, - } -} - -export async function getEthValidatorsSigningData( - validators: Buffer, - deadline: bigint, - exitSignaturesIpfsHash: string, - keeper: Keeper, - vault: EthVaultType | GnoVaultType, - validatorsRegistryRoot: BytesLike -) { - return { - primaryType: 'KeeperValidators', - types: { EIP712Domain, KeeperValidators: KeeperValidatorsSig }, - domain: { - name: 'KeeperOracles', - version: '1', - chainId: network.config.chainId, - verifyingContract: await keeper.getAddress(), - }, - message: { - validatorsRegistryRoot, - vault: await vault.getAddress(), - validators, - exitSignaturesIpfsHash, - deadline, - }, - } -} - -export async function getValidatorsManagerSigningData( - validators: Buffer, - vault: EthVaultType | GnoVaultType, - validatorsRegistryRoot: BytesLike -) { - return { - primaryType: 'VaultValidators', - types: { EIP712Domain, VaultValidators: VaultValidatorsSig }, - domain: { - name: 'VaultValidators', - version: '1', - chainId: network.config.chainId, - verifyingContract: await vault.getAddress(), - }, - message: { - validatorsRegistryRoot, - validators, - }, - } -} - -export async function getEthValidatorsExitSignaturesSigningData( - keeper: Keeper, - vault: EthVault, - deadline: number, - exitSignaturesIpfsHash: string, - nonce: number -) { - return { - primaryType: 'KeeperValidators', - types: { EIP712Domain, KeeperValidators: KeeperUpdateExitSignaturesSig }, - domain: { - name: 'KeeperOracles', - version: '1', - chainId: network.config.chainId, - verifyingContract: await keeper.getAddress(), - }, - message: { - vault: await vault.getAddress(), - deadline, - nonce, - exitSignaturesIpfsHash, - }, - } -} - -export function getValidatorProof( - tree: ValidatorsTree, - validator: Buffer, - index: number -): string[] { - return tree.getProof([validator, index]) -} - -export function getValidatorsMultiProof( - tree: ValidatorsTree, - validators: Buffer[], - indexes: number[] -): ValidatorsMultiProof { - const multiProof = tree.getMultiProof(validators.map((v, i) => [v, indexes[i]])) - return { - ...multiProof, - leaves: multiProof.leaves, - } -} - -export async function registerEthValidator( - vault: EthVaultType | GnoVaultType, - keeper: Keeper, - depositDataRegistry: DepositDataRegistry, - admin: Signer, - validatorsRegistry: Contract -): Promise { - const validatorsData = await createEthValidatorsData(vault) - const validatorsRegistryRoot = await validatorsRegistry.get_deposit_root() - const vaultAddress = await vault.getAddress() - if ((await vault.version()) > 1) { - if ((await depositDataRegistry.depositDataRoots(vaultAddress)) != ZERO_BYTES32) { - // reset validator index - await depositDataRegistry.connect(admin).setDepositDataRoot(vaultAddress, ZERO_BYTES32) - } - await depositDataRegistry.connect(admin).setDepositDataRoot(vaultAddress, validatorsData.root) - } else { - await vault.connect(admin).setValidatorsRoot(validatorsData.root) - } - const validator = validatorsData.validators[0] - const exitSignatureIpfsHash = exitSignatureIpfsHashes[0] - const signingData = await getEthValidatorsSigningData( - validator, - VALIDATORS_DEADLINE, - exitSignatureIpfsHash, - keeper, - vault, - validatorsRegistryRoot - ) - const signatures = getOraclesSignatures(signingData, VALIDATORS_MIN_ORACLES) - const proof = getValidatorProof(validatorsData.tree, validator, 0) - if ((await vault.version()) > 1) { - return await depositDataRegistry.connect(admin).registerValidator( - vaultAddress, - { - validatorsRegistryRoot, - validators: validator, - signatures, - exitSignaturesIpfsHash: exitSignatureIpfsHash, - deadline: VALIDATORS_DEADLINE, - }, - proof - ) - } else { - return await vault.registerValidator( - { - validatorsRegistryRoot, - validators: validator, - signatures, - exitSignaturesIpfsHash: exitSignatureIpfsHash, - deadline: VALIDATORS_DEADLINE, - }, - proof - ) - } -} From f889d0159061ebc6972257ce1115349ac0b368b2 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Fri, 11 Apr 2025 19:24:12 +0300 Subject: [PATCH 07/15] Extract VaultValidators, VaultOsToken to libraries (#107) --- contracts/base/ERC20Upgradeable.sol | 14 +- contracts/interfaces/IVaultEthStaking.sol | 3 +- contracts/interfaces/IVaultState.sol | 23 +- contracts/libraries/EIP712Utils.sol | 35 ++ contracts/libraries/ExitQueue.sol | 4 +- contracts/libraries/OsTokenUtils.sol | 86 +++++ contracts/libraries/ValidatorUtils.sol | 323 ++++++++++++++++ contracts/validators/ValidatorsChecker.sol | 61 +-- contracts/vaults/ethereum/EthGenesisVault.sol | 15 +- contracts/vaults/gnosis/GnoErc20Vault.sol | 11 - contracts/vaults/gnosis/GnoVault.sol | 11 - contracts/vaults/modules/VaultEnterExit.sol | 6 +- contracts/vaults/modules/VaultEthStaking.sol | 59 ++- contracts/vaults/modules/VaultGnoStaking.sol | 79 ++-- contracts/vaults/modules/VaultOsToken.sol | 52 +-- contracts/vaults/modules/VaultState.sol | 68 ++-- contracts/vaults/modules/VaultValidators.sol | 352 +++--------------- test/DepositDataRegistry.t.sol | 9 +- test/EthBlocklistErc20Vault.t.sol | 26 +- test/EthBlocklistVault.t.sol | 27 +- test/EthErc20Vault.t.sol | 30 +- test/EthFoxVault.t.sol | 13 +- test/EthGenesisVault.t.sol | 31 +- test/EthOsTokenVaultEscrow.t.sol | 5 +- test/EthPrivErc20Vault.t.sol | 26 +- test/EthPrivVault.t.sol | 27 +- test/EthValidatorsChecker.t.sol | 2 +- test/EthVault.t.sol | 90 ++++- test/VaultAdmin.t.sol | 20 +- test/VaultEnterExit.t.sol | 21 +- test/VaultEthStaking.t.sol | 5 +- test/VaultState.t.sol | 21 +- test/VaultToken.t.sol | 3 +- test/VaultValidators.t.sol | 17 +- test/gnosis/GnoBlocklistErc20Vault.t.sol | 26 +- test/gnosis/GnoBlocklistVault.t.sol | 27 +- test/gnosis/GnoErc20Vault.t.sol | 27 +- test/gnosis/GnoGenesisVault.t.sol | 14 +- test/gnosis/GnoOsTokenVaultEscrow.t.sol | 6 +- test/gnosis/GnoOwnMevEscrow.t.sol | 2 +- test/gnosis/GnoPrivErc20Vault.t.sol | 26 +- test/gnosis/GnoPrivVault.t.sol | 26 +- test/gnosis/GnoRewardSplitter.t.sol | 30 +- test/gnosis/GnoSharedMevEscrow.t.sol | 2 +- test/gnosis/GnoVault.t.sol | 81 +++- test/gnosis/GnoVaultExitQueue.t.sol | 19 +- test/gnosis/VaultGnoStaking.t.sol | 16 +- 47 files changed, 1147 insertions(+), 730 deletions(-) create mode 100644 contracts/libraries/EIP712Utils.sol create mode 100644 contracts/libraries/OsTokenUtils.sol create mode 100644 contracts/libraries/ValidatorUtils.sol diff --git a/contracts/base/ERC20Upgradeable.sol b/contracts/base/ERC20Upgradeable.sol index b49bfe7d..4658dc18 100644 --- a/contracts/base/ERC20Upgradeable.sol +++ b/contracts/base/ERC20Upgradeable.sol @@ -7,6 +7,7 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {IERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol'; import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import {Errors} from '../libraries/Errors.sol'; +import {EIP712Utils} from '../libraries/EIP712Utils.sol'; /** * @title ERC20 Upgradeable @@ -128,18 +129,7 @@ abstract contract ERC20Upgradeable is Initializable, IERC20Permit, IERC20, IERC2 * @dev This function is used to compute the hash of the EIP712 typed data */ function _computeDomainSeparator() private view returns (bytes32) { - return - keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes(name)), - keccak256('1'), - block.chainid, - address(this) - ) - ); + return EIP712Utils.computeDomainSeparator(name, address(this)); } /** diff --git a/contracts/interfaces/IVaultEthStaking.sol b/contracts/interfaces/IVaultEthStaking.sol index 07361e45..7202b5ca 100644 --- a/contracts/interfaces/IVaultEthStaking.sol +++ b/contracts/interfaces/IVaultEthStaking.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.22; -import {IVaultState} from './IVaultState.sol'; import {IVaultValidators} from './IVaultValidators.sol'; import {IVaultEnterExit} from './IVaultEnterExit.sol'; import {IKeeperRewards} from './IKeeperRewards.sol'; @@ -13,7 +12,7 @@ import {IVaultMev} from './IVaultMev.sol'; * @author StakeWise * @notice Defines the interface for the VaultEthStaking contract */ -interface IVaultEthStaking is IVaultState, IVaultValidators, IVaultEnterExit, IVaultMev { +interface IVaultEthStaking is IVaultValidators, IVaultEnterExit, IVaultMev { /** * @notice Deposit ETH to the Vault * @param receiver The address that will receive Vault's shares diff --git a/contracts/interfaces/IVaultState.sol b/contracts/interfaces/IVaultState.sol index 3023618b..87495e63 100644 --- a/contracts/interfaces/IVaultState.sol +++ b/contracts/interfaces/IVaultState.sol @@ -57,16 +57,21 @@ interface IVaultState is IVaultFee { function withdrawableAssets() external view returns (uint256); /** - * @notice Queued Shares - * @return The total number of shares queued for exit + * @notice Get exit queue data + * @return queuedShares The number of shares in the exit queue + * @return unclaimedAssets The amount of unclaimed assets in the exit queue + * @return totalExitingAssets The total amount of exiting assets + * @return totalTickets The total number of tickets in the exit queue */ - function queuedShares() external view returns (uint128); - - /** - * @notice Total Exiting Assets (deprecated) - * @return The total number of assets queued for exit - */ - function totalExitingAssets() external view returns (uint128); + function getExitQueueData() + external + view + returns ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ); /** * @notice Returns the number of shares held by an account diff --git a/contracts/libraries/EIP712Utils.sol b/contracts/libraries/EIP712Utils.sol new file mode 100644 index 00000000..2454a8c1 --- /dev/null +++ b/contracts/libraries/EIP712Utils.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title EIP712Utils + * @author StakeWise + * @notice Includes functionality for calculating EIP712 hashes + */ +library EIP712Utils { + /** + * @notice Computes the hash of the EIP712 typed data + * @dev This function is used to compute the hash of the EIP712 typed data + * @param name The name of the domain + * @param verifyingContract The address of the verifying contract + * @return The hash of the EIP712 typed data + */ + function computeDomainSeparator( + string memory name, + address verifyingContract + ) external view returns (bytes32) { + return + keccak256( + abi.encode( + keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + ), + keccak256(bytes(name)), + keccak256('1'), + block.chainid, + verifyingContract + ) + ); + } +} diff --git a/contracts/libraries/ExitQueue.sol b/contracts/libraries/ExitQueue.sol index 6e3ec21d..0a55f0b6 100644 --- a/contracts/libraries/ExitQueue.sol +++ b/contracts/libraries/ExitQueue.sol @@ -52,7 +52,7 @@ library ExitQueue { function getCheckpointIndex( History storage self, uint256 positionTicket - ) internal view returns (uint256) { + ) external view returns (uint256) { uint256 high = self.checkpoints.length; uint256 low; while (low < high) { @@ -83,7 +83,7 @@ library ExitQueue { uint256 checkpointIdx, uint256 positionTicket, uint256 positionShares - ) internal view returns (uint256 burnedShares, uint256 exitedAssets) { + ) external view returns (uint256 burnedShares, uint256 exitedAssets) { uint256 length = self.checkpoints.length; // there are no exited assets for such checkpoint index or no shares to burn if (checkpointIdx >= length || positionShares == 0) return (0, 0); diff --git a/contracts/libraries/OsTokenUtils.sol b/contracts/libraries/OsTokenUtils.sol new file mode 100644 index 00000000..dde7ec18 --- /dev/null +++ b/contracts/libraries/OsTokenUtils.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; +import {IOsTokenConfig} from '../interfaces/IOsTokenConfig.sol'; +import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; +import {Errors} from './Errors.sol'; + +/** + * @title OsTokenUtils + * @author StakeWise + * @notice Includes functionality for handling osToken redemptions + */ +library OsTokenUtils { + uint256 private constant _wad = 1e18; + uint256 private constant _hfLiqThreshold = 1e18; + uint256 private constant _maxPercent = 1e18; + uint256 private constant _disabledLiqThreshold = type(uint64).max; + + /** + * @dev Struct for storing redemption data + * @param mintedAssets The amount of minted assets + * @param depositedAssets The amount of deposited assets + * @param redeemedOsTokenShares The amount of redeemed osToken shares + * @param availableAssets The amount of available assets + * @param isLiquidation Whether the redemption is a liquidation + */ + struct RedemptionData { + uint256 mintedAssets; + uint256 depositedAssets; + uint256 redeemedOsTokenShares; + uint256 availableAssets; + bool isLiquidation; + } + + /** + * @dev Calculates the amount of received assets during osToken redemption + * @param osTokenConfig The address of the osToken config contract + * @param osTokenVaultController The address of the osToken vault controller contract + * @param data The redemption data + * @return receivedAssets The amount of received assets + */ + function calculateReceivedAssets( + IOsTokenConfig osTokenConfig, + IOsTokenVaultController osTokenVaultController, + RedemptionData memory data + ) external view returns (uint256 receivedAssets) { + // SLOAD to memory + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(this)); + if (data.isLiquidation && config.liqThresholdPercent == _disabledLiqThreshold) { + revert Errors.LiquidationDisabled(); + } + + // calculate received assets + if (data.isLiquidation) { + receivedAssets = Math.mulDiv( + osTokenVaultController.convertToAssets(data.redeemedOsTokenShares), + config.liqBonusPercent, + _maxPercent + ); + } else { + receivedAssets = osTokenVaultController.convertToAssets(data.redeemedOsTokenShares); + } + + { + // check whether received assets are valid + if (receivedAssets > data.depositedAssets || receivedAssets > data.availableAssets) { + revert Errors.InvalidReceivedAssets(); + } + + if (data.isLiquidation) { + // check health factor violation in case of liquidation + if ( + Math.mulDiv( + data.depositedAssets * _wad, + config.liqThresholdPercent, + data.mintedAssets * _maxPercent + ) >= _hfLiqThreshold + ) { + revert Errors.InvalidHealthFactor(); + } + } + } + } +} diff --git a/contracts/libraries/ValidatorUtils.sol b/contracts/libraries/ValidatorUtils.sol new file mode 100644 index 00000000..1c56dee9 --- /dev/null +++ b/contracts/libraries/ValidatorUtils.sol @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; +import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; +import {Errors} from './Errors.sol'; +import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; + +/** + * @title ValidatorUtils + * @author StakeWise + * @notice Includes functionality for managing the validators + */ +library ValidatorUtils { + bytes32 private constant _validatorsManagerTypeHash = + keccak256('VaultValidators(bytes32 nonce,bytes validators)'); + uint256 private constant _validatorV1DepositLength = 176; + uint256 private constant _validatorV2DepositLength = 184; + uint256 private constant _validatorWithdrawalLength = 56; + uint256 private constant _validatorConsolidationLength = 96; + uint256 private constant _validatorMinEffectiveBalance = 32 ether; + uint256 private constant _validatorMaxEffectiveBalance = 2048 ether; + + /* + * @dev Struct to hold the validator registration data + * @param publicKey The public key of the validator + * @param signature The signature of the validator + * @param withdrawalCredentials The withdrawal credentials of the validator + * @param depositDataRoot The deposit data root of the validator + * @param depositAmount The deposit amount of the validator + */ + struct ValidatorDeposit { + bytes publicKey; + bytes signature; + bytes withdrawalCredentials; + bytes32 depositDataRoot; + uint256 depositAmount; + } + + /** + * @dev Function to check if the validator signature is valid + * @param nonce The nonce of the validator + * @param domainSeparator The domain separator of the validator + * @param validatorsManager The address of the validators manager + * @param validators The validators data + * @param signature The signature of the validator + * @return Whether the signature is valid + */ + function isValidManagerSignature( + bytes32 nonce, + bytes32 domainSeparator, + address validatorsManager, + bytes calldata validators, + bytes calldata signature + ) external view returns (bool) { + bytes32 messageHash = MessageHashUtils.toTypedDataHash( + domainSeparator, + keccak256(abi.encode(_validatorsManagerTypeHash, nonce, keccak256(validators))) + ); + return SignatureChecker.isValidSignatureNow(validatorsManager, messageHash, signature); + } + + /** + * @dev Function to get the validator registration data + * @param validator The validator data + * @param isV1Validator Whether the validator is a V1 validator + * @return validatorDeposit The validator registration data + */ + function getValidatorDeposit( + bytes calldata validator, + bool isV1Validator + ) internal view returns (ValidatorDeposit memory validatorDeposit) { + validatorDeposit.publicKey = validator[:48]; + validatorDeposit.signature = validator[48:144]; + validatorDeposit.depositDataRoot = bytes32(validator[144:176]); + + // get the deposit amount and withdrawal credentials prefix + bytes1 withdrawalCredsPrefix; + if (isV1Validator) { + withdrawalCredsPrefix = 0x01; + validatorDeposit.depositAmount = _validatorMinEffectiveBalance; + } else { + withdrawalCredsPrefix = 0x02; + // extract amount from data, convert gwei to wei by multiplying by 1 gwei + validatorDeposit.depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei); + } + validatorDeposit.withdrawalCredentials = abi.encodePacked( + withdrawalCredsPrefix, + bytes11(0x0), + address(this) + ); + } + + /** + * @dev Function to get the type of validators + * @param validatorsLength The length of the validators data + * @return isV1Validators Whether the validators are V1 validators + */ + function getIsV1Validators(uint256 validatorsLength) internal pure returns (bool) { + bool isV1Validators = validatorsLength % _validatorV1DepositLength == 0; + bool isV2Validators = validatorsLength % _validatorV2DepositLength == 0; + if ( + validatorsLength == 0 || + (isV1Validators && isV2Validators) || + (!isV1Validators && !isV2Validators) + ) { + revert Errors.InvalidValidators(); + } + + return isV1Validators; + } + + /** + * @dev Function to get the validator registrations + * @param v2Validators The mapping of public key hashes to registration status + * @param validators The validators data + * @param isTopUp Whether the registration is a top-up + * @return validatorDeposits The array of validator registrations + */ + function getValidatorDeposits( + mapping(bytes32 publicKeyHash => bool isRegistered) storage v2Validators, + bytes calldata validators, + bool isTopUp + ) external returns (ValidatorDeposit[] memory validatorDeposits) { + // check validators length is valid + uint256 validatorsLength = validators.length; + bool isV1Validators = getIsV1Validators(validatorsLength); + + // top up is only allowed for V2 validators + if (isTopUp && isV1Validators) { + revert Errors.CannotTopUpV1Validators(); + } + + uint256 _validatorDepositLength = ( + isV1Validators ? _validatorV1DepositLength : _validatorV2DepositLength + ); + uint256 validatorsCount = validatorsLength / _validatorDepositLength; + + uint256 startIndex; + ValidatorDeposit memory valDeposit; + validatorDeposits = new ValidatorDeposit[](validatorsCount); + for (uint256 i = 0; i < validatorsCount; ) { + valDeposit = getValidatorDeposit( + validators[startIndex:startIndex + _validatorDepositLength], + isV1Validators + ); + + if (isTopUp) { + // check whether validator is tracked in case of the top-up + if (!v2Validators[keccak256(valDeposit.publicKey)]) { + revert Errors.InvalidValidators(); + } + // add registration data to the array + validatorDeposits[i] = valDeposit; + emit IVaultValidators.ValidatorFunded(valDeposit.publicKey, valDeposit.depositAmount); + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorDepositLength; + } + continue; + } + + // check the registration amount + if ( + valDeposit.depositAmount > _validatorMaxEffectiveBalance || + valDeposit.depositAmount < _validatorMinEffectiveBalance + ) { + revert Errors.InvalidAssets(); + } + + // mark v2 validator public key as tracked + if (!isV1Validators) { + v2Validators[keccak256(valDeposit.publicKey)] = true; + emit IVaultValidators.V2ValidatorRegistered(valDeposit.publicKey, valDeposit.depositAmount); + } else { + emit IVaultValidators.ValidatorRegistered(valDeposit.publicKey); + } + + // add registration data to the array + validatorDeposits[i] = valDeposit; + + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorDepositLength; + } + } + } + + /** + * @dev Function to withdraw the validators + * @param validators The validators data + * @param validatorsWithdrawals The address of the validators withdrawals contract + */ + function withdrawValidators(bytes calldata validators, address validatorsWithdrawals) external { + // check validators length is valid + uint256 validatorsCount = validators.length / _validatorWithdrawalLength; + unchecked { + if (validatorsCount == 0 || validators.length % _validatorWithdrawalLength != 0) { + revert Errors.InvalidValidators(); + } + } + + uint256 feePaid; + uint256 withdrawnAmount; + uint256 totalFeeAssets = msg.value; + bytes calldata publicKey; + bytes calldata validator; + uint256 startIndex; + for (uint256 i = 0; i < validatorsCount; ) { + validator = validators[startIndex:startIndex + _validatorWithdrawalLength]; + publicKey = validator[:48]; + + // convert gwei to wei by multiplying by 1 gwei + withdrawnAmount = (uint256(uint64(bytes8(validator[48:56]))) * 1 gwei); + feePaid = uint256(bytes32(Address.functionStaticCall(validatorsWithdrawals, ''))); + + // submit validator withdrawal + Address.functionCallWithValue(validatorsWithdrawals, validator, feePaid); + totalFeeAssets -= feePaid; + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, withdrawnAmount, feePaid); + + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorWithdrawalLength; + } + } + + // send the remaining assets to the caller + if (totalFeeAssets > 0) { + Address.sendValue(payable(msg.sender), totalFeeAssets); + } + } + + /** + * @dev Internal function for consolidating validators + * @param validator The validator data + * @param validatorsConsolidations The address of the validators consolidations contract + * @param fromPublicKey The public key of the validator that was consolidated + * @param toPublicKey The public key of the validator that was consolidated to + * @param feePaid The amount of fee that was paid + */ + function consolidateValidator( + bytes calldata validator, + address validatorsConsolidations + ) internal returns (bytes calldata fromPublicKey, bytes calldata toPublicKey, uint256 feePaid) { + fromPublicKey = validator[:48]; + toPublicKey = validator[48:96]; + feePaid = uint256(bytes32(Address.functionStaticCall(validatorsConsolidations, ''))); + + Address.functionCallWithValue(validatorsConsolidations, validator, feePaid); + } + + /** + * @dev Function to consolidate the validators + * @param v2Validators The mapping of public key hashes to registration status + * @param validators The validators data + * @param consolidationsApproved Whether the consolidations are approved + * @param validatorsConsolidations The address of the validators consolidations contract + */ + function consolidateValidators( + mapping(bytes32 publicKeyHash => bool isRegistered) storage v2Validators, + bytes calldata validators, + bool consolidationsApproved, + address validatorsConsolidations + ) external { + // Check validators length is valid + uint256 validatorsCount = validators.length / _validatorConsolidationLength; + unchecked { + if (validatorsCount == 0 || validators.length % _validatorConsolidationLength != 0) { + revert Errors.InvalidValidators(); + } + } + + uint256 totalFeeAssets = msg.value; + + // Process each validator + bytes32 destPubKeyHash; + bytes calldata sourcePublicKey; + bytes calldata destPublicKey; + uint256 feePaid; + uint256 startIndex; + for (uint256 i = 0; i < validatorsCount; ) { + // consolidate validators + (sourcePublicKey, destPublicKey, feePaid) = consolidateValidator( + validators[startIndex:startIndex + _validatorConsolidationLength], + validatorsConsolidations + ); + + // check whether the destination public key is tracked or approved + destPubKeyHash = keccak256(destPublicKey); + if (consolidationsApproved) { + v2Validators[destPubKeyHash] = true; + } else if (!v2Validators[destPubKeyHash]) { + revert Errors.InvalidValidators(); + } + + // Update fees and emit event + unchecked { + // cannot realistically overflow + totalFeeAssets -= feePaid; + startIndex += _validatorConsolidationLength; + ++i; + } + + // emit event + emit IVaultValidators.ValidatorConsolidationSubmitted( + sourcePublicKey, + destPublicKey, + feePaid + ); + } + + // refund unused fees + if (totalFeeAssets > 0) { + Address.sendValue(payable(msg.sender), totalFeeAssets); + } + } +} diff --git a/contracts/validators/ValidatorsChecker.sol b/contracts/validators/ValidatorsChecker.sol index 84de72aa..a078f9b7 100644 --- a/contracts/validators/ValidatorsChecker.sol +++ b/contracts/validators/ValidatorsChecker.sol @@ -3,8 +3,6 @@ pragma solidity ^0.8.22; import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; -import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; import {IKeeper} from '../interfaces/IKeeper.sol'; import {IValidatorsChecker} from '../interfaces/IValidatorsChecker.sol'; @@ -13,7 +11,8 @@ import {IVaultVersion} from '../interfaces/IVaultVersion.sol'; import {IDepositDataRegistry} from '../interfaces/IDepositDataRegistry.sol'; import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {EIP712Utils} from '../libraries/EIP712Utils.sol'; +import {ValidatorUtils} from '../libraries/ValidatorUtils.sol'; interface IVaultValidatorsV1 { function validatorsRoot() external view returns (bytes32); @@ -28,9 +27,6 @@ interface IVaultValidatorsV1 { * * checking deposit data root */ abstract contract ValidatorsChecker is IValidatorsChecker { - bytes32 private constant _registerValidatorsTypeHash = - keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'); - IValidatorsRegistry private immutable _validatorsRegistry; IKeeper private immutable _keeper; IVaultsRegistry private immutable _vaultsRegistry; @@ -76,17 +72,17 @@ abstract contract ValidatorsChecker is IValidatorsChecker { return (block.number, Status.INSUFFICIENT_ASSETS); } - // compose signing message - bytes32 message = _getValidatorsManagerMessageHash(vault, validatorsRegistryRoot, validators); + // validate signature + bool isValidSignature = ValidatorUtils.isValidManagerSignature( + validatorsRegistryRoot, + _computeVaultValidatorsDomain(vault), + IVaultValidators(vault).validatorsManager(), + validators, + signature + ); // verify validators manager ECDSA signature - if ( - !SignatureChecker.isValidSignatureNow( - IVaultValidators(vault).validatorsManager(), - message, - signature - ) - ) { + if (!isValidSignature) { return (block.number, Status.INVALID_SIGNATURE); } @@ -178,46 +174,13 @@ abstract contract ValidatorsChecker is IValidatorsChecker { return (block.number, Status.SUCCEEDED); } - /** - * @notice Get the hash to be signed by the validators manager - * @param vault The address of the vault - * @param validatorsRegistryRoot The validators registry root - * @param validators The concatenation of the validators' public key, deposit signature, deposit root - * @return The hash to be signed by the validators manager - */ - function _getValidatorsManagerMessageHash( - address vault, - bytes32 validatorsRegistryRoot, - bytes calldata validators - ) private view returns (bytes32) { - bytes32 domainSeparator = _computeVaultValidatorsDomain(vault); - return - MessageHashUtils.toTypedDataHash( - domainSeparator, - keccak256( - abi.encode(_registerValidatorsTypeHash, validatorsRegistryRoot, keccak256(validators)) - ) - ); - } - /** * @notice Computes the hash of the EIP712 typed data for the vault * @dev This function is used to compute the hash of the EIP712 typed data * @return The hash of the EIP712 typed data */ function _computeVaultValidatorsDomain(address vault) private view returns (bytes32) { - return - keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes('VaultValidators')), - keccak256('1'), - block.chainid, - vault - ) - ); + return EIP712Utils.computeDomainSeparator('VaultValidators', vault); } /** diff --git a/contracts/vaults/ethereum/EthGenesisVault.sol b/contracts/vaults/ethereum/EthGenesisVault.sol index ef245f12..7c938744 100644 --- a/contracts/vaults/ethereum/EthGenesisVault.sol +++ b/contracts/vaults/ethereum/EthGenesisVault.sol @@ -10,6 +10,7 @@ import {IEthPoolEscrow} from '../../interfaces/IEthPoolEscrow.sol'; import {IEthGenesisVault} from '../../interfaces/IEthGenesisVault.sol'; import {IRewardEthToken} from '../../interfaces/IRewardEthToken.sol'; import {Errors} from '../../libraries/Errors.sol'; +import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; import {VaultValidators} from '../modules/VaultValidators.sol'; import {VaultEnterExit} from '../modules/VaultEnterExit.sol'; import {VaultEthStaking} from '../modules/VaultEthStaking.sol'; @@ -153,17 +154,11 @@ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { } /// @inheritdoc VaultValidators - function _registerValidator( - bytes calldata validator, - bool isV1Validator - ) - internal - virtual - override(VaultValidators, VaultEthStaking) - returns (uint256 depositAmount, bytes calldata publicKey) - { + function _registerValidators( + ValidatorUtils.ValidatorDeposit[] memory deposits + ) internal virtual override(VaultValidators, VaultEthStaking) { _pullWithdrawals(); - return super._registerValidator(validator, isV1Validator); + return super._registerValidators(deposits); } /** diff --git a/contracts/vaults/gnosis/GnoErc20Vault.sol b/contracts/vaults/gnosis/GnoErc20Vault.sol index 0d0e4bfe..b0df4e13 100644 --- a/contracts/vaults/gnosis/GnoErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoErc20Vault.sol @@ -180,17 +180,6 @@ contract GnoErc20Vault is } } - /// @inheritdoc VaultValidators - function _withdrawValidator( - bytes calldata validator - ) - internal - override(VaultValidators, VaultGnoStaking) - returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) - { - return super._withdrawValidator(validator); - } - /** * @dev Upgrades the GnoErc20Vault contract */ diff --git a/contracts/vaults/gnosis/GnoVault.sol b/contracts/vaults/gnosis/GnoVault.sol index f91f563e..5fb0bff2 100644 --- a/contracts/vaults/gnosis/GnoVault.sol +++ b/contracts/vaults/gnosis/GnoVault.sol @@ -128,17 +128,6 @@ contract GnoVault is } } - /// @inheritdoc VaultValidators - function _withdrawValidator( - bytes calldata validator - ) - internal - override(VaultValidators, VaultGnoStaking) - returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) - { - return super._withdrawValidator(validator); - } - /** * @dev Upgrades the GnoVault contract */ diff --git a/contracts/vaults/modules/VaultEnterExit.sol b/contracts/vaults/modules/VaultEnterExit.sol index 04d692c4..20fc091b 100644 --- a/contracts/vaults/modules/VaultEnterExit.sol +++ b/contracts/vaults/modules/VaultEnterExit.sol @@ -181,10 +181,10 @@ abstract contract VaultEnterExit is VaultImmutables, Initializable, VaultState, } // SLOAD to memory - uint256 _queuedShares = queuedShares; + uint256 queuedShares = _queuedShares; // calculate position ticket - positionTicket = _exitQueue.getLatestTotalTickets() + _totalExitingTickets + _queuedShares; + positionTicket = _exitQueue.getLatestTotalTickets() + _totalExitingTickets + queuedShares; // add to the exit requests _exitRequests[keccak256(abi.encode(receiver, block.timestamp, positionTicket))] = shares; @@ -194,7 +194,7 @@ abstract contract VaultEnterExit is VaultImmutables, Initializable, VaultState, unchecked { // cannot overflow as it is capped with _totalShares - queuedShares = SafeCast.toUint128(_queuedShares + shares); + _queuedShares = SafeCast.toUint128(queuedShares + shares); } emit ExitQueueEntered(user, receiver, positionTicket, shares); diff --git a/contracts/vaults/modules/VaultEthStaking.sol b/contracts/vaults/modules/VaultEthStaking.sol index 30533ef5..47483136 100644 --- a/contracts/vaults/modules/VaultEthStaking.sol +++ b/contracts/vaults/modules/VaultEthStaking.sol @@ -8,6 +8,7 @@ import {IEthValidatorsRegistry} from '../../interfaces/IEthValidatorsRegistry.so import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; import {IVaultEthStaking} from '../../interfaces/IVaultEthStaking.sol'; import {Errors} from '../../libraries/Errors.sol'; +import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; import {VaultValidators} from './VaultValidators.sol'; import {VaultState} from './VaultState.sol'; import {VaultEnterExit} from './VaultEnterExit.sol'; @@ -59,32 +60,30 @@ abstract contract VaultEthStaking is } /// @inheritdoc VaultValidators - function _registerValidator( - bytes calldata validator, - bool isV1Validator - ) internal virtual override returns (uint256 depositAmount, bytes calldata publicKey) { - publicKey = validator[:48]; - bytes calldata signature = validator[48:144]; - bytes32 depositDataRoot = bytes32(validator[144:176]); - - // get the deposit amount and withdrawal credentials prefix - bytes1 withdrawalCredsPrefix; - if (isV1Validator) { - withdrawalCredsPrefix = 0x01; - depositAmount = _validatorMinEffectiveBalance(); - } else { - withdrawalCredsPrefix = 0x02; - // extract amount from data, convert gwei to wei by multiplying by 1 gwei - depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei); + function _registerValidators( + ValidatorUtils.ValidatorDeposit[] memory deposits + ) internal virtual override { + uint256 totalDeposits = deposits.length; + uint256 availableAssets = withdrawableAssets(); + ValidatorUtils.ValidatorDeposit memory depositData; + for (uint256 i = 0; i < totalDeposits; ) { + depositData = deposits[i]; + // deposit to the validators registry + IEthValidatorsRegistry(_validatorsRegistry).deposit{value: depositData.depositAmount}( + depositData.publicKey, + depositData.withdrawalCredentials, + depositData.signature, + depositData.depositDataRoot + ); + + // will revert if not enough assets + availableAssets -= depositData.depositAmount; + + unchecked { + // cannot realistically overflow + ++i; + } } - - // deposit to the validators registry - IEthValidatorsRegistry(_validatorsRegistry).deposit{value: depositAmount}( - publicKey, - abi.encodePacked(withdrawalCredsPrefix, bytes11(0x0), address(this)), - signature, - depositDataRoot - ); } /// @inheritdoc VaultState @@ -100,16 +99,6 @@ abstract contract VaultEthStaking is return Address.sendValue(payable(receiver), assets); } - /// @inheritdoc VaultValidators - function _validatorMinEffectiveBalance() internal pure virtual override returns (uint256) { - return 32 ether; - } - - /// @inheritdoc VaultValidators - function _validatorMaxEffectiveBalance() internal pure virtual override returns (uint256) { - return 2048 ether; - } - /** * @dev Initializes the VaultEthStaking contract */ diff --git a/contracts/vaults/modules/VaultGnoStaking.sol b/contracts/vaults/modules/VaultGnoStaking.sol index 8f483237..84aacd6e 100644 --- a/contracts/vaults/modules/VaultGnoStaking.sol +++ b/contracts/vaults/modules/VaultGnoStaking.sol @@ -8,7 +8,7 @@ import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Ini import {IGnoValidatorsRegistry} from '../../interfaces/IGnoValidatorsRegistry.sol'; import {IVaultGnoStaking} from '../../interfaces/IVaultGnoStaking.sol'; import {IGnoDaiDistributor} from '../../interfaces/IGnoDaiDistributor.sol'; -import {Errors} from '../../libraries/Errors.sol'; +import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; import {VaultAdmin} from './VaultAdmin.sol'; import {VaultState} from './VaultState.sol'; import {VaultValidators} from './VaultValidators.sol'; @@ -72,51 +72,38 @@ abstract contract VaultGnoStaking is receive() external payable {} /// @inheritdoc VaultValidators - function _registerValidator( - bytes calldata validator, - bool isV1Validator - ) internal virtual override returns (uint256 depositAmount, bytes calldata publicKey) { + function _registerValidators( + ValidatorUtils.ValidatorDeposit[] memory deposits + ) internal virtual override { // pull withdrawals from the deposit contract _pullWithdrawals(); - publicKey = validator[:48]; - bytes calldata signature = validator[48:144]; - bytes32 depositDataRoot = bytes32(validator[144:176]); - - // get the deposit amount and withdrawal credentials prefix - bytes1 withdrawalCredsPrefix; - if (isV1Validator) { - withdrawalCredsPrefix = 0x01; - depositAmount = _validatorMinEffectiveBalance(); - } else { - withdrawalCredsPrefix = 0x02; - // extract amount from data, convert gwei to wei by multiplying by 1 gwei + uint256 totalDeposits = deposits.length; + uint256 availableAssets = withdrawableAssets(); + ValidatorUtils.ValidatorDeposit memory depositData; + for (uint256 i = 0; i < totalDeposits; ) { + depositData = deposits[i]; + // divide by 32 to convert mGNO to GNO - depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei) / 32; + depositData.depositAmount /= 32; + + // deposit GNO tokens to the validators registry + IGnoValidatorsRegistry(_validatorsRegistry).deposit( + depositData.publicKey, + depositData.withdrawalCredentials, + depositData.signature, + depositData.depositDataRoot, + depositData.depositAmount + ); + + // will revert if not enough assets + availableAssets -= depositData.depositAmount; + + unchecked { + // cannot realistically overflow + ++i; + } } - - // deposit GNO tokens to the validators registry - IGnoValidatorsRegistry(_validatorsRegistry).deposit( - publicKey, - abi.encodePacked(withdrawalCredsPrefix, bytes11(0x0), address(this)), - signature, - depositDataRoot, - depositAmount - ); - } - - /// @inheritdoc VaultValidators - function _withdrawValidator( - bytes calldata validator - ) - internal - virtual - override - returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) - { - (publicKey, withdrawnAmount, feePaid) = super._withdrawValidator(validator); - // convert mGNO to GNO - withdrawnAmount /= 32; } /// @inheritdoc VaultState @@ -137,16 +124,6 @@ abstract contract VaultGnoStaking is SafeERC20.safeTransfer(_gnoToken, receiver, assets); } - /// @inheritdoc VaultValidators - function _validatorMinEffectiveBalance() internal pure override returns (uint256) { - return 1 ether; - } - - /// @inheritdoc VaultValidators - function _validatorMaxEffectiveBalance() internal pure override returns (uint256) { - return 64 ether; - } - /** * @dev Pulls assets from withdrawal contract */ diff --git a/contracts/vaults/modules/VaultOsToken.sol b/contracts/vaults/modules/VaultOsToken.sol index 5c077ace..2bc30b78 100644 --- a/contracts/vaults/modules/VaultOsToken.sol +++ b/contracts/vaults/modules/VaultOsToken.sol @@ -12,6 +12,7 @@ import {Errors} from '../../libraries/Errors.sol'; import {VaultImmutables} from './VaultImmutables.sol'; import {VaultEnterExit, IVaultEnterExit} from './VaultEnterExit.sol'; import {VaultState} from './VaultState.sol'; +import {OsTokenUtils} from '../../libraries/OsTokenUtils.sol'; /** * @title VaultOsToken @@ -19,10 +20,7 @@ import {VaultState} from './VaultState.sol'; * @notice Defines the functionality for minting OsToken */ abstract contract VaultOsToken is VaultImmutables, VaultState, VaultEnterExit, IVaultOsToken { - uint256 private constant _wad = 1e18; - uint256 private constant _hfLiqThreshold = 1e18; uint256 private constant _maxPercent = 1e18; - uint256 private constant _disabledLiqThreshold = type(uint64).max; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IOsTokenVaultController private immutable _osTokenVaultController; @@ -254,44 +252,18 @@ abstract contract VaultOsToken is VaultImmutables, VaultState, VaultEnterExit, I if (position.shares == 0) revert Errors.InvalidPosition(); _syncPositionFee(position); - // SLOAD to memory - IOsTokenConfig.Config memory osTokenConfig = _osTokenConfig.getConfig(address(this)); - if (isLiquidation && osTokenConfig.liqThresholdPercent == _disabledLiqThreshold) { - revert Errors.LiquidationDisabled(); - } - // calculate received assets - if (isLiquidation) { - receivedAssets = Math.mulDiv( - _osTokenVaultController.convertToAssets(osTokenShares), - osTokenConfig.liqBonusPercent, - _maxPercent - ); - } else { - receivedAssets = _osTokenVaultController.convertToAssets(osTokenShares); - } - - { - // check whether received assets are valid - uint256 depositedAssets = convertToAssets(_balances[owner]); - if (receivedAssets > depositedAssets || receivedAssets > withdrawableAssets()) { - revert Errors.InvalidReceivedAssets(); - } - - uint256 mintedAssets = _osTokenVaultController.convertToAssets(position.shares); - if (isLiquidation) { - // check health factor violation in case of liquidation - if ( - Math.mulDiv( - depositedAssets * _wad, - osTokenConfig.liqThresholdPercent, - mintedAssets * _maxPercent - ) >= _hfLiqThreshold - ) { - revert Errors.InvalidHealthFactor(); - } - } - } + receivedAssets = OsTokenUtils.calculateReceivedAssets( + _osTokenConfig, + _osTokenVaultController, + OsTokenUtils.RedemptionData({ + mintedAssets: _osTokenVaultController.convertToAssets(position.shares), + depositedAssets: convertToAssets(_balances[owner]), + redeemedOsTokenShares: osTokenShares, + availableAssets: withdrawableAssets(), + isLiquidation: isLiquidation + }) + ); // reduce osToken supply _osTokenVaultController.burnShares(msg.sender, osTokenShares); diff --git a/contracts/vaults/modules/VaultState.sol b/contracts/vaults/modules/VaultState.sol index c8a03618..759803dd 100644 --- a/contracts/vaults/modules/VaultState.sol +++ b/contracts/vaults/modules/VaultState.sol @@ -23,8 +23,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault uint128 internal _totalShares; uint128 internal _totalAssets; - /// @inheritdoc IVaultState - uint128 public override queuedShares; + uint128 internal _queuedShares; uint128 internal _unclaimedAssets; ExitQueue.History internal _exitQueue; @@ -33,8 +32,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault uint256 private _capacity; - /// @inheritdoc IVaultState - uint128 public override totalExitingAssets; // deprecated + uint128 internal _totalExitingAssets; // deprecated uint128 internal _totalExitingTickets; // deprecated uint256 internal _totalExitedTickets; // deprecated @@ -48,6 +46,26 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault return _totalAssets; } + /// @inheritdoc IVaultState + function getExitQueueData() + external + view + override + returns ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) + { + return ( + _queuedShares, + _unclaimedAssets, + _totalExitingAssets, + ExitQueue.getLatestTotalTickets(_exitQueue) + ); + } + /// @inheritdoc IVaultState function getShares(address account) external view override returns (uint256) { return _balances[account]; @@ -79,8 +97,8 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault unchecked { // calculate assets that are reserved by users who queued for exit // cannot overflow as it is capped with underlying asset total supply - uint256 reservedAssets = convertToAssets(queuedShares) + - totalExitingAssets + + uint256 reservedAssets = convertToAssets(_queuedShares) + + _totalExitingAssets + _unclaimedAssets; return vaultAssets > reservedAssets ? vaultAssets - reservedAssets : 0; } @@ -119,21 +137,21 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault uint256 penalty = uint256(-totalAssetsDelta); // SLOAD to memory - uint256 _totalExitingAssets = totalExitingAssets; - if (_totalExitingAssets > 0) { + uint256 totalExitingAssets = _totalExitingAssets; + if (totalExitingAssets > 0) { // apply penalty to exiting assets uint256 exitingAssetsPenalty = Math.mulDiv( penalty, - _totalExitingAssets, - _totalExitingAssets + newTotalAssets + totalExitingAssets, + totalExitingAssets + newTotalAssets ); // apply penalty to total exiting assets unchecked { // cannot underflow as exitingAssetsPenalty <= penalty penalty -= exitingAssetsPenalty; - // cannot underflow as exitingAssetsPenalty <= _totalExitingAssets - totalExitingAssets = SafeCast.toUint128(_totalExitingAssets - exitingAssetsPenalty); + // cannot underflow as exitingAssetsPenalty <= totalExitingAssets + _totalExitingAssets = SafeCast.toUint128(totalExitingAssets - exitingAssetsPenalty); } emit ExitingAssetsPenalized(exitingAssetsPenalty); } @@ -192,35 +210,35 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault if (availableAssets == 0) return 0; // SLOAD to memory - uint256 _totalExitingAssets = totalExitingAssets; - if (_totalExitingAssets > 0) { + uint256 totalExitingAssets = _totalExitingAssets; + if (totalExitingAssets > 0) { // wait for all the exiting assets from v2 to be processed - if (availableAssets < _totalExitingAssets) return 0; + if (availableAssets < totalExitingAssets) return 0; // SLOAD to memory - uint256 totalExitingTickets = _totalExitingTickets; + uint256 totalExitingTickets = totalExitingAssets; // push checkpoint so that exited assets could be claimed - _exitQueue.push(totalExitingTickets, _totalExitingAssets); - emit CheckpointCreated(totalExitingTickets, _totalExitingAssets); + _exitQueue.push(totalExitingTickets, totalExitingAssets); + emit CheckpointCreated(totalExitingTickets, totalExitingAssets); unchecked { // cannot underflow as _totalExitingAssets <= availableAssets - availableAssets -= _totalExitingAssets; + availableAssets -= totalExitingAssets; } // update state - _unclaimedAssets += SafeCast.toUint128(_totalExitingAssets); + _unclaimedAssets += SafeCast.toUint128(totalExitingAssets); _totalExitingTickets = 0; - totalExitingAssets = 0; + _totalExitingAssets = 0; } // SLOAD to memory - uint256 _queuedShares = queuedShares; - if (_queuedShares == 0 || availableAssets == 0) return 0; + uint256 queuedShares = _queuedShares; + if (queuedShares == 0 || availableAssets == 0) return 0; // calculate the amount of assets that can be exited - uint256 exitedAssets = Math.min(availableAssets, convertToAssets(_queuedShares)); + uint256 exitedAssets = Math.min(availableAssets, convertToAssets(queuedShares)); if (exitedAssets == 0) return 0; // calculate the amount of shares that can be burned @@ -228,7 +246,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault if (burnedShares == 0) return 0; // update queued shares and unclaimed assets - queuedShares = SafeCast.toUint128(_queuedShares - burnedShares); + _queuedShares = SafeCast.toUint128(queuedShares - burnedShares); _unclaimedAssets += SafeCast.toUint128(exitedAssets); // push checkpoint so that exited assets could be claimed diff --git a/contracts/vaults/modules/VaultValidators.sol b/contracts/vaults/modules/VaultValidators.sol index 34c6f29b..07cfad67 100644 --- a/contracts/vaults/modules/VaultValidators.sol +++ b/contracts/vaults/modules/VaultValidators.sol @@ -2,16 +2,15 @@ pragma solidity ^0.8.22; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; -import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; import {IKeeperValidators} from '../../interfaces/IKeeperValidators.sol'; import {IVaultValidators} from '../../interfaces/IVaultValidators.sol'; import {IConsolidationsChecker} from '../../interfaces/IConsolidationsChecker.sol'; import {IDepositDataRegistry} from '../../interfaces/IDepositDataRegistry.sol'; import {Errors} from '../../libraries/Errors.sol'; +import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; +import {EIP712Utils} from '../../libraries/EIP712Utils.sol'; import {VaultImmutables} from './VaultImmutables.sol'; import {VaultAdmin} from './VaultAdmin.sol'; import {VaultState} from './VaultState.sol'; @@ -29,13 +28,6 @@ abstract contract VaultValidators is VaultState, IVaultValidators { - bytes32 private constant _validatorsManagerTypeHash = - keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'); - uint256 internal constant _validatorV1DepositLength = 176; - uint256 internal constant _validatorV2DepositLength = 184; - uint256 private constant _validatorWithdrawalLength = 56; - uint256 private constant _validatorConsolidationLength = 96; - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable _depositDataRegistry; @@ -111,12 +103,27 @@ abstract contract VaultValidators is ) external override { // check whether oracles have approve validators registration IKeeperValidators(_keeper).approveValidators(keeperParams); - _registerValidators( - keeperParams.validators, - keeperParams.validatorsRegistryRoot, - validatorsManagerSignature, - false - ); + + // check vault is up to date + _checkHarvested(); + + // check access + if ( + !_isValidatorsManager( + keeperParams.validators, + keeperParams.validatorsRegistryRoot, + validatorsManagerSignature + ) + ) { + revert Errors.AccessDenied(); + } + + // get validator deposits + ValidatorUtils.ValidatorDeposit[] memory validatorDeposits = ValidatorUtils + .getValidatorDeposits(v2Validators, keeperParams.validators, false); + + // register validators + _registerValidators(validatorDeposits); } /// @inheritdoc IVaultValidators @@ -124,12 +131,22 @@ abstract contract VaultValidators is bytes calldata validators, bytes calldata validatorsManagerSignature ) external override { - _registerValidators( - validators, - bytes32(validatorsManagerNonce), - validatorsManagerSignature, - true - ); + // check vault is up to date + _checkHarvested(); + + // check access + if ( + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) + ) { + revert Errors.AccessDenied(); + } + + // get validator deposits + ValidatorUtils.ValidatorDeposit[] memory validatorDeposits = ValidatorUtils + .getValidatorDeposits(v2Validators, validators, true); + + // top up validators + _registerValidators(validatorDeposits); } /// @inheritdoc IVaultValidators @@ -139,37 +156,7 @@ abstract contract VaultValidators is ) external payable override nonReentrant { _checkCollateralized(); _checkCanWithdrawValidators(validators, validatorsManagerSignature); - - // check validators length is valid - uint256 validatorsCount = validators.length / _validatorWithdrawalLength; - unchecked { - if (validatorsCount == 0 || validators.length % _validatorWithdrawalLength != 0) { - revert Errors.InvalidValidators(); - } - } - - uint256 feePaid; - uint256 withdrawnAmount; - uint256 totalFeeAssets = msg.value; - bytes calldata publicKey; - uint256 startIndex; - for (uint256 i = 0; i < validatorsCount; ) { - (publicKey, withdrawnAmount, feePaid) = _withdrawValidator( - validators[startIndex:startIndex + _validatorWithdrawalLength] - ); - totalFeeAssets -= feePaid; - emit ValidatorWithdrawalSubmitted(publicKey, withdrawnAmount, feePaid); - - unchecked { - // cannot realistically overflow - ++i; - startIndex += _validatorWithdrawalLength; - } - } - - if (totalFeeAssets > 0) { - Address.sendValue(payable(msg.sender), totalFeeAssets); - } + ValidatorUtils.withdrawValidators(validators, _validatorsWithdrawals); } /// @inheritdoc IVaultValidators @@ -177,7 +164,7 @@ abstract contract VaultValidators is bytes calldata validators, bytes calldata validatorsManagerSignature, bytes calldata oracleSignatures - ) external payable override { + ) external payable override nonReentrant { _checkCollateralized(); if ( !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) @@ -185,14 +172,6 @@ abstract contract VaultValidators is revert Errors.AccessDenied(); } - // Check validators length is valid - uint256 validatorsCount = validators.length / _validatorConsolidationLength; - unchecked { - if (validatorsCount == 0 || validators.length % _validatorConsolidationLength != 0) { - revert Errors.InvalidValidators(); - } - } - // Check for oracle approval if signatures provided bool consolidationsApproved = false; if (oracleSignatures.length > 0) { @@ -205,58 +184,12 @@ abstract contract VaultValidators is consolidationsApproved = true; } - // Process the consolidation in smaller batches to avoid stack depth issues - _processConsolidation(validators, validatorsCount, consolidationsApproved); - } - - /** - * @dev Internal function to process validator consolidations - * @param validators The concatenated validators data - * @param validatorsCount The number of validators to consolidate - * @param consolidationsApproved Whether the consolidations are approved by oracles - */ - function _processConsolidation( - bytes calldata validators, - uint256 validatorsCount, - bool consolidationsApproved - ) private nonReentrant { - uint256 totalFeeAssets = msg.value; - - // Process each validator - bytes32 destPubKeyHash; - bytes calldata sourcePublicKey; - bytes calldata destPublicKey; - uint256 feePaid; - uint256 startIndex; - for (uint256 i = 0; i < validatorsCount; ) { - // consolidate validators - (sourcePublicKey, destPublicKey, feePaid) = _consolidateValidator( - validators[startIndex:startIndex + _validatorConsolidationLength] - ); - - // check whether the destination public key is tracked or approved - destPubKeyHash = keccak256(destPublicKey); - if (consolidationsApproved) { - v2Validators[destPubKeyHash] = true; - } else if (!v2Validators[destPubKeyHash]) { - revert Errors.InvalidValidators(); - } - - // Update fees and emit event - unchecked { - // cannot realistically overflow - totalFeeAssets -= feePaid; - startIndex += _validatorConsolidationLength; - ++i; - } - - emit ValidatorConsolidationSubmitted(sourcePublicKey, destPublicKey, feePaid); - } - - // refund unused fees - if (totalFeeAssets > 0) { - Address.sendValue(payable(msg.sender), totalFeeAssets); - } + ValidatorUtils.consolidateValidators( + v2Validators, + validators, + consolidationsApproved, + _validatorsConsolidations + ); } /// @inheritdoc IVaultValidators @@ -267,153 +200,11 @@ abstract contract VaultValidators is emit ValidatorsManagerUpdated(msg.sender, validatorsManager_); } - /** - * @dev Internal function for registering validator - * @param validator The validator registration data - * @param isV1Validator Whether the validator is V1 or V2 - * @return depositAmount The amount of assets that was deposited - * @return publicKey The public key of the registered validator - */ - function _registerValidator( - bytes calldata validator, - bool isV1Validator - ) internal virtual returns (uint256 depositAmount, bytes calldata publicKey); - - /** - * @dev Internal function for withdrawing validator - * @param validator The validator withdrawal data - * @return publicKey The public key of the withdrawn validator - * @return withdrawnAmount The amount of assets that was withdrawn - * @return feePaid The amount of fee that was paid - */ - function _withdrawValidator( - bytes calldata validator - ) internal virtual returns (bytes calldata publicKey, uint256 withdrawnAmount, uint256 feePaid) { - publicKey = validator[:48]; - // convert gwei to wei by multiplying by 1 gwei - withdrawnAmount = (uint256(uint64(bytes8(validator[48:56]))) * 1 gwei); - feePaid = uint256(bytes32(Address.functionStaticCall(_validatorsWithdrawals, ''))); - - Address.functionCallWithValue(_validatorsWithdrawals, validator, feePaid); - } - - /** - * @dev Internal function for consolidating validators - * @param fromPublicKey The public key of the validator that was consolidated - * @param toPublicKey The public key of the validator that was consolidated to - * @param feePaid The amount of fee that was paid - */ - function _consolidateValidator( - bytes calldata validator - ) private returns (bytes calldata fromPublicKey, bytes calldata toPublicKey, uint256 feePaid) { - fromPublicKey = validator[:48]; - toPublicKey = validator[48:96]; - feePaid = uint256(bytes32(Address.functionStaticCall(_validatorsConsolidations, ''))); - - Address.functionCallWithValue(_validatorsConsolidations, validator, feePaid); - } - - /** - * @dev Internal function for fetching validator minimum effective balance - * @return The minimum effective balance for the validator - */ - function _validatorMinEffectiveBalance() internal pure virtual returns (uint256); - - /** - * @dev Internal function for fetching validator maximum effective balance - * @return The maximum effective balance for the validator - */ - function _validatorMaxEffectiveBalance() internal pure virtual returns (uint256); - /** * @dev Internal function for registering validators - * @param validators The concatenated validators data - * @param nonce The nonce of the signature - * @param validatorsManagerSignature The optional signature from the validators manager - * @param isTopUp Whether the registration is a balance top-up + * @param deposits The validators registration data */ - function _registerValidators( - bytes calldata validators, - bytes32 nonce, - bytes calldata validatorsManagerSignature, - bool isTopUp - ) private { - // check vault is up to date - _checkHarvested(); - - // check access - if (!_isValidatorsManager(validators, nonce, validatorsManagerSignature)) { - revert Errors.AccessDenied(); - } - - // check validators length is valid - uint256 validatorsLength = validators.length; - bool isV1Validators = validatorsLength % _validatorV1DepositLength == 0; - bool isV2Validators = validatorsLength % _validatorV2DepositLength == 0; - if ( - validatorsLength == 0 || - (isV1Validators && isV2Validators) || - (!isV1Validators && !isV2Validators) - ) { - revert Errors.InvalidValidators(); - } - - // top up is only allowed for V2 validators - if (isTopUp && isV1Validators) { - revert Errors.CannotTopUpV1Validators(); - } - - uint256 _validatorDepositLength = ( - isV1Validators ? _validatorV1DepositLength : _validatorV2DepositLength - ); - uint256 validatorsCount = validatorsLength / _validatorDepositLength; - - uint256 startIndex; - uint256 availableDeposits = withdrawableAssets(); - bytes calldata validators_ = validators; // push down the stack - for (uint256 i = 0; i < validatorsCount; ) { - (uint256 depositAmount, bytes calldata publicKey) = _registerValidator( - validators_[startIndex:startIndex + _validatorDepositLength], - isV1Validators - ); - availableDeposits -= depositAmount; - - bytes32 publicKeyHash = keccak256(publicKey); - if (isTopUp) { - // check whether validator is tracked in case of the top-up - if (!v2Validators[publicKeyHash]) revert Errors.InvalidValidators(); - emit ValidatorFunded(publicKey, depositAmount); - unchecked { - // cannot realistically overflow - ++i; - startIndex += _validatorDepositLength; - } - continue; - } - - // check the registration amount - if ( - depositAmount > _validatorMaxEffectiveBalance() || - depositAmount < _validatorMinEffectiveBalance() - ) { - revert Errors.InvalidAssets(); - } - - // mark v2 validator public key as tracked - if (!isV1Validators) { - v2Validators[publicKeyHash] = true; - emit V2ValidatorRegistered(publicKey, depositAmount); - } else { - emit ValidatorRegistered(publicKey); - } - - unchecked { - // cannot realistically overflow - ++i; - startIndex += _validatorDepositLength; - } - } - } + function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual; /** * @dev Internal function for checking whether the caller can withdraw validators @@ -450,9 +241,14 @@ abstract contract VaultValidators is } // check signature - bool isValidSignature = SignatureChecker.isValidSignatureNow( + bytes32 domainSeparator = block.chainid == _initialChainId + ? _initialDomainSeparator + : _computeVaultValidatorsDomain(); + bool isValidSignature = ValidatorUtils.isValidManagerSignature( + nonce, + domainSeparator, validatorsManager_, - _getValidatorsManagerSigningMessage(nonce, validators), + validators, validatorsManagerSignature ); @@ -467,45 +263,13 @@ abstract contract VaultValidators is return isValidSignature; } - /** - * @notice Get the message to be signed by the validators manager - * @param nonce The nonce of the message - * @param validators The concatenated validators data - * @return The message to be signed - */ - function _getValidatorsManagerSigningMessage( - bytes32 nonce, - bytes calldata validators - ) private view returns (bytes32) { - bytes32 domainSeparator = block.chainid == _initialChainId - ? _initialDomainSeparator - : _computeVaultValidatorsDomain(); - - return - MessageHashUtils.toTypedDataHash( - domainSeparator, - keccak256(abi.encode(_validatorsManagerTypeHash, nonce, keccak256(validators))) - ); - } - /** * @notice Computes the hash of the EIP712 typed data * @dev This function is used to compute the hash of the EIP712 typed data * @return The hash of the EIP712 typed data */ function _computeVaultValidatorsDomain() private view returns (bytes32) { - return - keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes('VaultValidators')), - keccak256('1'), - block.chainid, - address(this) - ) - ); + return EIP712Utils.computeDomainSeparator('VaultValidators', address(this)); } /** @@ -534,11 +298,9 @@ abstract contract VaultValidators is /** * @dev Initializes the VaultValidators contract - * @dev NB! This initializer must be called after VaultState initializer */ function __VaultValidators_init() internal onlyInitializing { __ReentrancyGuard_init(); - if (capacity() < _validatorMinEffectiveBalance()) revert Errors.InvalidCapacity(); _initialDomainSeparator = _computeVaultValidatorsDomain(); } diff --git a/test/DepositDataRegistry.t.sol b/test/DepositDataRegistry.t.sol index 15326e21..fd7f52da 100644 --- a/test/DepositDataRegistry.t.sol +++ b/test/DepositDataRegistry.t.sol @@ -51,10 +51,13 @@ contract DepositDataRegistryTest is Test, EthHelpers { ), false ); + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = IEthVault( + validVault + ).getExitQueueData(); exitingAssets = - IEthVault(validVault).totalExitingAssets() + - IEthVault(validVault).convertToAssets(IEthVault(validVault).queuedShares()) + - address(validVault).balance; + totalExitingAssets + + IEthVault(validVault).convertToAssets(queuedShares) + + unclaimedAssets; invalidVault = makeAddr('invalidVault'); nonAdmin = makeAddr('nonAdmin'); diff --git a/test/EthBlocklistErc20Vault.t.sol b/test/EthBlocklistErc20Vault.t.sol index 907c8d32..320929ee 100644 --- a/test/EthBlocklistErc20Vault.t.sol +++ b/test/EthBlocklistErc20Vault.t.sol @@ -9,6 +9,11 @@ import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; import {EthBlocklistErc20Vault} from '../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthBlocklistErc20VaultTest is Test, EthHelpers { ForkContracts public contracts; EthBlocklistErc20Vault public vault; @@ -257,6 +262,12 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { _stopSnapshotGas(); EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); assertEq(blocklistVault.version(), 5); assertEq(blocklistVault.admin(), admin); @@ -265,10 +276,12 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), 0); assertEq(blocklistVault.totalShares(), _securityDeposit); assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(blocklistVault.totalExitingAssets(), 0); + assertEq(queuedShares, 0); + assertEq(totalTickets, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.totalSupply(), _securityDeposit); assertEq(blocklistVault.symbol(), 'SW-ETH-1'); @@ -302,8 +315,8 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { uint256 totalSharesBefore = blocklistVault.totalShares(); uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); - uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(blocklistVault)).queuedShares(); uint256 senderBalanceBefore = blocklistVault.getShares(sender); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); @@ -313,6 +326,7 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthBlocklistErc20Vault, address(blocklistVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); assertEq(blocklistVault.version(), 5); assertEq(blocklistVault.admin(), admin); @@ -321,10 +335,10 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(queuedShares, queuedSharesBefore); assertEq(blocklistVault.totalShares(), totalSharesBefore); assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.getShares(sender), senderBalanceBefore); assertEq(blocklistVault.totalSupply(), totalSharesBefore); diff --git a/test/EthBlocklistVault.t.sol b/test/EthBlocklistVault.t.sol index c8364af4..4390f41b 100644 --- a/test/EthBlocklistVault.t.sol +++ b/test/EthBlocklistVault.t.sol @@ -10,6 +10,11 @@ import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; import {EthBlocklistVault} from '../contracts/vaults/ethereum/EthBlocklistVault.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthBlocklistVaultTest is Test, EthHelpers { ForkContracts public contracts; EthBlocklistVault public vault; @@ -224,6 +229,12 @@ contract EthBlocklistVaultTest is Test, EthHelpers { _stopSnapshotGas(); EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); assertEq(blocklistVault.version(), 5); assertEq(blocklistVault.admin(), admin); @@ -232,11 +243,13 @@ contract EthBlocklistVaultTest is Test, EthHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), 0); assertEq(blocklistVault.totalShares(), _securityDeposit); assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(blocklistVault.totalExitingAssets(), 0); assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(totalExitingAssets, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -259,8 +272,8 @@ contract EthBlocklistVaultTest is Test, EthHelpers { uint256 totalSharesBefore = blocklistVault.totalShares(); uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); - uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(blocklistVault)).queuedShares(); uint256 senderSharesBefore = blocklistVault.getShares(sender); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); @@ -270,6 +283,8 @@ contract EthBlocklistVaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthBlocklistVault, address(blocklistVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); assertEq(blocklistVault.version(), 5); assertEq(blocklistVault.admin(), admin); @@ -278,10 +293,10 @@ contract EthBlocklistVaultTest is Test, EthHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(queuedShares, queuedSharesBefore); assertEq(blocklistVault.totalShares(), totalSharesBefore); assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.getShares(sender), senderSharesBefore); } diff --git a/test/EthErc20Vault.t.sol b/test/EthErc20Vault.t.sol index a0c402d5..02182d99 100644 --- a/test/EthErc20Vault.t.sol +++ b/test/EthErc20Vault.t.sol @@ -11,6 +11,11 @@ import {Errors} from '../contracts/libraries/Errors.sol'; import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthErc20VaultTest is Test, EthHelpers { ForkContracts public contracts; EthErc20Vault public vault; @@ -72,6 +77,12 @@ contract EthErc20VaultTest is Test, EthHelpers { _stopSnapshotGas(); EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = erc20Vault.getExitQueueData(); assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); assertEq(erc20Vault.version(), 5); assertEq(erc20Vault.admin(), admin); @@ -79,14 +90,16 @@ contract EthErc20VaultTest is Test, EthHelpers { assertEq(erc20Vault.feePercent(), 1000); assertEq(erc20Vault.feeRecipient(), admin); assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.queuedShares(), 0); assertEq(erc20Vault.totalShares(), _securityDeposit); assertEq(erc20Vault.totalAssets(), _securityDeposit); - assertEq(erc20Vault.totalExitingAssets(), 0); assertEq(erc20Vault.validatorsManagerNonce(), 0); assertEq(erc20Vault.totalSupply(), _securityDeposit); assertEq(erc20Vault.symbol(), 'SW-ETH-1'); assertEq(erc20Vault.name(), 'SW ETH Vault'); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -116,9 +129,9 @@ contract EthErc20VaultTest is Test, EthHelpers { uint256 totalSharesBefore = erc20Vault.totalShares(); uint256 totalAssetsBefore = erc20Vault.totalAssets(); - uint256 totalExitingAssetsBefore = erc20Vault.totalExitingAssets(); - uint256 queuedSharesBefore = erc20Vault.queuedShares(); uint256 senderBalanceBefore = erc20Vault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(erc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(erc20Vault)).queuedShares(); assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); assertEq(erc20Vault.version(), 4); @@ -127,6 +140,8 @@ contract EthErc20VaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthErc20Vault, address(erc20Vault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); + assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); assertEq(erc20Vault.version(), 5); assertEq(erc20Vault.admin(), admin); @@ -134,10 +149,10 @@ contract EthErc20VaultTest is Test, EthHelpers { assertEq(erc20Vault.feePercent(), 1000); assertEq(erc20Vault.feeRecipient(), admin); assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.queuedShares(), queuedSharesBefore); + assertEq(queuedShares, queuedSharesBefore); assertEq(erc20Vault.totalShares(), totalSharesBefore); assertEq(erc20Vault.totalAssets(), totalAssetsBefore); - assertEq(erc20Vault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); assertEq(erc20Vault.validatorsManagerNonce(), 0); assertEq(erc20Vault.getShares(sender), senderBalanceBefore); assertEq(erc20Vault.totalSupply(), totalSharesBefore); @@ -465,7 +480,8 @@ contract EthErc20VaultTest is Test, EthHelpers { // Verify the exit queue was processed correctly // The queue might not be fully processed in one update, so we'll check that progress was made - assertLt(vault.queuedShares(), exitShares, 'Exit queue should be at least partially processed'); + (uint128 queuedShares, , , ) = vault.getExitQueueData(); + assertLt(queuedShares, exitShares, 'Exit queue should be at least partially processed'); } // Helper function to deposit ETH to the vault diff --git a/test/EthFoxVault.t.sol b/test/EthFoxVault.t.sol index d1250dad..588385bf 100644 --- a/test/EthFoxVault.t.sol +++ b/test/EthFoxVault.t.sol @@ -51,7 +51,8 @@ contract EthFoxVaultTest is Test, EthHelpers { ); address _vault = _getOrCreateVault(VaultType.EthFoxVault, admin, initParams, false); vault = EthFoxVault(payable(_vault)); - exitingAssets = vault.convertToAssets(vault.queuedShares()) + address(vault).balance; + (uint128 queuedShares, , , ) = vault.getExitQueueData(); + exitingAssets = vault.convertToAssets(queuedShares) + address(vault).balance; } function test_deployFails() public { @@ -194,7 +195,7 @@ contract EthFoxVaultTest is Test, EthHelpers { // Deposit ETH to get vault shares _depositToVault(address(vault), amount, sender, sender); - uint256 queueSharesBefore = vault.queuedShares(); + (uint256 queuedSharesBefore, , , ) = vault.getExitQueueData(); // Set blocklist manager vm.prank(admin); @@ -214,7 +215,8 @@ contract EthFoxVaultTest is Test, EthHelpers { // User's shares should be in exit queue assertEq(vault.getShares(sender), 0); - assertApproxEqAbs(vault.queuedShares(), queueSharesBefore + shares, 1); + (uint256 queuedShares, , , ) = vault.getExitQueueData(); + assertApproxEqAbs(queuedShares, queuedSharesBefore + shares, 1); } function test_ejectUserWithNoShares() public { @@ -222,7 +224,7 @@ contract EthFoxVaultTest is Test, EthHelpers { vm.prank(admin); vault.setBlocklistManager(blocklistManager); - uint256 queueSharesBefore = vault.queuedShares(); + (uint256 queuedSharesBefore, , , ) = vault.getExitQueueData(); // Eject user with no shares _startSnapshotGas('EthFoxVaultTest_test_ejectUserWithNoShares'); @@ -234,7 +236,8 @@ contract EthFoxVaultTest is Test, EthHelpers { assertTrue(vault.blockedAccounts(sender)); // No shares should be in exit queue - assertEq(vault.queuedShares(), queueSharesBefore); + (uint256 queuedShares, , , ) = vault.getExitQueueData(); + assertEq(queuedShares, queuedSharesBefore); } function test_ejectUserFailsFromNonBlocklistManager() public { diff --git a/test/EthGenesisVault.t.sol b/test/EthGenesisVault.t.sol index 923eb186..7069b027 100644 --- a/test/EthGenesisVault.t.sol +++ b/test/EthGenesisVault.t.sol @@ -12,6 +12,11 @@ import {EthGenesisVault} from '../contracts/vaults/ethereum/EthGenesisVault.sol' import {Errors} from '../contracts/libraries/Errors.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthGenesisVaultTest is Test, EthHelpers { ForkContracts public contracts; address public admin; @@ -63,8 +68,8 @@ contract EthGenesisVaultTest is Test, EthHelpers { vm.deal( vaultAddr, - existingVault.totalExitingAssets() + - existingVault.convertToAssets(existingVault.queuedShares()) + + IVaultStateV4(address(existingVault)).totalExitingAssets() + + existingVault.convertToAssets(IVaultStateV4(address(existingVault)).queuedShares()) + vaultAddr.balance ); _depositToVault(address(existingVault), 40 ether, user, user); @@ -76,14 +81,14 @@ contract EthGenesisVaultTest is Test, EthHelpers { // Record initial state uint256 initialTotalAssets = existingVault.totalAssets(); uint256 initialTotalShares = existingVault.totalShares(); - uint256 totalExitingAssetsBefore = existingVault.totalExitingAssets(); - uint256 queuedSharesBefore = existingVault.queuedShares(); uint256 senderBalanceBefore = existingVault.getShares(user); uint256 initialCapacity = existingVault.capacity(); uint256 initialFeePercent = existingVault.feePercent(); address validatorsManager = existingVault.validatorsManager(); address feeRecipient = existingVault.feeRecipient(); address adminBefore = existingVault.admin(); + uint256 queuedSharesBefore = IVaultStateV4(address(existingVault)).queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(existingVault)).totalExitingAssets(); assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); assertEq(existingVault.version(), 4); @@ -92,6 +97,8 @@ contract EthGenesisVaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthGenesisVault, address(existingVault)); _stopSnapshotGas(); + (uint128 queuedSharesAfter, , uint128 totalExitingAssetsAfter, ) = existingVault + .getExitQueueData(); assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); assertEq(existingVault.version(), 5); assertEq(existingVault.admin(), adminBefore); @@ -99,10 +106,10 @@ contract EthGenesisVaultTest is Test, EthHelpers { assertEq(existingVault.feePercent(), initialFeePercent); assertEq(existingVault.feeRecipient(), feeRecipient); assertEq(existingVault.validatorsManager(), validatorsManager); - assertEq(existingVault.queuedShares(), queuedSharesBefore); + assertEq(queuedSharesAfter, queuedSharesBefore); assertEq(existingVault.totalShares(), initialTotalShares); assertEq(existingVault.totalAssets(), initialTotalAssets); - assertEq(existingVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(totalExitingAssetsAfter, totalExitingAssetsBefore); assertEq(existingVault.validatorsManagerNonce(), 0); assertEq(existingVault.getShares(user), senderBalanceBefore); } @@ -255,11 +262,10 @@ contract EthGenesisVaultTest is Test, EthHelpers { // Add some ETH to the pool escrow uint256 escrowAmount = 40 ether; vm.deal(poolEscrow, poolEscrow.balance + escrowAmount); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); vm.deal( address(vault), - address(vault).balance + - vault.convertToAssets(vault.queuedShares()) + - vault.totalExitingAssets() + address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets ); // Record initial balances @@ -335,9 +341,10 @@ contract EthGenesisVaultTest is Test, EthHelpers { address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - uint256 vaultAmount = vault.totalExitingAssets() + - vault.convertToAssets(vault.queuedShares()) + - vaultAddr.balance; + (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + uint256 vaultAmount = address(vault).balance + + vault.convertToAssets(queuedShares) + + totalExitingAssets; uint256 depositAmount = 3 ether; uint256 shares = vault.convertToShares(depositAmount); diff --git a/test/EthOsTokenVaultEscrow.t.sol b/test/EthOsTokenVaultEscrow.t.sol index 0a179e8d..9f46a540 100644 --- a/test/EthOsTokenVaultEscrow.t.sol +++ b/test/EthOsTokenVaultEscrow.t.sol @@ -60,11 +60,10 @@ contract EthOsTokenVaultEscrowTest is Test, EthHelpers { vault = IEthVault(_vault); // Ensure the vault has enough ETH to process exit requests + (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); vm.deal( address(vault), - address(vault).balance + - vault.totalExitingAssets() + - vault.convertToAssets(vault.queuedShares()) + address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets ); } diff --git a/test/EthPrivErc20Vault.t.sol b/test/EthPrivErc20Vault.t.sol index de082269..a5b72a09 100644 --- a/test/EthPrivErc20Vault.t.sol +++ b/test/EthPrivErc20Vault.t.sol @@ -10,6 +10,11 @@ import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; import {EthPrivErc20Vault} from '../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthPrivErc20VaultTest is Test, EthHelpers { ForkContracts public contracts; EthPrivErc20Vault public vault; @@ -364,6 +369,12 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { address _vault = _createVault(VaultType.EthPrivErc20Vault, admin, initParams, true); _stopSnapshotGas(); EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privErc20Vault.getExitQueueData(); assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); assertEq(privErc20Vault.version(), 5); @@ -373,14 +384,16 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { assertEq(privErc20Vault.feePercent(), 1000); assertEq(privErc20Vault.feeRecipient(), admin); assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.queuedShares(), 0); assertEq(privErc20Vault.totalShares(), _securityDeposit); assertEq(privErc20Vault.totalAssets(), _securityDeposit); - assertEq(privErc20Vault.totalExitingAssets(), 0); assertEq(privErc20Vault.validatorsManagerNonce(), 0); assertEq(privErc20Vault.totalSupply(), _securityDeposit); assertEq(privErc20Vault.symbol(), 'SW-ETH-1'); assertEq(privErc20Vault.name(), 'SW ETH Vault'); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -409,8 +422,8 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { uint256 totalSharesBefore = privErc20Vault.totalShares(); uint256 totalAssetsBefore = privErc20Vault.totalAssets(); - uint256 totalExitingAssetsBefore = privErc20Vault.totalExitingAssets(); - uint256 queuedSharesBefore = privErc20Vault.queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(privErc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(privErc20Vault)).queuedShares(); uint256 senderBalanceBefore = privErc20Vault.getShares(sender); assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); @@ -420,6 +433,7 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthPrivErc20Vault, address(privErc20Vault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); assertEq(privErc20Vault.version(), 5); assertEq(privErc20Vault.admin(), admin); @@ -428,14 +442,14 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { assertEq(privErc20Vault.feePercent(), 1000); assertEq(privErc20Vault.feeRecipient(), admin); assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.queuedShares(), queuedSharesBefore); assertEq(privErc20Vault.totalShares(), totalSharesBefore); assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); - assertEq(privErc20Vault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(privErc20Vault.validatorsManagerNonce(), 0); assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); assertEq(privErc20Vault.totalSupply(), totalSharesBefore); assertEq(privErc20Vault.symbol(), 'SW-ETH-1'); assertEq(privErc20Vault.name(), 'SW ETH Vault'); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); } } diff --git a/test/EthPrivVault.t.sol b/test/EthPrivVault.t.sol index ee901bf1..557e271b 100644 --- a/test/EthPrivVault.t.sol +++ b/test/EthPrivVault.t.sol @@ -10,6 +10,11 @@ import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; import {EthPrivVault} from '../contracts/vaults/ethereum/EthPrivVault.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthPrivVaultTest is Test, EthHelpers { ForkContracts public contracts; EthPrivVault public vault; @@ -305,6 +310,13 @@ contract EthPrivVaultTest is Test, EthHelpers { _stopSnapshotGas(); EthPrivVault privVault = EthPrivVault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privVault.getExitQueueData(); + assertEq(privVault.vaultId(), keccak256('EthPrivVault')); assertEq(privVault.version(), 5); assertEq(privVault.admin(), admin); @@ -313,11 +325,13 @@ contract EthPrivVaultTest is Test, EthHelpers { assertEq(privVault.feePercent(), 1000); assertEq(privVault.feeRecipient(), admin); assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.queuedShares(), 0); assertEq(privVault.totalShares(), _securityDeposit); assertEq(privVault.totalAssets(), _securityDeposit); - assertEq(privVault.totalExitingAssets(), 0); assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -348,10 +362,10 @@ contract EthPrivVaultTest is Test, EthHelpers { uint256 totalSharesBefore = privVault.totalShares(); uint256 totalAssetsBefore = privVault.totalAssets(); - uint256 totalExitingAssetsBefore = privVault.totalExitingAssets(); - uint256 queuedSharesBefore = privVault.queuedShares(); uint256 senderSharesBefore = privVault.getShares(sender); bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(privVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(privVault)).queuedShares(); assertEq(privVault.vaultId(), keccak256('EthPrivVault')); assertEq(privVault.version(), 4); @@ -360,6 +374,7 @@ contract EthPrivVaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthPrivVault, address(privVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); assertEq(privVault.vaultId(), keccak256('EthPrivVault')); assertEq(privVault.version(), 5); assertEq(privVault.admin(), admin); @@ -368,13 +383,13 @@ contract EthPrivVaultTest is Test, EthHelpers { assertEq(privVault.feePercent(), 1000); assertEq(privVault.feeRecipient(), admin); assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.queuedShares(), queuedSharesBefore); assertEq(privVault.totalShares(), totalSharesBefore); assertEq(privVault.totalAssets(), totalAssetsBefore); - assertEq(privVault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(privVault.validatorsManagerNonce(), 0); assertEq(privVault.getShares(sender), senderSharesBefore); assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(queuedShares, queuedSharesBefore); } function test_setWhitelister() public { diff --git a/test/EthValidatorsChecker.t.sol b/test/EthValidatorsChecker.t.sol index 5cac4900..ae3d4acd 100644 --- a/test/EthValidatorsChecker.t.sol +++ b/test/EthValidatorsChecker.t.sol @@ -396,7 +396,7 @@ contract EthValidatorsCheckerTest is Test, EthHelpers { // 5. Create the message hash that matches the contract's implementation bytes32 validatorsManagerTypeHash = keccak256( - 'VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)' + 'VaultValidators(bytes32 nonce,bytes validators)' ); bytes32 messageHash = keccak256( abi.encode(validatorsManagerTypeHash, validRegistryRoot, keccak256(validatorData)) diff --git a/test/EthVault.t.sol b/test/EthVault.t.sol index f57ee489..0cfbfc1f 100644 --- a/test/EthVault.t.sol +++ b/test/EthVault.t.sol @@ -7,11 +7,15 @@ import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Ini import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; import {Errors} from '../contracts/libraries/Errors.sol'; import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; +interface IVaultStateV4 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract EthVaultTest is Test, EthHelpers { ForkContracts public contracts; EthVault public vault; @@ -54,9 +58,10 @@ contract EthVaultTest is Test, EthHelpers { vm.prank(admin); vault.setValidatorsManager(validatorsManager); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = IEthVault(vault).getExitQueueData(); exitingAssets = - vault.totalExitingAssets() + - vault.convertToAssets(vault.queuedShares()) + + totalExitingAssets + + IEthVault(vault).convertToAssets(queuedShares) + vaultAddr.balance; } @@ -81,6 +86,12 @@ contract EthVaultTest is Test, EthHelpers { _stopSnapshotGas(); EthVault newVault = EthVault(payable(vaultAddr)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = newVault.getExitQueueData(); // Verify the vault was deployed correctly assertEq(newVault.vaultId(), keccak256('EthVault')); @@ -90,10 +101,12 @@ contract EthVaultTest is Test, EthHelpers { assertEq(newVault.feePercent(), 1000); assertEq(newVault.feeRecipient(), admin); assertEq(newVault.validatorsManager(), _depositDataRegistry); - assertEq(newVault.queuedShares(), 0); + assertEq(queuedShares, 0); + assertEq(totalTickets, 0); + assertEq(unclaimedAssets, 0); assertEq(newVault.totalShares(), _securityDeposit); assertEq(newVault.totalAssets(), _securityDeposit); - assertEq(newVault.totalExitingAssets(), 0); + assertEq(totalExitingAssets, 0); assertEq(newVault.validatorsManagerNonce(), 0); } @@ -122,9 +135,9 @@ contract EthVaultTest is Test, EthHelpers { // Record state before upgrade uint256 totalSharesBefore = prevVault.totalShares(); uint256 totalAssetsBefore = prevVault.totalAssets(); - uint256 totalExitingAssetsBefore = prevVault.totalExitingAssets(); - uint256 queuedSharesBefore = prevVault.queuedShares(); uint256 senderBalanceBefore = prevVault.getShares(sender); + uint256 queuedSharesBefore = IVaultStateV4(address(prevVault)).queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(prevVault)).totalExitingAssets(); // Verify current version assertEq(prevVault.vaultId(), keccak256('EthVault')); @@ -136,6 +149,7 @@ contract EthVaultTest is Test, EthHelpers { _stopSnapshotGas(); // Check that the vault was upgraded correctly + (uint128 queuedShares, , uint128 totalExitingAssets, ) = prevVault.getExitQueueData(); assertEq(prevVault.vaultId(), keccak256('EthVault')); assertEq(prevVault.version(), 5); assertEq(prevVault.admin(), admin); @@ -145,12 +159,12 @@ contract EthVaultTest is Test, EthHelpers { assertEq(prevVault.validatorsManager(), _depositDataRegistry); // State should be preserved - assertEq(prevVault.queuedShares(), queuedSharesBefore); assertEq(prevVault.totalShares(), totalSharesBefore); assertEq(prevVault.totalAssets(), totalAssetsBefore); - assertEq(prevVault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(prevVault.validatorsManagerNonce(), 0); assertEq(prevVault.getShares(sender), senderBalanceBefore); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); } function test_exitQueue_works() public { @@ -163,7 +177,12 @@ contract EthVaultTest is Test, EthHelpers { // Get initial state uint256 senderSharesBefore = vault.getShares(sender); - uint256 queuedSharesBefore = vault.queuedShares(); + ( + uint128 queuedSharesBefore, + uint128 unclaimedAssetsBefore, + uint128 totalExitingAssetsBefore, + uint256 totalTicketsBefore + ) = vault.getExitQueueData(); // Amount to exit with uint256 exitAmount = senderSharesBefore / 2; @@ -175,14 +194,56 @@ contract EthVaultTest is Test, EthHelpers { uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); _stopSnapshotGas(); + ( + uint128 queuedSharesAfter, + uint128 unclaimedAssetsAfter, + uint128 totalExitingAssetsAfter, + uint256 totalTicketsAfter + ) = vault.getExitQueueData(); + // Check state after entering exit queue assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, 'Sender shares not reduced'); - assertEq(vault.queuedShares(), queuedSharesBefore + exitAmount, 'Queued shares not increased'); + assertEq(queuedSharesAfter, queuedSharesBefore + exitAmount, 'Queued shares not increased'); + assertEq(unclaimedAssetsAfter, unclaimedAssetsBefore, 'Unclaimed assets should not change'); + assertEq( + totalExitingAssetsAfter, + totalExitingAssetsBefore, + 'Total exiting assets should not change' + ); + assertEq(totalTicketsAfter, totalTicketsBefore, 'Total tickets should not change'); + + queuedSharesBefore = queuedSharesAfter; + unclaimedAssetsBefore = unclaimedAssetsAfter; + totalExitingAssetsBefore = totalExitingAssetsAfter; + totalTicketsBefore = totalTicketsAfter; // Process exit queue by updating state IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); vault.updateState(harvestParams); + (queuedSharesAfter, unclaimedAssetsAfter, totalExitingAssetsAfter, totalTicketsAfter) = vault + .getExitQueueData(); + assertLt( + queuedSharesAfter, + queuedSharesBefore, + 'Queued shares should be reduced after processing exit queue' + ); + assertGt( + unclaimedAssetsAfter, + unclaimedAssetsBefore, + 'Unclaimed assets should increase after processing exit queue' + ); + assertEq( + totalExitingAssetsAfter, + totalExitingAssetsBefore, + 'Total exiting assets should not change after processing exit queue' + ); + assertGt( + totalTicketsAfter, + totalTicketsBefore, + 'Total tickets should increase after processing exit queue' + ); + // Check that position can be found in exit queue int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); assertGt(exitQueueIndex, -1, 'Exit queue index not found'); @@ -344,7 +405,12 @@ contract EthVaultTest is Test, EthHelpers { _stopSnapshotGas(); // Verify sender got vault shares - assertApproxEqAbs(vault.getShares(sender), depositShares, 1, 'Incorrect amount of vault shares'); + assertApproxEqAbs( + vault.getShares(sender), + depositShares, + 1, + 'Incorrect amount of vault shares' + ); // Verify osToken position uint128 osTokenShares = vault.osTokenPositions(sender); diff --git a/test/VaultAdmin.t.sol b/test/VaultAdmin.t.sol index c2b96a4f..0ad25ce9 100644 --- a/test/VaultAdmin.t.sol +++ b/test/VaultAdmin.t.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; -import {IVaultAdmin} from "../contracts/interfaces/IVaultAdmin.sol"; -import {Errors} from "../contracts/libraries/Errors.sol"; -import {CommonBase} from "../lib/forge-std/src/Base.sol"; -import {StdAssertions} from "../lib/forge-std/src/StdAssertions.sol"; -import {StdChains} from "../lib/forge-std/src/StdChains.sol"; -import {StdCheats, StdCheatsSafe} from "../lib/forge-std/src/StdCheats.sol"; -import {StdUtils} from "../lib/forge-std/src/StdUtils.sol"; -import {Test} from "../lib/forge-std/src/Test.sol"; -import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IVaultAdmin} from '../contracts/interfaces/IVaultAdmin.sol'; +import {Errors} from '../contracts/libraries/Errors.sol'; +import {CommonBase} from '../lib/forge-std/src/Base.sol'; +import {StdAssertions} from '../lib/forge-std/src/StdAssertions.sol'; +import {StdChains} from '../lib/forge-std/src/StdChains.sol'; +import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; +import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; +import {Test} from '../lib/forge-std/src/Test.sol'; +import {EthHelpers} from './helpers/EthHelpers.sol'; contract VaultAdminTest is Test, EthHelpers { ForkContracts public contracts; diff --git a/test/VaultEnterExit.t.sol b/test/VaultEnterExit.t.sol index c6fe789d..f71e3264 100644 --- a/test/VaultEnterExit.t.sol +++ b/test/VaultEnterExit.t.sol @@ -47,9 +47,10 @@ contract VaultEnterExitTest is Test, EthHelpers { address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); vault = EthVault(payable(vaultAddr)); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); vm.deal( - vaultAddr, - vault.convertToAssets(vault.queuedShares()) + vault.totalExitingAssets() + vaultAddr.balance + address(vault), + address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets ); } @@ -263,7 +264,7 @@ contract VaultEnterExitTest is Test, EthHelpers { // 3. Enter exit queue uint256 shares = vault.getShares(sender); - uint256 queuedSharesBefore = vault.queuedShares(); + (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); vm.prank(sender); uint256 timestamp = vm.getBlockTimestamp(); @@ -272,8 +273,9 @@ contract VaultEnterExitTest is Test, EthHelpers { _stopSnapshotGas(); // 4. Verify the position ticket was created and shares moved to the queue + (uint128 queuedShares, , , ) = vault.getExitQueueData(); assertEq( - vault.queuedShares(), + queuedShares, queuedSharesBefore + shares, 'Queued shares should equal the shares sent to exit queue' ); @@ -480,7 +482,8 @@ contract VaultEnterExitTest is Test, EthHelpers { // 3. Both users enter exit queue uint256 shares1 = vault.getShares(sender); uint256 shares2 = vault.getShares(sender2); - uint256 queuedSharesBefore = vault.queuedShares(); + + (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); vm.prank(sender); uint256 timestamp1 = vm.getBlockTimestamp(); @@ -495,8 +498,9 @@ contract VaultEnterExitTest is Test, EthHelpers { _stopSnapshotGas(); // 4. Verify the queued shares + (uint128 queuedShares, , , ) = vault.getExitQueueData(); assertEq( - vault.queuedShares(), + queuedShares, queuedSharesBefore + shares1 + shares2, 'Queued shares should equal the sum of all shares in exit queue' ); @@ -568,7 +572,7 @@ contract VaultEnterExitTest is Test, EthHelpers { // 2. Collateralize the vault _collateralizeEthVault(address(vault)); - uint256 queuedSharesBefore = vault.queuedShares(); + (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); // 3. Enter exit queue with half of the shares uint256 totalShares = vault.getShares(sender); @@ -582,8 +586,9 @@ contract VaultEnterExitTest is Test, EthHelpers { _stopSnapshotGas(); // 4. Verify the position ticket and remaining shares + (uint128 queuedShares, , , ) = vault.getExitQueueData(); assertEq( - vault.queuedShares(), + queuedShares, queuedSharesBefore + halfShares, 'Queued shares should equal the half shares sent to exit queue' ); diff --git a/test/VaultEthStaking.t.sol b/test/VaultEthStaking.t.sol index a662e2cc..cc274dc0 100644 --- a/test/VaultEthStaking.t.sol +++ b/test/VaultEthStaking.t.sol @@ -421,8 +421,9 @@ contract VaultEthStakingTest is Test, EthHelpers { _collateralizeEthVault(address(vault)); // Deposit ETH to the vault - uint256 senderDeposit = vault.convertToAssets(vault.queuedShares()) + - vault.totalExitingAssets() + + (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + uint256 senderDeposit = vault.convertToAssets(queuedShares) + + totalExitingAssets + depositAmount; _depositToVault(address(vault), senderDeposit, sender, sender); diff --git a/test/VaultState.t.sol b/test/VaultState.t.sol index 562c0e2c..b2618aea 100644 --- a/test/VaultState.t.sol +++ b/test/VaultState.t.sol @@ -47,7 +47,12 @@ contract VaultStateTest is Test, EthHelpers { address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); vault = EthVault(payable(vaultAddr)); - vm.deal(vaultAddr, vault.totalExitingAssets() + vault.convertToAssets(vault.queuedShares())); + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + .getExitQueueData(); + vm.deal( + address(vault), + unclaimedAssets + vault.convertToAssets(queuedShares) + totalExitingAssets + ); // Initial deposit to the vault _depositToVault(address(vault), initialDeposit, owner, owner); @@ -274,7 +279,7 @@ contract VaultStateTest is Test, EthHelpers { // Record owner's ETH balance before uint256 ownerBalanceBefore = owner.balance; - uint256 queuedSharesBefore = vault.queuedShares(); + (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); vm.expectEmit(true, true, true, false); emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); @@ -293,8 +298,9 @@ contract VaultStateTest is Test, EthHelpers { ); // Verify queued shares increased + (uint128 queuedShares, , , ) = vault.getExitQueueData(); assertEq( - vault.queuedShares(), + queuedShares, queuedSharesBefore + exitShares, 'Queued shares should match exit amount' ); @@ -476,10 +482,11 @@ contract VaultStateTest is Test, EthHelpers { // Step 2: User enters exit queue with all shares uint256 user1Shares = vault.getShares(user1); - uint256 vaultBalance = vault.totalExitingAssets() + - vault.convertToAssets(vault.queuedShares()) + - address(vault).balance - - vault.withdrawableAssets(); + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + .getExitQueueData(); + uint256 vaultBalance = totalExitingAssets + + vault.convertToAssets(queuedShares) + + unclaimedAssets; vm.expectEmit(true, true, true, false); emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); diff --git a/test/VaultToken.t.sol b/test/VaultToken.t.sol index 32407ae2..4b38adf6 100644 --- a/test/VaultToken.t.sol +++ b/test/VaultToken.t.sol @@ -346,7 +346,8 @@ contract VaultTokenTest is Test, EthHelpers { assertEq(ownerFinalBalance, ownerInitialBalance - exitShares, 'Owner balance should decrease'); // Verify queued shares - assertEq(vault.queuedShares(), exitShares, 'Queued shares should match exit amount'); + (uint128 queuedShares, , , ) = vault.getExitQueueData(); + assertEq(queuedShares, exitShares, 'Queued shares should match exit amount'); } // Test _updateExitQueue burns shares and emits Transfer diff --git a/test/VaultValidators.t.sol b/test/VaultValidators.t.sol index 741decca..1ccc9b9e 100644 --- a/test/VaultValidators.t.sol +++ b/test/VaultValidators.t.sol @@ -403,10 +403,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Extract the public key from validators data bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - vm.assertFalse( - vault.v2Validators(keccak256(publicKey)), - 'Validator should not be tracked' - ); + vm.assertFalse(vault.v2Validators(keccak256(publicKey)), 'Validator should not be tracked'); // For V1 validators, the event is emitted without deposit amount vm.expectEmit(true, true, true, false); @@ -421,10 +418,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Cleanup _stopOracleImpersonate(address(contracts.keeper)); - vm.assertFalse( - vault.v2Validators(keccak256(publicKey)), - 'Validator should not be tracked' - ); + vm.assertFalse(vault.v2Validators(keccak256(publicKey)), 'Validator should not be tracked'); } // Test V2 validator registration (with 0x02 prefix) @@ -442,10 +436,7 @@ contract VaultValidatorsTest is Test, EthHelpers { // Extract the public key from validators data bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - vm.assertFalse( - vault.v2Validators(keccak256(publicKey)), - 'Validator should not be tracked' - ); + vm.assertFalse(vault.v2Validators(keccak256(publicKey)), 'Validator should not be tracked'); // For V2 validators, the event includes deposit amount vm.expectEmit(true, true, true, true); @@ -537,7 +528,7 @@ contract VaultValidatorsTest is Test, EthHelpers { bytes32 structHash = keccak256( abi.encode( - keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'), + keccak256('VaultValidators(bytes32 nonce,bytes validators)'), validatorsRegistryRoot, keccak256(validators) ) diff --git a/test/gnosis/GnoBlocklistErc20Vault.t.sol b/test/gnosis/GnoBlocklistErc20Vault.t.sol index 6621fc6a..8c9b6d11 100644 --- a/test/gnosis/GnoBlocklistErc20Vault.t.sol +++ b/test/gnosis/GnoBlocklistErc20Vault.t.sol @@ -8,6 +8,11 @@ import {Errors} from '../../contracts/libraries/Errors.sol'; import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; import {GnoBlocklistErc20Vault} from '../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { ForkContracts public contracts; GnoBlocklistErc20Vault public vault; @@ -241,6 +246,12 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { _stopSnapshotGas(); GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); assertEq(blocklistVault.version(), 3); assertEq(blocklistVault.admin(), admin); @@ -249,10 +260,12 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), 0); assertEq(blocklistVault.totalShares(), _securityDeposit); assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(blocklistVault.totalExitingAssets(), 0); + assertEq(queuedShares, 0); + assertEq(totalExitingAssets, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalTickets, 0); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.totalSupply(), _securityDeposit); assertEq(blocklistVault.symbol(), 'SW-GNO-1'); @@ -286,9 +299,9 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { uint256 totalSharesBefore = blocklistVault.totalShares(); uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); - uint256 queuedSharesBefore = blocklistVault.queuedShares(); uint256 senderBalanceBefore = blocklistVault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(blocklistVault)).queuedShares(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); assertEq(blocklistVault.version(), 2); @@ -301,6 +314,7 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoBlocklistErc20Vault, address(blocklistVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); assertEq(blocklistVault.version(), 3); assertEq(blocklistVault.admin(), admin); @@ -309,10 +323,10 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), queuedSharesBefore); + assertEq(queuedShares, queuedSharesBefore); assertEq(blocklistVault.totalShares(), totalSharesBefore); assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.getShares(sender), senderBalanceBefore); assertEq( diff --git a/test/gnosis/GnoBlocklistVault.t.sol b/test/gnosis/GnoBlocklistVault.t.sol index 382fd1f0..ad3f05fc 100644 --- a/test/gnosis/GnoBlocklistVault.t.sol +++ b/test/gnosis/GnoBlocklistVault.t.sol @@ -8,6 +8,11 @@ import {Errors} from '../../contracts/libraries/Errors.sol'; import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; import {GnoBlocklistVault} from '../../contracts/vaults/gnosis/GnoBlocklistVault.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoBlocklistVaultTest is Test, GnoHelpers { ForkContracts public contracts; GnoBlocklistVault public vault; @@ -168,6 +173,13 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { _stopSnapshotGas(); GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); assertEq(blocklistVault.version(), 3); assertEq(blocklistVault.admin(), admin); @@ -176,11 +188,13 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), 0); assertEq(blocklistVault.totalShares(), _securityDeposit); assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(blocklistVault.totalExitingAssets(), 0); assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -203,8 +217,8 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { uint256 totalSharesBefore = blocklistVault.totalShares(); uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = blocklistVault.totalExitingAssets(); - uint256 queuedSharesBefore = blocklistVault.queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(blocklistVault)).queuedShares(); uint256 senderBalanceBefore = blocklistVault.getShares(sender); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); @@ -218,6 +232,7 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoBlocklistVault, address(blocklistVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); assertEq(blocklistVault.version(), 3); assertEq(blocklistVault.admin(), admin); @@ -226,12 +241,12 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { assertEq(blocklistVault.feePercent(), 1000); assertEq(blocklistVault.feeRecipient(), admin); assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.queuedShares(), queuedSharesBefore); assertEq(blocklistVault.totalShares(), totalSharesBefore); assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(blocklistVault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); assertEq( contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), type(uint256).max diff --git a/test/gnosis/GnoErc20Vault.t.sol b/test/gnosis/GnoErc20Vault.t.sol index ffb19f84..a87b6bb2 100644 --- a/test/gnosis/GnoErc20Vault.t.sol +++ b/test/gnosis/GnoErc20Vault.t.sol @@ -11,6 +11,11 @@ import {Errors} from '../../contracts/libraries/Errors.sol'; import {GnoErc20Vault} from '../../contracts/vaults/gnosis/GnoErc20Vault.sol'; import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoErc20VaultTest is Test, GnoHelpers { ForkContracts public contracts; GnoErc20Vault public vault; @@ -72,6 +77,13 @@ contract GnoErc20VaultTest is Test, GnoHelpers { _stopSnapshotGas(); GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = erc20Vault.getExitQueueData(); + assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); assertEq(erc20Vault.version(), 3); assertEq(erc20Vault.admin(), admin); @@ -79,14 +91,16 @@ contract GnoErc20VaultTest is Test, GnoHelpers { assertEq(erc20Vault.feePercent(), 1000); assertEq(erc20Vault.feeRecipient(), admin); assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.queuedShares(), 0); assertEq(erc20Vault.totalShares(), _securityDeposit); assertEq(erc20Vault.totalAssets(), _securityDeposit); - assertEq(erc20Vault.totalExitingAssets(), 0); assertEq(erc20Vault.validatorsManagerNonce(), 0); assertEq(erc20Vault.totalSupply(), _securityDeposit); assertEq(erc20Vault.symbol(), 'SW-GNO-1'); assertEq(erc20Vault.name(), 'SW GNO Vault'); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -111,9 +125,9 @@ contract GnoErc20VaultTest is Test, GnoHelpers { uint256 totalSharesBefore = erc20Vault.totalShares(); uint256 totalAssetsBefore = erc20Vault.totalAssets(); - uint256 totalExitingAssetsBefore = erc20Vault.totalExitingAssets(); - uint256 queuedSharesBefore = erc20Vault.queuedShares(); uint256 senderBalanceBefore = erc20Vault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(erc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(erc20Vault)).queuedShares(); assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); assertEq(erc20Vault.version(), 2); @@ -126,6 +140,7 @@ contract GnoErc20VaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoErc20Vault, address(erc20Vault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); assertEq(erc20Vault.version(), 3); assertEq(erc20Vault.admin(), admin); @@ -133,10 +148,8 @@ contract GnoErc20VaultTest is Test, GnoHelpers { assertEq(erc20Vault.feePercent(), 1000); assertEq(erc20Vault.feeRecipient(), admin); assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.queuedShares(), queuedSharesBefore); assertEq(erc20Vault.totalShares(), totalSharesBefore); assertEq(erc20Vault.totalAssets(), totalAssetsBefore); - assertEq(erc20Vault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(erc20Vault.validatorsManagerNonce(), 0); assertEq(erc20Vault.getShares(sender), senderBalanceBefore); assertEq( @@ -146,6 +159,8 @@ contract GnoErc20VaultTest is Test, GnoHelpers { assertEq(erc20Vault.totalSupply(), totalSharesBefore); assertEq(erc20Vault.symbol(), 'SW-GNO-1'); assertEq(erc20Vault.name(), 'SW GNO Vault'); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); } function test_deposit_emitsTransfer() public { diff --git a/test/gnosis/GnoGenesisVault.t.sol b/test/gnosis/GnoGenesisVault.t.sol index 016bebab..ef6c6325 100644 --- a/test/gnosis/GnoGenesisVault.t.sol +++ b/test/gnosis/GnoGenesisVault.t.sol @@ -10,6 +10,11 @@ import {GnoGenesisVault} from '../../contracts/vaults/gnosis/GnoGenesisVault.sol import {Errors} from '../../contracts/libraries/Errors.sol'; import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +interface IVaultStateV3 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoGenesisVaultTest is Test, GnoHelpers { ForkContracts public contracts; address public admin; @@ -66,10 +71,10 @@ contract GnoGenesisVaultTest is Test, GnoHelpers { existingVault.enterExitQueue(10 ether, user); // Record initial state + uint256 totalExitingAssetsBefore = IVaultStateV3(address(existingVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV3(address(existingVault)).queuedShares(); uint256 initialTotalAssets = existingVault.totalAssets(); uint256 initialTotalShares = existingVault.totalShares(); - uint256 totalExitingAssetsBefore = existingVault.totalExitingAssets(); - uint256 queuedSharesBefore = existingVault.queuedShares(); uint256 senderBalanceBefore = existingVault.getShares(user); uint256 initialCapacity = existingVault.capacity(); uint256 initialFeePercent = existingVault.feePercent(); @@ -84,6 +89,7 @@ contract GnoGenesisVaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoGenesisVault, address(existingVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = existingVault.getExitQueueData(); assertEq(existingVault.vaultId(), keccak256('GnoGenesisVault')); assertEq(existingVault.version(), 4); assertEq(existingVault.admin(), adminBefore); @@ -91,10 +97,10 @@ contract GnoGenesisVaultTest is Test, GnoHelpers { assertEq(existingVault.feePercent(), initialFeePercent); assertEq(existingVault.feeRecipient(), feeRecipient); assertEq(existingVault.validatorsManager(), validatorsManager); - assertEq(existingVault.queuedShares(), queuedSharesBefore); + assertEq(queuedShares, queuedSharesBefore); assertEq(existingVault.totalShares(), initialTotalShares); assertEq(existingVault.totalAssets(), initialTotalAssets); - assertEq(existingVault.totalExitingAssets(), totalExitingAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); assertEq(existingVault.validatorsManagerNonce(), 0); assertEq(existingVault.getShares(user), senderBalanceBefore); assertEq( diff --git a/test/gnosis/GnoOsTokenVaultEscrow.t.sol b/test/gnosis/GnoOsTokenVaultEscrow.t.sol index 94caaccb..40068e90 100644 --- a/test/gnosis/GnoOsTokenVaultEscrow.t.sol +++ b/test/gnosis/GnoOsTokenVaultEscrow.t.sol @@ -93,10 +93,8 @@ contract GnoOsTokenVaultEscrowTest is Test, GnoHelpers { assertEq(escrowOsTokenShares, osTokenShares, 'Incorrect osToken shares in escrow'); IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - _mintGnoToken( - address(vault), - vault.totalExitingAssets() + vault.convertToAssets(vault.queuedShares()) - ); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + _mintGnoToken(address(vault), totalExitingAssets + vault.convertToAssets(queuedShares)); vault.updateState(harvestParams); vm.warp(timestamp + _exitingAssetsClaimDelay + 1); diff --git a/test/gnosis/GnoOwnMevEscrow.t.sol b/test/gnosis/GnoOwnMevEscrow.t.sol index 0637e5e0..2b82fa27 100644 --- a/test/gnosis/GnoOwnMevEscrow.t.sol +++ b/test/gnosis/GnoOwnMevEscrow.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; import {Test} from 'forge-std/Test.sol'; -import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; import {Errors} from '../../contracts/libraries/Errors.sol'; import {IOwnMevEscrow} from '../../contracts/interfaces/IOwnMevEscrow.sol'; diff --git a/test/gnosis/GnoPrivErc20Vault.t.sol b/test/gnosis/GnoPrivErc20Vault.t.sol index 36cf17b7..82aef29e 100644 --- a/test/gnosis/GnoPrivErc20Vault.t.sol +++ b/test/gnosis/GnoPrivErc20Vault.t.sol @@ -8,6 +8,11 @@ import {Errors} from '../../contracts/libraries/Errors.sol'; import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; import {GnoPrivErc20Vault} from '../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoPrivErc20VaultTest is Test, GnoHelpers { ForkContracts public contracts; GnoPrivErc20Vault public vault; @@ -263,6 +268,12 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { _stopSnapshotGas(); GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privErc20Vault.getExitQueueData(); assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); assertEq(privErc20Vault.version(), 3); assertEq(privErc20Vault.admin(), admin); @@ -271,14 +282,16 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { assertEq(privErc20Vault.feePercent(), 1000); assertEq(privErc20Vault.feeRecipient(), admin); assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.queuedShares(), 0); assertEq(privErc20Vault.totalShares(), _securityDeposit); assertEq(privErc20Vault.totalAssets(), _securityDeposit); - assertEq(privErc20Vault.totalExitingAssets(), 0); assertEq(privErc20Vault.validatorsManagerNonce(), 0); assertEq(privErc20Vault.totalSupply(), _securityDeposit); assertEq(privErc20Vault.symbol(), 'SW-GNO-1'); assertEq(privErc20Vault.name(), 'SW GNO Vault'); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -307,9 +320,9 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { uint256 totalSharesBefore = privErc20Vault.totalShares(); uint256 totalAssetsBefore = privErc20Vault.totalAssets(); - uint256 totalExitingAssetsBefore = privErc20Vault.totalExitingAssets(); - uint256 queuedSharesBefore = privErc20Vault.queuedShares(); uint256 senderBalanceBefore = privErc20Vault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(privErc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(privErc20Vault)).queuedShares(); assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); assertEq(privErc20Vault.version(), 2); @@ -322,6 +335,7 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoPrivErc20Vault, address(privErc20Vault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); assertEq(privErc20Vault.version(), 3); assertEq(privErc20Vault.admin(), admin); @@ -330,10 +344,8 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { assertEq(privErc20Vault.feePercent(), 1000); assertEq(privErc20Vault.feeRecipient(), admin); assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.queuedShares(), queuedSharesBefore); assertEq(privErc20Vault.totalShares(), totalSharesBefore); assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); - assertEq(privErc20Vault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(privErc20Vault.validatorsManagerNonce(), 0); assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); assertEq( @@ -343,6 +355,8 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { assertEq(privErc20Vault.totalSupply(), totalSharesBefore); assertEq(privErc20Vault.symbol(), 'SW-GNO-1'); assertEq(privErc20Vault.name(), 'SW GNO Vault'); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); } // Helper function to deposit GNO to the vault diff --git a/test/gnosis/GnoPrivVault.t.sol b/test/gnosis/GnoPrivVault.t.sol index 4284f28a..8f3a8f11 100644 --- a/test/gnosis/GnoPrivVault.t.sol +++ b/test/gnosis/GnoPrivVault.t.sol @@ -8,6 +8,11 @@ import {Errors} from '../../contracts/libraries/Errors.sol'; import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; import {GnoPrivVault} from '../../contracts/vaults/gnosis/GnoPrivVault.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoPrivVaultTest is Test, GnoHelpers { ForkContracts public contracts; GnoPrivVault public vault; @@ -220,6 +225,12 @@ contract GnoPrivVaultTest is Test, GnoHelpers { _stopSnapshotGas(); GnoPrivVault privVault = GnoPrivVault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privVault.getExitQueueData(); assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); assertEq(privVault.version(), 3); assertEq(privVault.admin(), admin); @@ -228,11 +239,13 @@ contract GnoPrivVaultTest is Test, GnoHelpers { assertEq(privVault.feePercent(), 1000); assertEq(privVault.feeRecipient(), admin); assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.queuedShares(), 0); assertEq(privVault.totalShares(), _securityDeposit); assertEq(privVault.totalAssets(), _securityDeposit); - assertEq(privVault.totalExitingAssets(), 0); assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -263,10 +276,10 @@ contract GnoPrivVaultTest is Test, GnoHelpers { uint256 totalSharesBefore = privVault.totalShares(); uint256 totalAssetsBefore = privVault.totalAssets(); - uint256 totalExitingAssetsBefore = privVault.totalExitingAssets(); - uint256 queuedSharesBefore = privVault.queuedShares(); uint256 senderBalanceBefore = privVault.getShares(sender); bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(privVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(privVault)).queuedShares(); assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); assertEq(privVault.version(), 2); @@ -279,6 +292,7 @@ contract GnoPrivVaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoPrivVault, address(privVault)); _stopSnapshotGas(); + (uint128 queuedShares, , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); assertEq(privVault.version(), 3); assertEq(privVault.admin(), admin); @@ -287,10 +301,8 @@ contract GnoPrivVaultTest is Test, GnoHelpers { assertEq(privVault.feePercent(), 1000); assertEq(privVault.feeRecipient(), admin); assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.queuedShares(), queuedSharesBefore); assertEq(privVault.totalShares(), totalSharesBefore); assertEq(privVault.totalAssets(), totalAssetsBefore); - assertEq(privVault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(privVault.validatorsManagerNonce(), 0); assertEq(privVault.getShares(sender), senderBalanceBefore); assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); @@ -298,6 +310,8 @@ contract GnoPrivVaultTest is Test, GnoHelpers { contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), type(uint256).max ); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); } function test_setWhitelister() public { diff --git a/test/gnosis/GnoRewardSplitter.t.sol b/test/gnosis/GnoRewardSplitter.t.sol index b3e969aa..493b5d0c 100644 --- a/test/gnosis/GnoRewardSplitter.t.sol +++ b/test/gnosis/GnoRewardSplitter.t.sol @@ -173,7 +173,11 @@ contract GnoRewardSplitterTest is Test, GnoHelpers { _stopSnapshotGas(); // Verify shareholder2 received vault tokens - assertGt(IVaultState(vault).getShares(shareholder2), 0, 'Shareholder2 should receive vault tokens directly'); + assertGt( + IVaultState(vault).getShares(shareholder2), + 0, + 'Shareholder2 should receive vault tokens directly' + ); } function test_maxWithdrawal() public { @@ -431,8 +435,16 @@ contract GnoRewardSplitterTest is Test, GnoHelpers { uint256 newSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); uint256 newTotalShares = rewardSplitter.totalShares(); - assertEq(newSharesShareholder1, initialSharesShareholder1 + increaseAmount, "Shares should be increased correctly"); - assertEq(newTotalShares, initialTotalShares + increaseAmount, "Total shares should be increased correctly"); + assertEq( + newSharesShareholder1, + initialSharesShareholder1 + increaseAmount, + 'Shares should be increased correctly' + ); + assertEq( + newTotalShares, + initialTotalShares + increaseAmount, + 'Total shares should be increased correctly' + ); // Test decrease shares vm.prank(admin); @@ -444,8 +456,16 @@ contract GnoRewardSplitterTest is Test, GnoHelpers { uint256 finalSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); uint256 finalTotalShares = rewardSplitter.totalShares(); - assertEq(finalSharesShareholder1, initialSharesShareholder1, "Shares should be decreased back to original amount"); - assertEq(finalTotalShares, initialTotalShares, "Total shares should be decreased back to original amount"); + assertEq( + finalSharesShareholder1, + initialSharesShareholder1, + 'Shares should be decreased back to original amount' + ); + assertEq( + finalTotalShares, + initialTotalShares, + 'Total shares should be decreased back to original amount' + ); } function test_syncRewards() public { diff --git a/test/gnosis/GnoSharedMevEscrow.t.sol b/test/gnosis/GnoSharedMevEscrow.t.sol index 29dc23d7..ad2aeee3 100644 --- a/test/gnosis/GnoSharedMevEscrow.t.sol +++ b/test/gnosis/GnoSharedMevEscrow.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; import {Test} from 'forge-std/Test.sol'; -import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; import {Errors} from '../../contracts/libraries/Errors.sol'; import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; diff --git a/test/gnosis/GnoVault.t.sol b/test/gnosis/GnoVault.t.sol index 1c8efca4..ae2ed1d4 100644 --- a/test/gnosis/GnoVault.t.sol +++ b/test/gnosis/GnoVault.t.sol @@ -2,16 +2,19 @@ pragma solidity ^0.8.22; import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; import {Errors} from '../../contracts/libraries/Errors.sol'; import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoVaultTest is Test, GnoHelpers { ForkContracts public contracts; GnoVault public vault; @@ -77,6 +80,12 @@ contract GnoVaultTest is Test, GnoHelpers { GnoVault newVault = GnoVault(payable(vaultAddr)); // Verify the vault was deployed correctly + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = newVault.getExitQueueData(); assertEq(newVault.vaultId(), keccak256('GnoVault')); assertEq(newVault.version(), 3); assertEq(newVault.admin(), admin); @@ -84,11 +93,13 @@ contract GnoVaultTest is Test, GnoHelpers { assertEq(newVault.feePercent(), 1000); assertEq(newVault.feeRecipient(), admin); assertEq(newVault.validatorsManager(), _depositDataRegistry); - assertEq(newVault.queuedShares(), 0); assertEq(newVault.totalShares(), _securityDeposit); assertEq(newVault.totalAssets(), _securityDeposit); - assertEq(newVault.totalExitingAssets(), 0); assertEq(newVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); } function test_upgradesCorrectly() public { @@ -116,8 +127,8 @@ contract GnoVaultTest is Test, GnoHelpers { // Record state before upgrade uint256 totalSharesBefore = prevVault.totalShares(); uint256 totalAssetsBefore = prevVault.totalAssets(); - uint256 totalExitingAssetsBefore = prevVault.totalExitingAssets(); - uint256 queuedSharesBefore = prevVault.queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(prevVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(prevVault)).queuedShares(); uint256 senderBalanceBefore = prevVault.getShares(sender); // Verify current version @@ -136,6 +147,7 @@ contract GnoVaultTest is Test, GnoHelpers { _stopSnapshotGas(); // Check that the vault was upgraded correctly + (uint128 queuedShares, , uint128 totalExitingAssets, ) = prevVault.getExitQueueData(); assertEq(prevVault.vaultId(), keccak256('GnoVault')); assertEq(prevVault.version(), 3); assertEq(prevVault.admin(), admin); @@ -145,12 +157,12 @@ contract GnoVaultTest is Test, GnoHelpers { assertEq(prevVault.validatorsManager(), _depositDataRegistry); // State should be preserved - assertEq(prevVault.queuedShares(), queuedSharesBefore); assertEq(prevVault.totalShares(), totalSharesBefore); assertEq(prevVault.totalAssets(), totalAssetsBefore); - assertEq(prevVault.totalExitingAssets(), totalExitingAssetsBefore); assertEq(prevVault.validatorsManagerNonce(), 0); assertEq(prevVault.getShares(sender), senderBalanceBefore); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); // Allowance should be set after upgrade assertEq( @@ -169,7 +181,12 @@ contract GnoVaultTest is Test, GnoHelpers { // Get initial state uint256 senderSharesBefore = vault.getShares(sender); - uint256 queuedSharesBefore = vault.queuedShares(); + ( + uint128 queuedSharesBefore, + uint128 unclaimedAssetsBefore, + uint128 totalExitingAssetsBefore, + uint256 totalTicketsBefore + ) = vault.getExitQueueData(); // Amount to exit with uint256 exitAmount = senderSharesBefore / 2; @@ -181,19 +198,61 @@ contract GnoVaultTest is Test, GnoHelpers { uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); _stopSnapshotGas(); + ( + uint128 queuedSharesAfter, + uint128 unclaimedAssetsAfter, + uint128 totalExitingAssetsAfter, + uint256 totalTicketsAfter + ) = vault.getExitQueueData(); + // Check state after entering exit queue assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, 'Sender shares not reduced'); - assertEq(vault.queuedShares(), queuedSharesBefore + exitAmount, 'Queued shares not increased'); + assertEq(queuedSharesAfter, queuedSharesBefore + exitAmount, 'Queued shares not increased'); + assertEq(unclaimedAssetsAfter, unclaimedAssetsBefore, 'Unclaimed assets should not change'); + assertEq( + totalExitingAssetsAfter, + totalExitingAssetsBefore, + 'Total exiting assets should not change' + ); + assertEq(totalTicketsAfter, totalTicketsBefore, 'Total tickets should not change'); + + queuedSharesBefore = queuedSharesAfter; + unclaimedAssetsBefore = unclaimedAssetsAfter; + totalExitingAssetsBefore = totalExitingAssetsAfter; + totalTicketsBefore = totalTicketsAfter; _mintGnoToken( address(vault), - vault.totalExitingAssets() + vault.convertToAssets(vault.queuedShares()) + totalExitingAssetsAfter + vault.convertToAssets(queuedSharesAfter) ); // Process exit queue by updating state IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); vault.updateState(harvestParams); + (queuedSharesAfter, unclaimedAssetsAfter, totalExitingAssetsAfter, totalTicketsAfter) = vault + .getExitQueueData(); + assertLt( + queuedSharesAfter, + queuedSharesBefore, + 'Queued shares should be reduced after processing exit queue' + ); + assertGt( + unclaimedAssetsAfter, + unclaimedAssetsBefore, + 'Unclaimed assets should increase after processing exit queue' + ); + assertLe( + totalExitingAssetsAfter, + totalExitingAssetsBefore, + 'Total exiting assets should not change after processing exit queue' + ); + assertGt( + totalTicketsAfter, + totalTicketsBefore, + 'Total tickets should increase after processing exit queue' + ); + // Check that position can be found in exit queue int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); assertGt(exitQueueIndex, -1, 'Exit queue index not found'); diff --git a/test/gnosis/GnoVaultExitQueue.t.sol b/test/gnosis/GnoVaultExitQueue.t.sol index 13831b8b..5c036cbd 100644 --- a/test/gnosis/GnoVaultExitQueue.t.sol +++ b/test/gnosis/GnoVaultExitQueue.t.sol @@ -8,6 +8,11 @@ import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; +interface IVaultStateV2 { + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); +} + contract GnoVaultExitQueueTest is Test, GnoHelpers { ForkContracts public contracts; GnoVault public vault; @@ -92,7 +97,7 @@ contract GnoVaultExitQueueTest is Test, GnoHelpers { // Step 2: Add 3 exit requests to the vault uint256 exitShares = vault.convertToShares(exitAmount); - uint256 totalExitingAssetsBefore = vault.totalExitingAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(vault)).totalExitingAssets(); timestamp1 = vm.getBlockTimestamp(); vm.prank(user1); @@ -108,7 +113,7 @@ contract GnoVaultExitQueueTest is Test, GnoHelpers { // Verify exit requests are in the queue assertEq( - vault.totalExitingAssets(), + IVaultStateV2(address(vault)).totalExitingAssets(), totalExitingAssetsBefore + exitAmount * 3, 'Exit requests not added to queue' ); @@ -287,15 +292,16 @@ contract GnoVaultExitQueueTest is Test, GnoHelpers { vm.prank(user1); vault.enterExitQueue(exitAmount, user1); - uint256 totalExitingAssetsBefore = vault.totalExitingAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(vault)).totalExitingAssets(); // Upgrade the vault to v3 _upgradeVault(VaultType.GnoVault, vaultAddr); // Calculate what the penalty should be + (, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); int256 penalty = -1 ether; // 1 GNO worth of penalty - uint256 expectedPenalty = (uint256(-penalty) * uint256(vault.totalExitingAssets())) / - (uint256(vault.totalExitingAssets()) + uint256(vault.totalAssets())); + uint256 expectedPenalty = (uint256(-penalty) * uint256(totalExitingAssets)) / + (uint256(totalExitingAssets) + uint256(vault.totalAssets())); // Set a negative reward (penalty) and update the vault state IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( @@ -313,8 +319,9 @@ contract GnoVaultExitQueueTest is Test, GnoHelpers { _stopSnapshotGas(); // Verify the exiting assets were penalized + (, , totalExitingAssets, ) = vault.getExitQueueData(); assertLt( - vault.totalExitingAssets(), + totalExitingAssets, totalExitingAssetsBefore + exitAmount, 'Exiting assets should be reduced by the penalty' ); diff --git a/test/gnosis/VaultGnoStaking.t.sol b/test/gnosis/VaultGnoStaking.t.sol index b2780b22..f6329982 100644 --- a/test/gnosis/VaultGnoStaking.t.sol +++ b/test/gnosis/VaultGnoStaking.t.sol @@ -189,8 +189,11 @@ contract VaultGnoStakingTest is Test, GnoHelpers { function test_vaultAssets() public { // Initial check uint256 initialAssets = vault.totalAssets(); - uint256 senderDeposit = vault.convertToAssets(vault.queuedShares()) + - vault.totalExitingAssets() + + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + .getExitQueueData(); + uint256 senderDeposit = vault.convertToAssets(queuedShares) + + totalExitingAssets + + unclaimedAssets + 1 ether; // Deposit GNO @@ -455,7 +458,7 @@ contract VaultGnoStakingTest is Test, GnoHelpers { // Check for ValidatorFunded event vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + emit IVaultValidators.ValidatorFunded(publicKey, 32 ether); vm.prank(validatorsManager); _startSnapshotGas('VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid'); @@ -490,8 +493,11 @@ contract VaultGnoStakingTest is Test, GnoHelpers { _collateralizeGnoVault(address(vault)); // Deposit GNO to the vault - uint256 senderDeposit = vault.convertToAssets(vault.queuedShares()) + - vault.totalExitingAssets() + + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + .getExitQueueData(); + uint256 senderDeposit = vault.convertToAssets(queuedShares) + + totalExitingAssets + + unclaimedAssets + depositAmount; _mintGnoToken(sender, senderDeposit); _depositGno(senderDeposit, sender, sender); From fd24677980231509024476bc1666b3d84c38cf66 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Sun, 13 Apr 2025 14:32:17 +0300 Subject: [PATCH 08/15] Validators checker exit queue (#108) * Fix validators manager signature * Fix github action * Update foundry file * Remove helpers * Remove tsconfig * Remove tasks * Remove snapshots * Add remappings.txt * Update ignore files * Add .env.example * Add UpgradeEthNetwork script * remove libs * forge install: forge-std v1.9.5 * forge install: openzeppelin-contracts-upgradeable v5.2.0 * Add exit queue state function to ValidatorsChecker * Fix tests * Extend EthValidatorsChecker tests * Extend GnoValidatorsChecker tests * Fix GnoValidatorsCheckerTest test * fix .gitignore * Split getExitQueueState into two functions * Fix ValidatorsChecker tests --- .env.example | 6 +- .github/workflows/coverage.yaml | 2 +- .github/workflows/test-fork.yaml | 1 + .github/workflows/test.yaml | 1 + .gitignore | 50 +-- .prettierignore | 12 +- contracts/interfaces/IValidatorsChecker.sol | 35 +- contracts/interfaces/IVaultEthStaking.sol | 3 +- contracts/interfaces/IVaultState.sol | 2 + contracts/libraries/OsTokenUtils.sol | 24 +- contracts/libraries/ValidatorUtils.sol | 4 +- contracts/validators/EthValidatorsChecker.sol | 5 + contracts/validators/GnoValidatorsChecker.sol | 16 +- contracts/validators/ValidatorsChecker.sol | 78 +++- contracts/vaults/modules/VaultState.sol | 6 +- foundry.toml | 17 +- helpers/constants.ts | 402 ------------------ helpers/types.ts | 85 ---- helpers/utils.ts | 86 ---- lib/openzeppelin-foundry-upgrades | 1 - remappings.txt | 2 + script/Network.sol | 172 ++++++++ script/UpgradeEthNetwork.s.sol | 176 ++++++++ snapshots/DepositDataRegistryTest.json | 9 - snapshots/GnoBlocklistErc20VaultTest.json | 7 - snapshots/GnoBlocklistVaultTest.json | 6 - snapshots/GnoErc20VaultTest.json | 12 - snapshots/GnoGenesisVaultTest.json | 5 - snapshots/GnoOsTokenVaultEscrowTest.json | 5 - snapshots/GnoOwnMevEscrowTest.json | 3 - snapshots/GnoPrivErc20VaultTest.json | 7 - snapshots/GnoPrivVaultTest.json | 8 - snapshots/GnoSharedMevEscrowTest.json | 3 - snapshots/GnoVaultTest.json | 8 - snapshots/VaultGnoStakingTest.json | 14 - tasks/eth-full-deploy-local.ts | 345 --------------- tasks/eth-full-deploy.ts | 388 ----------------- tasks/eth-upgrade.ts | 182 -------- tasks/gno-full-deploy.ts | 382 ----------------- tasks/gno-upgrade.ts | 247 ----------- test/DepositDataRegistry.t.sol | 2 +- test/EthBlocklistErc20Vault.t.sol | 4 +- test/EthBlocklistVault.t.sol | 4 +- test/EthErc20Vault.t.sol | 6 +- test/EthFoxVault.t.sol | 10 +- test/EthGenesisVault.t.sol | 6 +- test/EthOsTokenVaultEscrow.t.sol | 2 +- test/EthPrivErc20Vault.t.sol | 4 +- test/EthPrivVault.t.sol | 4 +- test/EthValidatorsChecker.t.sol | 187 +++++++- test/EthVault.t.sol | 10 +- test/VaultEnterExit.t.sol | 14 +- test/VaultEthStaking.t.sol | 2 +- test/VaultState.t.sol | 8 +- test/VaultToken.t.sol | 2 +- test/VaultValidators.t.sol | 2 +- test/gnosis/GnoBlocklistErc20Vault.t.sol | 4 +- test/gnosis/GnoBlocklistVault.t.sol | 4 +- test/gnosis/GnoErc20Vault.t.sol | 4 +- test/gnosis/GnoGenesisVault.t.sol | 2 +- test/gnosis/GnoOsTokenVaultEscrow.t.sol | 2 +- test/gnosis/GnoPrivErc20Vault.t.sol | 4 +- test/gnosis/GnoPrivVault.t.sol | 4 +- test/gnosis/GnoValidatorsChecker.t.sol | 133 ++++++ test/gnosis/GnoVault.t.sol | 8 +- test/gnosis/GnoVaultExitQueue.t.sol | 4 +- test/gnosis/VaultGnoStaking.t.sol | 4 +- tsconfig.json | 13 - 68 files changed, 924 insertions(+), 2346 deletions(-) delete mode 100644 helpers/constants.ts delete mode 100644 helpers/types.ts delete mode 100644 helpers/utils.ts delete mode 160000 lib/openzeppelin-foundry-upgrades create mode 100644 remappings.txt create mode 100644 script/Network.sol create mode 100644 script/UpgradeEthNetwork.s.sol delete mode 100644 snapshots/DepositDataRegistryTest.json delete mode 100644 snapshots/GnoBlocklistErc20VaultTest.json delete mode 100644 snapshots/GnoBlocklistVaultTest.json delete mode 100644 snapshots/GnoErc20VaultTest.json delete mode 100644 snapshots/GnoGenesisVaultTest.json delete mode 100644 snapshots/GnoOsTokenVaultEscrowTest.json delete mode 100644 snapshots/GnoOwnMevEscrowTest.json delete mode 100644 snapshots/GnoPrivErc20VaultTest.json delete mode 100644 snapshots/GnoPrivVaultTest.json delete mode 100644 snapshots/GnoSharedMevEscrowTest.json delete mode 100644 snapshots/GnoVaultTest.json delete mode 100644 snapshots/VaultGnoStakingTest.json delete mode 100644 tasks/eth-full-deploy-local.ts delete mode 100644 tasks/eth-full-deploy.ts delete mode 100644 tasks/eth-upgrade.ts delete mode 100644 tasks/gno-full-deploy.ts delete mode 100644 tasks/gno-upgrade.ts create mode 100644 test/gnosis/GnoValidatorsChecker.t.sol delete mode 100644 tsconfig.json diff --git a/.env.example b/.env.example index 968f3f0e..0de3d705 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,3 @@ -NETWORK_RPC_URL=http://localhost:8545 -MNEMONIC=optional deployer mnemonic goes here -BLOCK_EXPLORER_KEY=optional etherscan key for verifying contracts \ No newline at end of file +MAINNET_RPC_URL=http://localhost:8545 +GNOSIS_RPC_URL=http://localhost:8546 +USE_FORK_VAULTS=false diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 57dbb3a4..f2eba612 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -34,7 +34,7 @@ jobs: echo 'COVERAGE</dev/null | + forge coverage --skip script --no-match-coverage "(keeper|mocks|test|script|tokens|VaultsRegistry|DepositDataRegistry)" 2>/dev/null | grep '^|' | grep -v 'test/' | grep -v '^|--' | diff --git a/.github/workflows/test-fork.yaml b/.github/workflows/test-fork.yaml index 05c7fc54..a47c81cd 100644 --- a/.github/workflows/test-fork.yaml +++ b/.github/workflows/test-fork.yaml @@ -30,3 +30,4 @@ jobs: FORGE_SNAPSHOT_CHECK: false USE_FORK_VAULTS: true MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + FOUNDRY_PROFILE: test diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a9009a56..cb7bdf36 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,3 +30,4 @@ jobs: FORGE_SNAPSHOT_CHECK: true USE_FORK_VAULTS: false MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + FOUNDRY_PROFILE: test \ No newline at end of file diff --git a/.gitignore b/.gitignore index a7c2ed61..7a3eff0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1,13 @@ -*.swp -*.swo - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed - -# Dependency directory -node_modules - -# Debug log from npm -npm-debug.log - -# Local env variables -.env - -# Hardhat -cache -/artifacts - -# Typechain -/typechain-types +# if you add a file here, add it to `.npmignore` too +artifacts/ +cache/ +node_modules/ +typechain/ +coverage/ +foundry-out/ +.vscode/ +out/ +lcov.info # macOS .DS_Store @@ -34,15 +17,4 @@ cache # VS Code .vscode -*.code-workspace - -# Coverage -coverage -coverage.json - -addresses.json -/.openzeppelin/unknown-31337.json -/deployments/local.json - -# Python -.python-version +.env \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 4725ed22..a3b978a2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,8 @@ -artifacts -cache -node_modules -typechain-types +.prettierrc +foundry.toml +out +lib/ +cache/ +*.sol +dist/ +snapshots/ \ No newline at end of file diff --git a/contracts/interfaces/IValidatorsChecker.sol b/contracts/interfaces/IValidatorsChecker.sol index 46b22dff..5585fdc2 100644 --- a/contracts/interfaces/IValidatorsChecker.sol +++ b/contracts/interfaces/IValidatorsChecker.sol @@ -2,12 +2,15 @@ pragma solidity ^0.8.22; +import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; +import {IMulticall} from './IMulticall.sol'; + /** * @title IValidatorsChecker * @author StakeWise * @notice Defines the interface for ValidatorsChecker */ -interface IValidatorsChecker { +interface IValidatorsChecker is IMulticall { enum Status { SUCCEEDED, INVALID_VALIDATORS_REGISTRY_ROOT, @@ -38,6 +41,36 @@ interface IValidatorsChecker { uint256[] proofIndexes; } + /** + * @notice Function for updating vault state + * @param vault The address of the vault + * @param harvestParams The parameters for harvesting + */ + function updateVaultState( + address vault, + IKeeperRewards.HarvestParams calldata harvestParams + ) external; + + /** + * @notice Function for getting the exit queue cumulative tickets + * @param vault The address of the vault + * @return The exit queue cumulative tickets + */ + function getExitQueueCumulativeTickets(address vault) external view returns (uint256); + + /** + * @notice Function for getting the exit queue missing assets + * @param vault The address of the vault + * @param withdrawingAssets The amount of assets currently being withdrawn from validators + * @param targetCumulativeTickets The target cumulative tickets + * @return missingAssets The exit queue missing assets + */ + function getExitQueueMissingAssets( + address vault, + uint256 withdrawingAssets, + uint256 targetCumulativeTickets + ) external view returns (uint256 missingAssets); + /** * @notice Function for checking validators manager signature * @param vault The address of the vault diff --git a/contracts/interfaces/IVaultEthStaking.sol b/contracts/interfaces/IVaultEthStaking.sol index 7202b5ca..07361e45 100644 --- a/contracts/interfaces/IVaultEthStaking.sol +++ b/contracts/interfaces/IVaultEthStaking.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.22; +import {IVaultState} from './IVaultState.sol'; import {IVaultValidators} from './IVaultValidators.sol'; import {IVaultEnterExit} from './IVaultEnterExit.sol'; import {IKeeperRewards} from './IKeeperRewards.sol'; @@ -12,7 +13,7 @@ import {IVaultMev} from './IVaultMev.sol'; * @author StakeWise * @notice Defines the interface for the VaultEthStaking contract */ -interface IVaultEthStaking is IVaultValidators, IVaultEnterExit, IVaultMev { +interface IVaultEthStaking is IVaultState, IVaultValidators, IVaultEnterExit, IVaultMev { /** * @notice Deposit ETH to the Vault * @param receiver The address that will receive Vault's shares diff --git a/contracts/interfaces/IVaultState.sol b/contracts/interfaces/IVaultState.sol index 87495e63..91cd6383 100644 --- a/contracts/interfaces/IVaultState.sol +++ b/contracts/interfaces/IVaultState.sol @@ -60,6 +60,7 @@ interface IVaultState is IVaultFee { * @notice Get exit queue data * @return queuedShares The number of shares in the exit queue * @return unclaimedAssets The amount of unclaimed assets in the exit queue + * @return totalExitingTickets The total number of exiting tickets * @return totalExitingAssets The total amount of exiting assets * @return totalTickets The total number of tickets in the exit queue */ @@ -69,6 +70,7 @@ interface IVaultState is IVaultFee { returns ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ); diff --git a/contracts/libraries/OsTokenUtils.sol b/contracts/libraries/OsTokenUtils.sol index dde7ec18..fa4dbe0b 100644 --- a/contracts/libraries/OsTokenUtils.sol +++ b/contracts/libraries/OsTokenUtils.sol @@ -69,17 +69,19 @@ library OsTokenUtils { revert Errors.InvalidReceivedAssets(); } - if (data.isLiquidation) { - // check health factor violation in case of liquidation - if ( - Math.mulDiv( - data.depositedAssets * _wad, - config.liqThresholdPercent, - data.mintedAssets * _maxPercent - ) >= _hfLiqThreshold - ) { - revert Errors.InvalidHealthFactor(); - } + if (!data.isLiquidation) { + return receivedAssets; + } + + // check health factor violation in case of liquidation + if ( + Math.mulDiv( + data.depositedAssets * _wad, + config.liqThresholdPercent, + data.mintedAssets * _maxPercent + ) >= _hfLiqThreshold + ) { + revert Errors.InvalidHealthFactor(); } } } diff --git a/contracts/libraries/ValidatorUtils.sol b/contracts/libraries/ValidatorUtils.sol index 1c56dee9..90c615af 100644 --- a/contracts/libraries/ValidatorUtils.sol +++ b/contracts/libraries/ValidatorUtils.sol @@ -5,8 +5,8 @@ pragma solidity ^0.8.22; import {Address} from '@openzeppelin/contracts/utils/Address.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; -import {Errors} from './Errors.sol'; import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; +import {Errors} from './Errors.sol'; /** * @title ValidatorUtils @@ -15,7 +15,7 @@ import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; */ library ValidatorUtils { bytes32 private constant _validatorsManagerTypeHash = - keccak256('VaultValidators(bytes32 nonce,bytes validators)'); + keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'); uint256 private constant _validatorV1DepositLength = 176; uint256 private constant _validatorV2DepositLength = 184; uint256 private constant _validatorWithdrawalLength = 56; diff --git a/contracts/validators/EthValidatorsChecker.sol b/contracts/validators/EthValidatorsChecker.sol index 56bcbedc..32d0a210 100644 --- a/contracts/validators/EthValidatorsChecker.sol +++ b/contracts/validators/EthValidatorsChecker.sol @@ -28,4 +28,9 @@ contract EthValidatorsChecker is ValidatorsChecker { function _depositAmount() internal pure override returns (uint256) { return 32 ether; } + + /// @inheritdoc ValidatorsChecker + function _vaultAssets(address vault) internal view override returns (uint256) { + return address(vault).balance; + } } diff --git a/contracts/validators/GnoValidatorsChecker.sol b/contracts/validators/GnoValidatorsChecker.sol index 9d583f79..530a5da3 100644 --- a/contracts/validators/GnoValidatorsChecker.sol +++ b/contracts/validators/GnoValidatorsChecker.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.22; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {ValidatorsChecker} from './ValidatorsChecker.sol'; /** @@ -10,22 +11,33 @@ import {ValidatorsChecker} from './ValidatorsChecker.sol'; * @notice Defines functionality for checking validators registration on Gnosis */ contract GnoValidatorsChecker is ValidatorsChecker { + address private immutable _gnoToken; + /** * @dev Constructor * @param validatorsRegistry The address of the beacon chain validators registry contract * @param keeper The address of the Keeper contract * @param vaultsRegistry The address of the VaultsRegistry contract * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param gnoToken The address of the Gnosis token contract */ constructor( address validatorsRegistry, address keeper, address vaultsRegistry, - address depositDataRegistry - ) ValidatorsChecker(validatorsRegistry, keeper, vaultsRegistry, depositDataRegistry) {} + address depositDataRegistry, + address gnoToken + ) ValidatorsChecker(validatorsRegistry, keeper, vaultsRegistry, depositDataRegistry) { + _gnoToken = gnoToken; + } /// @inheritdoc ValidatorsChecker function _depositAmount() internal pure override returns (uint256) { return 1 ether; } + + /// @inheritdoc ValidatorsChecker + function _vaultAssets(address vault) internal view override returns (uint256) { + return IERC20(_gnoToken).balanceOf(vault); + } } diff --git a/contracts/validators/ValidatorsChecker.sol b/contracts/validators/ValidatorsChecker.sol index a078f9b7..1e728a09 100644 --- a/contracts/validators/ValidatorsChecker.sol +++ b/contracts/validators/ValidatorsChecker.sol @@ -2,17 +2,20 @@ pragma solidity ^0.8.22; +import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; +import {IDepositDataRegistry} from '../interfaces/IDepositDataRegistry.sol'; import {IKeeper} from '../interfaces/IKeeper.sol'; +import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; import {IValidatorsChecker} from '../interfaces/IValidatorsChecker.sol'; +import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; import {IVaultState} from '../interfaces/IVaultState.sol'; +import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; import {IVaultVersion} from '../interfaces/IVaultVersion.sol'; -import {IDepositDataRegistry} from '../interfaces/IDepositDataRegistry.sol'; import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; import {EIP712Utils} from '../libraries/EIP712Utils.sol'; import {ValidatorUtils} from '../libraries/ValidatorUtils.sol'; +import {Multicall} from '../base/Multicall.sol'; interface IVaultValidatorsV1 { function validatorsRoot() external view returns (bytes32); @@ -26,7 +29,7 @@ interface IVaultValidatorsV1 { * * checking validators manager signature * * checking deposit data root */ -abstract contract ValidatorsChecker is IValidatorsChecker { +abstract contract ValidatorsChecker is Multicall, IValidatorsChecker { IValidatorsRegistry private immutable _validatorsRegistry; IKeeper private immutable _keeper; IVaultsRegistry private immutable _vaultsRegistry; @@ -51,6 +54,66 @@ abstract contract ValidatorsChecker is IValidatorsChecker { _depositDataRegistry = IDepositDataRegistry(depositDataRegistry); } + /// @inheritdoc IValidatorsChecker + function updateVaultState( + address vault, + IKeeperRewards.HarvestParams calldata harvestParams + ) external override { + IVaultState(vault).updateState(harvestParams); + } + + /// @inheritdoc IValidatorsChecker + function getExitQueueCumulativeTickets(address vault) external view override returns (uint256) { + ( + uint128 queuedShares, + , + uint128 totalExitingTickets, + , + uint256 totalTickets + ) = IVaultValidators(vault).getExitQueueData(); + return totalTickets + queuedShares + totalExitingTickets; + } + + /// @inheritdoc IValidatorsChecker + function getExitQueueMissingAssets( + address vault, + uint256 withdrawingAssets, + uint256 targetCumulativeTickets + ) external view override returns (uint256 missingAssets) { + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = IVaultValidators(vault).getExitQueueData(); + // check whether already covered + if (totalTickets >= targetCumulativeTickets) { + return 0; + } + + // calculate the amount of tickets that need to be covered + uint256 totalTicketsToCover = targetCumulativeTickets - totalTickets; + + // calculate missing assets from legacy exits + uint256 ticketsToCover; + if (totalExitingTickets > 0) { + ticketsToCover = Math.min(totalTicketsToCover, totalExitingTickets); + missingAssets = Math.mulDiv(ticketsToCover, totalExitingAssets, totalExitingTickets); + totalTicketsToCover -= ticketsToCover; + } + + // calculate missing assets from queued shares + if (totalTicketsToCover > 0 && queuedShares > 0) { + ticketsToCover = Math.min(totalTicketsToCover, queuedShares); + missingAssets += IVaultState(vault).convertToAssets(ticketsToCover); + } + + // check whether there is enough available assets + uint256 availableAssets = withdrawingAssets + _vaultAssets(vault) - unclaimedAssets; + return availableAssets >= missingAssets ? 0 : missingAssets - availableAssets; + } + /// @inheritdoc IValidatorsChecker function checkValidatorsManagerSignature( address vault, @@ -188,4 +251,11 @@ abstract contract ValidatorsChecker is IValidatorsChecker { * @return The amount of assets required for deposit */ function _depositAmount() internal pure virtual returns (uint256); + + /** + * @notice Get the amount of assets in the vault + * @param vault The address of the vault + * @return The amount of assets in the vault + */ + function _vaultAssets(address vault) internal view virtual returns (uint256); } diff --git a/contracts/vaults/modules/VaultState.sol b/contracts/vaults/modules/VaultState.sol index 759803dd..6c11be9a 100644 --- a/contracts/vaults/modules/VaultState.sol +++ b/contracts/vaults/modules/VaultState.sol @@ -54,6 +54,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault returns ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) @@ -61,8 +62,9 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault return ( _queuedShares, _unclaimedAssets, + _totalExitingTickets, _totalExitingAssets, - ExitQueue.getLatestTotalTickets(_exitQueue) + _exitQueue.getLatestTotalTickets() ); } @@ -216,7 +218,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault if (availableAssets < totalExitingAssets) return 0; // SLOAD to memory - uint256 totalExitingTickets = totalExitingAssets; + uint256 totalExitingTickets = _totalExitingTickets; // push checkpoint so that exited assets could be claimed _exitQueue.push(totalExitingTickets, totalExitingAssets); diff --git a/foundry.toml b/foundry.toml index decb1c80..d7a0f23b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,15 +1,12 @@ [profile.default] src = 'contracts' -out = 'out' -libs = ['node_modules', 'lib'] -test = 'test' -cache_path = 'cache_forge' -via_ir = false -solc = "0.8.22" +solc = "0.8.26" evm_version = "cancun" optimizer = true -optimizer_runs = 1000 +optimizer_runs = 200 +via_ir = true ffi = true -ast = true -build_info = true -extra_output = ["storageLayout"] +bytecode_hash = 'none' + +[profile.test] +via_ir = false diff --git a/helpers/constants.ts b/helpers/constants.ts deleted file mode 100644 index b4f1afc0..00000000 --- a/helpers/constants.ts +++ /dev/null @@ -1,402 +0,0 @@ -import { NetworkConfig, Networks } from './types' -import { parseEther } from 'ethers' -import { MAX_UINT128, MAX_UINT256 } from '../test/shared/constants' - -export const NETWORKS: { - [network in Networks]: NetworkConfig -} = { - [Networks.hoodi]: { - url: process.env.HOODI_RPC_URL || '', - chainId: 560048, - - governor: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - validatorsRegistry: '0x00000000219ab540356cBB839Cbe05303d7705Fa', - securityDeposit: 1000000000n, // 1 gwei - exitedAssetsClaimDelay: 24 * 60 * 60, // 24 hours - - // Keeper - oracles: [ - '0xf1a2f8E2FaE384566Fe10f9a960f52fe4a103737', - '0xF1091485531122c2cd0Beb6fD998FBCcCf42b38C', - '0x51182c9B66F5Cb2394511006851aE9b1Ea7f1B5D', - '0x675eD17F58b15CD2C31F6d9bfb0b4DfcCA264eC1', - '0x6bAfFEE3c8B59E5bA19c26Cd409B2a232abb57Cb', - '0x36a2E8FF08f801caB399eab2fEe9E6A8C49A9C2A', - '0x3EC6676fa4D07C1f31d088ae1DE96240eC56D1D9', - '0x893e1c16fE47DF676Fd344d44c074096675B6aF6', - '0x3eEC4A51cbB2De4e8Cc6c9eE859Ad16E8a8693FC', - '0x9772Ef6AbC2Dfd879ebd88aeAA9Cf1e69a16fCF4', - '0x18991d6F877eF0c0920BFF9B14D994D80d2E7B0c', - ], - rewardsMinOracles: 6, - validatorsMinOracles: 6, - rewardsDelay: 12 * 60 * 60, // 12 hours - maxAvgRewardPerSecond: 6341958397n, // 20% APY - oraclesConfigIpfsHash: 'Qmb1vAihRCDuEkhe22RL2FkW19MZ2jXKLERuFLwdXvWdQC', - - // OsToken - treasury: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - osTokenFeePercent: 500, // 5% - osTokenCapacity: parseEther('1000000'), // 1m ETH - osTokenName: 'Staked ETH', - osTokenSymbol: 'osETH', - - // OsTokenConfig - liqThresholdPercent: parseEther('0.92'), // 92% - liqBonusPercent: parseEther('1.01'), // 101% - ltvPercent: parseEther('0.90'), // 90% - - // OsTokenVaultEscrow - osTokenVaultEscrow: { - authenticator: '0x4a745DFF39bBEa970Da28DBA2ba94DB81938AC39', - liqThresholdPercent: parseEther('0.99994'), // 99.994% - liqBonusPercent: parseEther('1.000027'), // 0.0027% - }, - - // EthGenesisVault - genesisVault: { - admin: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - poolEscrow: '0x291Fa5849215847081B475450cBE5De46CfD4fAE', - rewardToken: '0x75c57bd50A3EB7291Da3429956D3566E0153A38f', - capacity: parseEther('1000000'), // 1m ETH - feePercent: 500, // 5% - }, - // EthFoxVault - foxVault: { - admin: '0xd23D393167e391e62d464CD5ef09e52Ed58BC889', - capacity: MAX_UINT256, // unlimited - feePercent: 500, // 5% - metadataIpfsHash: '', - }, - priceFeedDescription: 'osETH/ETH', - }, - [Networks.mainnet]: { - url: process.env.MAINNET_RPC_URL || '', - chainId: 1, - - governor: '0x144a98cb1CdBb23610501fE6108858D9B7D24934', - validatorsRegistry: '0x00000000219ab540356cBB839Cbe05303d7705Fa', - securityDeposit: 1000000000n, // 1 gwei - exitedAssetsClaimDelay: 24 * 60 * 60, // 24 hours - - // Keeper - oracles: [ - '0x6D403394848EaD12356C9Bb667ED27bCe1945914', - '0xED5a1c366984215A28a95bE95A9a49d59a065e91', - '0x20B04EcB2bc5E44Ac5AaAd9c8DD3cd04d9Fb87c8', - '0x4E81bfde2eb1574bf0839aDEFb65cEA0D8B07EFC', - '0x49F436341dbB3ffFce92C59fBcfcAEdaD22D0b0e', - '0x624EC1141Eb0C3bE58b382737718852665c35Cf0', - '0x671D846eCd7D945011912a6fa42E6F3E39eD0569', - '0x3F77cC37b5F49561E84e36D87FAe1F032E1f771e', - '0xa9Ccb8ba942C45F6Fa786F936679812591dA012a', - '0xb5dBd61DAb7138aF20A61614e0A4587566C2A15A', - '0x8Ce4f2800dE6476F42a070C79AfA58E0E209173e', - ], - rewardsDelay: 12 * 60 * 60, // 12 hours - rewardsMinOracles: 6, - validatorsMinOracles: 6, - maxAvgRewardPerSecond: 6341958397n, // 20% APY - oraclesConfigIpfsHash: 'QmX3Hx3UTBCAy4FTietUeSbD9NPjTnTwBzMxPdPeJgyRJF', - - // OsToken - treasury: '0x144a98cb1CdBb23610501fE6108858D9B7D24934', - osTokenFeePercent: 500, // 5 % - osTokenCapacity: parseEther('20000000'), // 20m osETH - osTokenName: 'Staked ETH', - osTokenSymbol: 'osETH', - - // OsTokenConfig - liqThresholdPercent: parseEther('0.92'), // 92% - liqBonusPercent: parseEther('1.01'), // 101% - ltvPercent: parseEther('0.90'), // 90% - - // OsTokenVaultEscrow - osTokenVaultEscrow: { - authenticator: '0xFc8E3E7c919b4392D9F5B27015688e49c80015f0', - liqThresholdPercent: parseEther('0.99986'), // 99.986% - liqBonusPercent: parseEther('1.000068'), // 0.0068% - }, - - // EthGenesisVault - genesisVault: { - admin: '0xf330b5fE72E91d1a3782E65eED876CF3624c7802', - poolEscrow: '0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079', - rewardToken: '0x20BC832ca081b91433ff6c17f85701B6e92486c5', - capacity: parseEther('1000000'), // 1m ETH - feePercent: 500, // 5% - }, - // EthFoxVault - foxVault: { - admin: '0xFD8100AA60F851e0EB585C7c893B8Ef6A7F88788', - capacity: MAX_UINT256, // unlimited - feePercent: 1500, // 15% - metadataIpfsHash: '', - }, - priceFeedDescription: 'osETH/ETH', - }, - [Networks.chiado]: { - url: process.env.CHIADO_RPC_URL || '', - chainId: 10200, - - governor: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - validatorsRegistry: '0xb97036A26259B7147018913bD58a774cf91acf25', - securityDeposit: 1000000000n, // 1 gwei of GNO - exitedAssetsClaimDelay: 24 * 60 * 60, // 24 hours - - // Keeper - oracles: [ - '0xf1a2f8E2FaE384566Fe10f9a960f52fe4a103737', - '0xF1091485531122c2cd0Beb6fD998FBCcCf42b38C', - '0x51182c9B66F5Cb2394511006851aE9b1Ea7f1B5D', - '0x675eD17F58b15CD2C31F6d9bfb0b4DfcCA264eC1', - '0x6bAfFEE3c8B59E5bA19c26Cd409B2a232abb57Cb', - '0x36a2E8FF08f801caB399eab2fEe9E6A8C49A9C2A', - '0x3EC6676fa4D07C1f31d088ae1DE96240eC56D1D9', - '0x893e1c16fE47DF676Fd344d44c074096675B6aF6', - '0x3eEC4A51cbB2De4e8Cc6c9eE859Ad16E8a8693FC', - '0x9772Ef6AbC2Dfd879ebd88aeAA9Cf1e69a16fCF4', - '0x18991d6F877eF0c0920BFF9B14D994D80d2E7B0c', - ], - rewardsDelay: 12 * 60 * 60, // 12 hours - rewardsMinOracles: 6, - validatorsMinOracles: 6, - maxAvgRewardPerSecond: MAX_UINT256, // unlimited - oraclesConfigIpfsHash: 'QmTuG4mzQpjRp3zZV9q4u49kUeVhusoFv6Pvem89ZvPqTB', - - // OsToken - treasury: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - osTokenFeePercent: 500, // 5 % - osTokenCapacity: parseEther('500000'), // 500k osGNO - osTokenName: 'Staked GNO', - osTokenSymbol: 'osGNO', - - // OsTokenConfig - liqThresholdPercent: parseEther('0.92'), // 92% - liqBonusPercent: parseEther('1.01'), // 101% - ltvPercent: parseEther('0.90'), // 90% - - // OsTokenVaultEscrow - osTokenVaultEscrow: { - authenticator: '0xCd4f0b056F56BCc28193Ca2Ca9B98AEdd940308d', - liqThresholdPercent: parseEther('0.99835'), // 99.835% - liqBonusPercent: parseEther('1.000821'), // 0.0821% - }, - - // GnoGenesisVault - genesisVault: { - admin: '0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6', - poolEscrow: '0x928F9a91E674C886Cae0c377670109aBeF7e19d6', - rewardToken: '0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4', - capacity: parseEther('1000000'), // 1m GNO - feePercent: 1500, // 15% - }, - priceFeedDescription: 'osGNO/GNO', - - // Gnosis data - gnosis: { - gnoToken: '0x19C653Da7c37c66208fbfbE8908A5051B57b4C70', - gnoPriceFeed: '0xcC5E385EdB2fEaB9C9A6DE97b572f1d811312ae7', - daiPriceFeed: '0x390C320Ae2B001C7CB31A690e2500b55313aC986', - balancerVault: '0x8b6c2C9E09c6022780D164F3cFd882808b8bDBF0', - balancerPoolId: '0xa99fd9950b5d5dceeaf4939e221dca8ca9b938ab000100000000000000000025', - maxSlippage: 100, // 1% - stalePriceTimeDelta: MAX_UINT128, // unlimited - }, - }, - [Networks.gnosis]: { - url: process.env.GNOSIS_RPC_URL || '', - chainId: 100, - - governor: '0x8737f638E9af54e89ed9E1234dbC68B115CD169e', - validatorsRegistry: '0x0B98057eA310F4d31F2a452B414647007d1645d9', - securityDeposit: 1000000000n, // 1 gwei of GNO - exitedAssetsClaimDelay: 24 * 60 * 60, // 24 hours - - // Keeper - oracles: [ - '0xf35938F9Dd462F9AB6B4C75A5Cd786b319F00C1b', - '0x0199e1804fea282b10445Cc0844418D276F74741', - '0x4806EE05e73dcC9b6EC5BB23477E5e7bcBE5317F', - '0x8F504a3706cBe2122e7Ca04b1fedD00BAAC988b5', - '0x7D03d930775e629CBf9712838098Abfe08a69635', - '0xf9E45a16a2505093dbb2828f4fb9DCdaeD4E2ac6', - '0x049614C22E7c33d3E0C8f698f20235cE54761266', - '0x973fb54e573eb7eF90176d05c9504FF2176B37c8', - '0x7628a7166B924f48906f40722C8fb4d09ce1D4fe', - '0xAB47D82D81b5FD24efb00a17F5732b6d52987700', - '0x04744cCE57Bdacc6f8f03579e47c3B64D4495c0E', - ], - rewardsDelay: 12 * 60 * 60, // 12 hours - rewardsMinOracles: 6, - validatorsMinOracles: 6, - maxAvgRewardPerSecond: 15854895992n, // 50% APY - oraclesConfigIpfsHash: 'QmT9DNP5DFgWtrRDyYWCVFMbLuxmf8bfWLrWEKETQu77Zj', - - // OsToken - treasury: '0x8737f638E9af54e89ed9E1234dbC68B115CD169e', - osTokenFeePercent: 500, // 5 % - osTokenCapacity: parseEther('500000'), // 500k osGNO - osTokenName: 'Staked GNO', - osTokenSymbol: 'osGNO', - - // OsTokenConfig - liqThresholdPercent: parseEther('0.92'), // 92% - liqBonusPercent: parseEther('1.01'), // 101% - ltvPercent: parseEther('0.90'), // 90% - - // OsTokenVaultEscrow - osTokenVaultEscrow: { - authenticator: '0xe0Ae8B04922d6e3fA06c2496A94EF2875EFcC7BB', - liqThresholdPercent: parseEther('0.99972'), // 99.972% - liqBonusPercent: parseEther('1.000136'), // 0.0136% - }, - - // GnoGenesisVault - genesisVault: { - admin: '0x6Da6B1EfCCb7216078B9004535941b71EeD30b0F', - poolEscrow: '0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394', - rewardToken: '0x6aC78efae880282396a335CA2F79863A1e6831D4', - capacity: parseEther('1000000'), // 1m GNO - feePercent: 1500, // 15% - }, - priceFeedDescription: 'osGNO/GNO', - - // Gnosis data - gnosis: { - gnoToken: '0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb', - gnoPriceFeed: '0x22441d81416430A54336aB28765abd31a792Ad37', - daiPriceFeed: '0x678df3415fc31947dA4324eC63212874be5a82f8', - balancerVault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', - balancerPoolId: '0x8189c4c96826d016a99986394103dfa9ae41e7ee0002000000000000000000aa', - maxSlippage: 100, // 1% - stalePriceTimeDelta: 172800n, // 48 hours - }, - }, -} - -export const MAINNET_FORK = { - enabled: process.env.ENABLE_MAINNET_FORK === 'true', - blockNumber: 21866520, - rpcUrl: process.env.MAINNET_FORK_RPC_URL || '', - vaults: { - ethVaultOwnMevEscrow: '0x663580B3edAd914D0b59CeA88616F06278D42bb2', - ethVaultSharedMevEscrow: '0x089A97A8bC0C0F016f89F9CF42181Ff06afB2Daf', - ethPrivVaultOwnMevEscrow: '0xcCa8d532e625d30514Ace25963283228F82CcdDa', - ethPrivVaultSharedMevEscrow: '0xD66A71A68392767F26b7EE47e9a0293191A23072', - ethErc20VaultOwnMevEscrow: '0x3102B4013cB506481e959c8F4500B994D2bFF22e', - ethErc20VaultSharedMevEscrow: '0x9c29c571847A68A947AceC8bacd303e36bC72ec5', - ethPrivErc20VaultOwnMevEscrow: '0x3F202096c3A3f544Bd8f5ca2793E83d5642D5bFb', - ethPrivErc20VaultSharedMevEscrow: '0xFB22Ded2bd69aff0907e195F23E448aB44E3cA97', - ethGenesisVault: '0xAC0F906E433d58FA868F936E8A43230473652885', - }, - harvestParams: { - '0x663580B3edAd914D0b59CeA88616F06278D42bb2': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 370271478000000000n, - unlockedMevReward: 0n, - proof: [ - '0xeba2e46ead610b3c8adfba5a82347455780a60c09d39b710d15a6328eab1de9f', - '0xc58722f8a3a2f5b912188b6acbb022bb54744fe503a657ac7003fc7ab89fae46', - '0x268012151cfa636100d04670dce054810272e30f999af28f3f35c1858e85f7ec', - '0x81bd3f4859fc226bc7e862117af2627abb49fc301350ba32f559bbf3138b4234', - '0x2baff53a841f50a771305eaf2b89d0341c74f340802d00d904f67d1c0ac99a12', - ], - }, - '0x089A97A8bC0C0F016f89F9CF42181Ff06afB2Daf': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 2601666098562034418n, - unlockedMevReward: 379242282394372329n, - proof: [ - '0xab66ab73737efc81d39f0a47ef1d246d96792a076b995fbc6bc72a0c660966dc', - '0x018a5b7f2279f13288ce78cb3cffa1c8516e8a07243c5f1da58d14084c445fe0', - '0x48f527f36d88907dd18e991ed351427c347e1a5aeee7bdf8a07db285ca3f3674', - '0x4edc01daf2151f4f6c3e190eac41140c88524d84a7321134a3ca8dd00a9437c6', - '0x3cf045ccf1a4cc4e7c14f42b2eaa3fc1da583236a7f8e3de1ac596921b663c63', - '0x768a161fdfb31a71b5157d2f7d0df43a0c9d5e854598d20c7ad170dc7adcb247', - ], - }, - '0xcCa8d532e625d30514Ace25963283228F82CcdDa': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 36038818000000000n, - unlockedMevReward: 0n, - proof: [ - '0x5a2cf20e40b748349bb7c4c9419055062e4be2782b34225cc6f0dd1caed3bd46', - '0xcb42b5e68fc764cad24857634e45e53084bed23f0908b8c780cda29179af2cc6', - '0xde6b45c9b33a6de3c30c6865171710003311dd46b3addb26d1d8f0554295c467', - '0x789d2bb0a65e6fc55ce935d58c4375aa7e6a9246fd48d5b52866fc352685a4dc', - '0xd6f3d64c83c769ac76a7a98bccb7afd7cf5be14a8a211e7a10832c1b2bf7573a', - '0x768a161fdfb31a71b5157d2f7d0df43a0c9d5e854598d20c7ad170dc7adcb247', - ], - }, - '0xD66A71A68392767F26b7EE47e9a0293191A23072': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 17651468000000000n, - unlockedMevReward: 0n, - proof: [ - '0x8d2ba9677e8a7d87b2bde1fabe8c83aabba7b4964a18bd89951041d042f722b5', - '0x781ac864ad599fa62059dacbcc7a3ec16c7c0ff1c140c59a092b00b2309697da', - '0x5e4ec1f28a602e4c8a32ee3230025b9aef4c2d781f77ae083e6c378325189b6e', - '0x304900b975ba8fa13e4f8bfe8af28ede6836d3edbd4f88d10364902fca226f35', - '0x3cf045ccf1a4cc4e7c14f42b2eaa3fc1da583236a7f8e3de1ac596921b663c63', - '0x768a161fdfb31a71b5157d2f7d0df43a0c9d5e854598d20c7ad170dc7adcb247', - ], - }, - '0x3102B4013cB506481e959c8F4500B994D2bFF22e': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 655782750000000000n, - unlockedMevReward: 0n, - proof: [ - '0xc5004cfcce48426798a0a7da4a3291b70fae7e48ea4cc7cb8e1924427aa9074a', - '0x81105a8489f0d024e3ccb62b6573aa8db4bbb7e5d435572bc2bb7bbe4aec776f', - '0x62dd6f6c4d69dbc543f15c2c3519ca839410ccec7150d6ebfbbe56ef5d6a47ba', - '0x4edc01daf2151f4f6c3e190eac41140c88524d84a7321134a3ca8dd00a9437c6', - '0x3cf045ccf1a4cc4e7c14f42b2eaa3fc1da583236a7f8e3de1ac596921b663c63', - '0x768a161fdfb31a71b5157d2f7d0df43a0c9d5e854598d20c7ad170dc7adcb247', - ], - }, - '0x9c29c571847A68A947AceC8bacd303e36bC72ec5': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 838642149564534034n, - unlockedMevReward: 108454527643194127n, - proof: [ - '0xa890ed09db09b75b5a2e14d78f6129884daf9d63505f8dad1af12f36e56921e8', - '0x5fe5be84d089057868886cf9dd57153017f92c5ffe686cc75e54d3de55297435', - '0xd8800fcf89fa6a4ddc6be9b5f07acf66ddf797b7b2b37d433d7e75b11e0d1222', - '0x304900b975ba8fa13e4f8bfe8af28ede6836d3edbd4f88d10364902fca226f35', - '0x3cf045ccf1a4cc4e7c14f42b2eaa3fc1da583236a7f8e3de1ac596921b663c63', - '0x768a161fdfb31a71b5157d2f7d0df43a0c9d5e854598d20c7ad170dc7adcb247', - ], - }, - '0xAC0F906E433d58FA868F936E8A43230473652885': { - rewardsRoot: '0xfa786879b42abe1980a18209a73b7982e91554d82c495d687dd8c2a8109b0e96', - reward: 10281264030482176612823n, - unlockedMevReward: 439405911556251952650n, - proof: [ - '0xe2f045aaddf90b4dbc747cf1f71c853fe94c43acf634ed7c4e75a79958ec96f2', - '0x9fed225a4ba8a8c1dfc347bbb2475c0a479f2c4b46cb3c6186b23a471b5bff6d', - '0x02e1b574ed1cbca2eedf1c583b9cfd54be5acff0ffb16dd76d73f9dbcab694a9', - '0x07333d832cb8b6e5ae0fafd3f8113b91b84b09b413dbae80f0b90b458c5e94b6', - '0x2baff53a841f50a771305eaf2b89d0341c74f340802d00d904f67d1c0ac99a12', - ], - }, - }, - oracles: [ - '0x6D403394848EaD12356C9Bb667ED27bCe1945914', - '0xED5a1c366984215A28a95bE95A9a49d59a065e91', - '0x20B04EcB2bc5E44Ac5AaAd9c8DD3cd04d9Fb87c8', - '0x4E81bfde2eb1574bf0839aDEFb65cEA0D8B07EFC', - '0x49F436341dbB3ffFce92C59fBcfcAEdaD22D0b0e', - '0x624EC1141Eb0C3bE58b382737718852665c35Cf0', - '0x671D846eCd7D945011912a6fa42E6F3E39eD0569', - '0x3F77cC37b5F49561E84e36D87FAe1F032E1f771e', - '0xa9Ccb8ba942C45F6Fa786F936679812591dA012a', - '0xb5dBd61DAb7138aF20A61614e0A4587566C2A15A', - '0x8Ce4f2800dE6476F42a070C79AfA58E0E209173e', - ], - v2PoolHolder: '0xa48a523F3e0f1A9232BfE22bB6aE07Bb44bF36F1', - eigenPodManager: '0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338', - eigenDelegationManager: '0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A', - eigenDelayedWithdrawalRouter: '0x7Fe7E9CC0F274d2435AD5d56D5fa73E47F6A23D8', - eigenOperator: '0xDbEd88D83176316fc46797B43aDeE927Dc2ff2F5', -} diff --git a/helpers/types.ts b/helpers/types.ts deleted file mode 100644 index e073d922..00000000 --- a/helpers/types.ts +++ /dev/null @@ -1,85 +0,0 @@ -export type ThenArg = T extends PromiseLike ? U : T - -export enum Networks { - mainnet = 'mainnet', - hoodi = 'hoodi', - chiado = 'chiado', - gnosis = 'gnosis', -} - -export type NetworkConfig = { - url: string - chainId: number - - governor: string - validatorsRegistry: string - securityDeposit: bigint - exitedAssetsClaimDelay: number - - // Keeper - oracles: string[] - rewardsMinOracles: number - validatorsMinOracles: number - rewardsDelay: number - oraclesConfigIpfsHash: string - maxAvgRewardPerSecond: bigint - - // OsToken - treasury: string - osTokenFeePercent: number - osTokenCapacity: bigint - osTokenName: string - osTokenSymbol: string - - // OsTokenConfig - liqThresholdPercent: bigint - liqBonusPercent: bigint - ltvPercent: bigint - - // OsTokenVaultEscrow - osTokenVaultEscrow: { - authenticator: string - liqThresholdPercent: bigint - liqBonusPercent: bigint - } - - // EthGenesisVault - genesisVault: { - admin: string - poolEscrow: string - rewardToken: string - capacity: bigint - feePercent: number - } - - // EthFoxVault - foxVault?: { - admin: string - capacity: bigint - feePercent: number - metadataIpfsHash: string - } - - // Gnosis data - gnosis?: { - gnoToken: string - gnoPriceFeed: string - daiPriceFeed: string - balancerVault: string - balancerPoolId: string - maxSlippage: number - stalePriceTimeDelta: bigint - } - - // PriceFeed - priceFeedDescription: string -} - -export type GovernorCall = { - to: string - operation: string - value: string - data: string - method: string - params: any[] -} diff --git a/helpers/utils.ts b/helpers/utils.ts deleted file mode 100644 index e135d631..00000000 --- a/helpers/utils.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Contract } from 'ethers' -import { HardhatRuntimeEnvironment } from 'hardhat/types/runtime' -import '@openzeppelin/hardhat-upgrades/dist/type-extensions' -import { GovernorCall } from './types' - -export async function deployContract( - hre: HardhatRuntimeEnvironment, - contractName: string, - constructorArgs: any[], - path?: string, - options?: any -): Promise { - const contract = await hre.ethers.deployContract(contractName, constructorArgs, options) - await contract.waitForDeployment() - - const contractAddress = await contract.getAddress() - console.log(`${contractName} deployed at`, contractAddress) - if (path) { - await verify(hre, contractAddress, constructorArgs, path) - } - return contract -} - -export async function callContract(tx: any) { - const result = await tx - await result.wait() -} - -async function delay(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)) -} - -export async function verify( - hre: HardhatRuntimeEnvironment, - address: string, - constructorArgs: any, - contractPath: string -) { - if (!process.env.BLOCK_EXPLORER_KEY) { - return - } - - let count = 0 - const maxTries = 8 - - while (true) { - await delay(10000) - try { - console.log('Verifying contract at', address) - await hre.run('verify:verify', { - address, - constructorArguments: constructorArgs, - contract: contractPath, - }) - break - } catch (error) { - if (String(error).includes('Already Verified')) { - console.log(`Already verified contract at ${contractPath} at address ${address}`) - break - } - if (++count == maxTries) { - console.log( - `Failed to verify contract at ${contractPath} at address ${address}, error: ${error}` - ) - break - } - console.log(`Retrying... Retry #${count}, last error: ${error}`) - } - } -} - -export async function encodeGovernorContractCall( - contract: Contract, - method: string, - params: any[] -): Promise { - const data = contract.interface.encodeFunctionData(method, params) - return { - to: await contract.getAddress(), - operation: '0', - value: '0.0', - data, - method, - params, - } -} diff --git a/lib/openzeppelin-foundry-upgrades b/lib/openzeppelin-foundry-upgrades deleted file mode 160000 index cbce1e00..00000000 --- a/lib/openzeppelin-foundry-upgrades +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cbce1e00305e943aa1661d43f41e5ac72c662b07 diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 00000000..5be0b517 --- /dev/null +++ b/remappings.txt @@ -0,0 +1,2 @@ +@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/ +@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ \ No newline at end of file diff --git a/script/Network.sol b/script/Network.sol new file mode 100644 index 00000000..1a1f5636 --- /dev/null +++ b/script/Network.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +/** + * @title Network + * @author StakeWise + * @notice Solidity library containing constants for the StakeWise protocol + */ +library Network { + uint256 internal constant MAINNET = 1; + uint256 internal constant HOODI = 560048; + uint256 internal constant CHIADO = 10200; + uint256 internal constant GNOSIS = 100; + + uint64 internal constant PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY = 1 days; + // disable delay for private vaults as stakers are KYC'd + uint64 internal constant PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY = 0; + address internal constant VALIDATORS_WITHDRAWALS = 0x00000961Ef480Eb55e80D19ad83579A64c007002; + address internal constant VALIDATORS_CONSOLIDATIONS = 0x0000BBdDc7CE488642fb579F8B00f3a590007251; + + // MAINNET + address internal constant MAINNET_KEEPER = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; + address internal constant MAINNET_VAULTS_REGISTRY = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; + address internal constant MAINNET_VALIDATORS_REGISTRY = + 0x00000000219ab540356cBB839Cbe05303d7705Fa; + address internal constant MAINNET_OS_TOKEN_VAULT_CONTROLLER = + 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; + address internal constant MAINNET_OS_TOKEN_CONFIG = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; + address internal constant MAINNET_OS_TOKEN_VAULT_ESCROW = + 0x09e84205DF7c68907e619D07aFD90143c5763605; + address internal constant MAINNET_SHARED_MEV_ESCROW = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; + address internal constant MAINNET_DEPOSIT_DATA_REGISTRY = + 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; + address internal constant MAINNET_LEGACY_POOL_ESCROW = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; + address internal constant MAINNET_LEGACY_REWARD_TOKEN = + 0x20BC832ca081b91433ff6c17f85701B6e92486c5; + + // HOODI + address internal constant HOODI_KEEPER = 0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f; + address internal constant HOODI_VAULTS_REGISTRY = 0xf16fea93D3253A401C3f73B0De890C6586740B25; + address internal constant HOODI_VALIDATORS_REGISTRY = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + address internal constant HOODI_OS_TOKEN_VAULT_CONTROLLER = + 0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1; + address internal constant HOODI_OS_TOKEN_CONFIG = 0x5b817621EBE00622b9a71b53c942b392751c8197; + address internal constant HOODI_OS_TOKEN_VAULT_ESCROW = + 0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B; + address internal constant HOODI_SHARED_MEV_ESCROW = 0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd; + address internal constant HOODI_DEPOSIT_DATA_REGISTRY = + 0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487; + address internal constant HOODI_LEGACY_POOL_ESCROW = 0x291Fa5849215847081B475450cBE5De46CfD4fAE; + address internal constant HOODI_LEGACY_REWARD_TOKEN = 0x75c57bd50A3EB7291Da3429956D3566E0153A38f; + + // GNOSIS + address internal constant GNOSIS_KEEPER = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; + address internal constant GNOSIS_VAULTS_REGISTRY = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; + address internal constant GNOSIS_VALIDATORS_REGISTRY = 0x0B98057eA310F4d31F2a452B414647007d1645d9; + address internal constant GNOSIS_OS_TOKEN_VAULT_CONTROLLER = + 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; + address internal constant GNOSIS_OS_TOKEN_CONFIG = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; + address internal constant GNOSIS_OS_TOKEN_VAULT_ESCROW = + 0x28F325dD287a5984B754d34CfCA38af3A8429e71; + address internal constant GNOSIS_SHARED_MEV_ESCROW = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; + address internal constant GNOSIS_DEPOSIT_DATA_REGISTRY = + 0x58e16621B5c0786D6667D2d54E28A20940269E16; + address internal constant GNOSIS_LEGACY_POOL_ESCROW = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; + address internal constant GNOSIS_LEGACY_REWARD_TOKEN = 0x6aC78efae880282396a335CA2F79863A1e6831D4; + + // CHIADO + address internal constant CHIADO_KEEPER = 0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988; + address internal constant CHIADO_VAULTS_REGISTRY = 0x8750594B33516232e751C8B9C350a660cD5f1BB8; + address internal constant CHIADO_VALIDATORS_REGISTRY = 0xb97036A26259B7147018913bD58a774cf91acf25; + address internal constant CHIADO_OS_TOKEN_VAULT_CONTROLLER = + 0x5518052f2d898f062ee59964004A560F24E2eE7d; + address internal constant CHIADO_OS_TOKEN_CONFIG = 0x6D5957e075fd93b3B9F36Da93d7462F14387706d; + address internal constant CHIADO_OS_TOKEN_VAULT_ESCROW = + 0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7; + address internal constant CHIADO_SHARED_MEV_ESCROW = 0x453056f0bc4631abB15eEC656139f88067668E3E; + address internal constant CHIADO_DEPOSIT_DATA_REGISTRY = + 0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D; + address internal constant CHIADO_LEGACY_POOL_ESCROW = 0x928F9a91E674C886Cae0c377670109aBeF7e19d6; + address internal constant CHIADO_LEGACY_REWARD_TOKEN = 0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4; + + struct Constants { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + address legacyPoolEscrow; + address legacyRewardToken; + uint64 exitedAssetsClaimDelay; + } + + function getNetworkConstants(uint256 chainId) internal pure returns (Constants memory) { + if (chainId == MAINNET) { + return + Constants({ + keeper: MAINNET_KEEPER, + vaultsRegistry: MAINNET_VAULTS_REGISTRY, + validatorsRegistry: MAINNET_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: MAINNET_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: MAINNET_OS_TOKEN_CONFIG, + osTokenVaultEscrow: MAINNET_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: MAINNET_SHARED_MEV_ESCROW, + depositDataRegistry: MAINNET_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: MAINNET_LEGACY_POOL_ESCROW, + legacyRewardToken: MAINNET_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else if (chainId == HOODI) { + return + Constants({ + keeper: HOODI_KEEPER, + vaultsRegistry: HOODI_VAULTS_REGISTRY, + validatorsRegistry: HOODI_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: HOODI_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: HOODI_OS_TOKEN_CONFIG, + osTokenVaultEscrow: HOODI_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: HOODI_SHARED_MEV_ESCROW, + depositDataRegistry: HOODI_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: HOODI_LEGACY_POOL_ESCROW, + legacyRewardToken: HOODI_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else if (chainId == GNOSIS) { + return + Constants({ + keeper: GNOSIS_KEEPER, + vaultsRegistry: GNOSIS_VAULTS_REGISTRY, + validatorsRegistry: GNOSIS_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: GNOSIS_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: GNOSIS_OS_TOKEN_CONFIG, + osTokenVaultEscrow: GNOSIS_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: GNOSIS_SHARED_MEV_ESCROW, + depositDataRegistry: GNOSIS_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: GNOSIS_LEGACY_POOL_ESCROW, + legacyRewardToken: GNOSIS_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else if (chainId == CHIADO) { + return + Constants({ + keeper: CHIADO_KEEPER, + vaultsRegistry: CHIADO_VAULTS_REGISTRY, + validatorsRegistry: CHIADO_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: CHIADO_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: CHIADO_OS_TOKEN_CONFIG, + osTokenVaultEscrow: CHIADO_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: CHIADO_SHARED_MEV_ESCROW, + depositDataRegistry: CHIADO_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: CHIADO_LEGACY_POOL_ESCROW, + legacyRewardToken: CHIADO_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else { + revert('Unsupported chain ID'); + } + } +} diff --git a/script/UpgradeEthNetwork.s.sol b/script/UpgradeEthNetwork.s.sol new file mode 100644 index 00000000..6a4ca4d6 --- /dev/null +++ b/script/UpgradeEthNetwork.s.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +import {Script} from 'forge-std/Script.sol'; +import {console} from 'forge-std/console.sol'; +import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; +import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; +import {IVaultsRegistry} from '../contracts/interfaces/IVaultsRegistry.sol'; +import {IVaultVersion} from '../contracts/interfaces/IVaultVersion.sol'; +import {ConsolidationsChecker} from '../contracts/validators/ConsolidationsChecker.sol'; +import {EthBlocklistErc20Vault} from '../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; +import {EthBlocklistVault} from '../contracts/vaults/ethereum/EthBlocklistVault.sol'; +import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; +import {EthGenesisVault} from '../contracts/vaults/ethereum/EthGenesisVault.sol'; +import {EthPrivErc20Vault} from '../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; +import {EthPrivVault} from '../contracts/vaults/ethereum/EthPrivVault.sol'; +import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {EthVaultFactory} from '../contracts/vaults/ethereum/EthVaultFactory.sol'; +import {Network} from './Network.sol'; + +contract UpgradeEthNetwork is Script { + Network.Constants public constants; + address public consolidationsChecker; + address[] public vaultImpls; + address[] public vaultFactories; + + function run() external { + vm.startBroadcast(vm.envUint('PRIVATE_KEY')); + console.log('Deploying from: ', msg.sender); + + constants = Network.getNetworkConstants(block.chainid); + + // Deploy consolidations checker + consolidationsChecker = address(new ConsolidationsChecker(constants.keeper)); + + _deployImplementations(); + _deployFactories(); + + vm.stopBroadcast(); + } + + function _deployImplementations() internal { + // constructors for implementations + IEthVault.EthVaultConstructorArgs memory vaultArgs = _getEthVaultConstructorArgs(); + IEthErc20Vault.EthErc20VaultConstructorArgs + memory erc20VaultArgs = _getEthErc20VaultConstructorArgs(); + + // deploy genesis vault + vaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + + EthGenesisVault ethGenesisVault = new EthGenesisVault( + vaultArgs, + constants.legacyPoolEscrow, + constants.legacyRewardToken + ); + + // deploy normal vaults + EthVault ethVault = new EthVault(vaultArgs); + EthErc20Vault ethErc20Vault = new EthErc20Vault(erc20VaultArgs); + + // deploy blocklist vaults + EthBlocklistVault ethBlocklistVault = new EthBlocklistVault(vaultArgs); + EthBlocklistErc20Vault ethBlocklistErc20Vault = new EthBlocklistErc20Vault(erc20VaultArgs); + + // deploy private vaults + // update exited assets claim delay for private vaults + vaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + EthPrivVault ethPrivVault = new EthPrivVault(vaultArgs); + EthPrivErc20Vault ethPrivErc20Vault = new EthPrivErc20Vault(erc20VaultArgs); + + vaultImpls.push(address(ethGenesisVault)); + vaultImpls.push(address(ethVault)); + vaultImpls.push(address(ethErc20Vault)); + vaultImpls.push(address(ethBlocklistVault)); + vaultImpls.push(address(ethBlocklistErc20Vault)); + vaultImpls.push(address(ethPrivVault)); + vaultImpls.push(address(ethPrivErc20Vault)); + } + + function _deployFactories() internal { + for (uint256 i = 0; i < vaultImpls.length; i++) { + address vaultImpl = vaultImpls[i]; + if (IVaultVersion(vaultImpl).vaultId() == keccak256('EthGenesisVault')) { + continue; + } + EthVaultFactory factory = new EthVaultFactory( + vaultImpl, + IVaultsRegistry(constants.vaultsRegistry) + ); + vaultFactories.push(address(factory)); + } + } + + function _getEthVaultConstructorArgs() + internal + view + returns (IEthVault.EthVaultConstructorArgs memory) + { + return + IEthVault.EthVaultConstructorArgs({ + keeper: constants.keeper, + vaultsRegistry: constants.vaultsRegistry, + validatorsRegistry: constants.validatorsRegistry, + validatorsWithdrawals: constants.validatorsWithdrawals, + validatorsConsolidations: constants.validatorsConsolidations, + consolidationsChecker: consolidationsChecker, + osTokenVaultController: constants.osTokenVaultController, + osTokenConfig: constants.osTokenConfig, + osTokenVaultEscrow: constants.osTokenVaultEscrow, + sharedMevEscrow: constants.sharedMevEscrow, + depositDataRegistry: constants.depositDataRegistry, + exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay + }); + } + + function _getEthErc20VaultConstructorArgs() + internal + view + returns (IEthErc20Vault.EthErc20VaultConstructorArgs memory) + { + return + IEthErc20Vault.EthErc20VaultConstructorArgs({ + keeper: constants.keeper, + vaultsRegistry: constants.vaultsRegistry, + validatorsRegistry: constants.validatorsRegistry, + validatorsWithdrawals: constants.validatorsWithdrawals, + validatorsConsolidations: constants.validatorsConsolidations, + consolidationsChecker: consolidationsChecker, + osTokenVaultController: constants.osTokenVaultController, + osTokenConfig: constants.osTokenConfig, + osTokenVaultEscrow: constants.osTokenVaultEscrow, + sharedMevEscrow: constants.sharedMevEscrow, + depositDataRegistry: constants.depositDataRegistry, + exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay + }); + } + + function _generateGovernorTxJson() internal { + string[] memory objects = new string[](vaultImpls.length + vaultFactories.length); + for (uint256 i = 0; i < vaultImpls.length; i++) { + string memory object = Strings.toString(i); + vm.serializeAddress(object, 'to', constants.vaultsRegistry); + vm.serializeString(object, 'operation', '0'); + vm.serializeBytes( + object, + 'data', + abi.encodeWithSelector( + IVaultsRegistry(constants.vaultsRegistry).addVaultImpl.selector, + vaultImpls[i] + ) + ); + objects[i] = vm.serializeString(object, 'value', '0.0'); + } + + for (uint256 i = 0; i < vaultFactories.length; i++) { + string memory object = Strings.toString(vaultImpls.length + i); + vm.serializeAddress(object, 'to', constants.vaultsRegistry); + vm.serializeString(object, 'operation', '0'); + vm.serializeBytes( + object, + 'data', + abi.encodeWithSelector( + IVaultsRegistry(constants.vaultsRegistry).addFactory.selector, + vaultFactories[i] + ) + ); + objects[vaultImpls.length + i] = vm.serializeString(object, 'value', '0.0'); + } + string memory json = 'json'; + string memory output = vm.serializeString(json, 'transactions', objects); + vm.writeJson(output, './output/example.json'); + } +} diff --git a/snapshots/DepositDataRegistryTest.json b/snapshots/DepositDataRegistryTest.json deleted file mode 100644 index ed4b30fb..00000000 --- a/snapshots/DepositDataRegistryTest.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator": "287227", - "DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator": "287865", - "DepositDataRegistryTest_test_registerValidators_successWith0x01Validators": "347824", - "DepositDataRegistryTest_test_registerValidators_successWith0x02Validators": "349319", - "DepositDataRegistryTest_test_setDepositDataManager_succeeds": "64040", - "DepositDataRegistryTest_test_setDepositDataRoot_succeeds": "64979", - "DepositDataRegistryTest_test_updateVaultState_succeeds": "123935" -} \ No newline at end of file diff --git a/snapshots/GnoBlocklistErc20VaultTest.json b/snapshots/GnoBlocklistErc20VaultTest.json deleted file mode 100644 index 5880491e..00000000 --- a/snapshots/GnoBlocklistErc20VaultTest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "162316", - "GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161296", - "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "817154", - "GnoBlocklistErc20VaultTest_test_transfer": "61604", - "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "111723" -} \ No newline at end of file diff --git a/snapshots/GnoBlocklistVaultTest.json b/snapshots/GnoBlocklistVaultTest.json deleted file mode 100644 index 4dc89d1e..00000000 --- a/snapshots/GnoBlocklistVaultTest.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "160362", - "GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161279", - "GnoBlocklistVaultTest_test_deploysCorrectly": "535557", - "GnoBlocklistVaultTest_test_upgradesCorrectly": "111056" -} \ No newline at end of file diff --git a/snapshots/GnoErc20VaultTest.json b/snapshots/GnoErc20VaultTest.json deleted file mode 100644 index 727df3be..00000000 --- a/snapshots/GnoErc20VaultTest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv": "89861", - "GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "95982", - "GnoErc20VaultTest_test_deploysCorrectly": "585920", - "GnoErc20VaultTest_test_deposit_emitsTransfer": "100513", - "GnoErc20VaultTest_test_enterExitQueue_emitsTransfer": "89588", - "GnoErc20VaultTest_test_redeem_emitsEvent": "76768", - "GnoErc20VaultTest_test_upgradesCorrectly": "111580", - "VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "66365", - "VaultGnoErc20VaultTest_test_withdrawValidator_unknown": "51492", - "VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager": "61047" -} \ No newline at end of file diff --git a/snapshots/GnoGenesisVaultTest.json b/snapshots/GnoGenesisVaultTest.json deleted file mode 100644 index ee2d2629..00000000 --- a/snapshots/GnoGenesisVaultTest.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "GnoGenesisVaultTest_test_migrate_works": "201309", - "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "769734", - "GnoGenesisVaultTest_test_upgradesCorrectly": "6448921" -} \ No newline at end of file diff --git a/snapshots/GnoOsTokenVaultEscrowTest.json b/snapshots/GnoOsTokenVaultEscrowTest.json deleted file mode 100644 index 31d1352b..00000000 --- a/snapshots/GnoOsTokenVaultEscrowTest.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "GnoOsTokenVaultEscrowTest_test_transferAssets_claim": "118345", - "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "713279", - "GnoOsTokenVaultEscrowTest_test_transferAssets_transfer": "163008" -} \ No newline at end of file diff --git a/snapshots/GnoOwnMevEscrowTest.json b/snapshots/GnoOwnMevEscrowTest.json deleted file mode 100644 index 16b8527c..00000000 --- a/snapshots/GnoOwnMevEscrowTest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "GnoOwnMevEscrowTest_test_ownMevEscrowDeploymentGas": "252843" -} \ No newline at end of file diff --git a/snapshots/GnoPrivErc20VaultTest.json b/snapshots/GnoPrivErc20VaultTest.json deleted file mode 100644 index c4e99689..00000000 --- a/snapshots/GnoPrivErc20VaultTest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "158245", - "GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161315", - "GnoPrivErc20VaultTest_test_deploysCorrectly": "817176", - "GnoPrivErc20VaultTest_test_transfer": "59533", - "GnoPrivErc20VaultTest_test_upgradesCorrectly": "111749" -} \ No newline at end of file diff --git a/snapshots/GnoPrivVaultTest.json b/snapshots/GnoPrivVaultTest.json deleted file mode 100644 index 62e2617a..00000000 --- a/snapshots/GnoPrivVaultTest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "156378", - "GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161298", - "GnoPrivVaultTest_test_deploysCorrectly": "535512", - "GnoPrivVaultTest_test_setWhitelister": "36440", - "GnoPrivVaultTest_test_updateWhitelist": "54390", - "GnoPrivVaultTest_test_upgradesCorrectly": "111036" -} \ No newline at end of file diff --git a/snapshots/GnoSharedMevEscrowTest.json b/snapshots/GnoSharedMevEscrowTest.json deleted file mode 100644 index 9408113d..00000000 --- a/snapshots/GnoSharedMevEscrowTest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "GnoSharedMevEscrowTest_test_sharedEscrowDeploymentGas": "259099" -} \ No newline at end of file diff --git a/snapshots/GnoVaultTest.json b/snapshots/GnoVaultTest.json deleted file mode 100644 index bb9156bb..00000000 --- a/snapshots/GnoVaultTest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "GnoVaultTest_test_deploysCorrectly": "511667", - "GnoVaultTest_test_exitQueue_works": "94571", - "GnoVaultTest_test_upgradesCorrectly": "110935", - "GnoVaultTest_test_withdrawValidator_osTokenRedeemer": "66354", - "GnoVaultTest_test_withdrawValidator_unknown": "51481", - "GnoVaultTest_test_withdrawValidator_validatorsManager": "61025" -} \ No newline at end of file diff --git a/snapshots/VaultGnoStakingTest.json b/snapshots/VaultGnoStakingTest.json deleted file mode 100644 index c1e01b88..00000000 --- a/snapshots/VaultGnoStakingTest.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "136389", - "VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid": "129765", - "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "164448", - "VaultGnoStakingTest_test_deposit": "100895", - "VaultGnoStakingTest_test_processTotalAssetsDelta": "219087", - "VaultGnoStakingTest_test_pullWithdrawals": "85025", - "VaultGnoStakingTest_test_receive_xDai": "33397", - "VaultGnoStakingTest_test_transferVaultAssets": "81956", - "VaultGnoStakingTest_test_vaultGnoStaking_init": "511667", - "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "61019", - "test_registerValidators_succeeds_0x01": "297898", - "test_registerValidators_succeeds_0x02": "488267" -} \ No newline at end of file diff --git a/tasks/eth-full-deploy-local.ts b/tasks/eth-full-deploy-local.ts deleted file mode 100644 index 597a7522..00000000 --- a/tasks/eth-full-deploy-local.ts +++ /dev/null @@ -1,345 +0,0 @@ -import fs from 'fs' -import '@openzeppelin/hardhat-upgrades/dist/type-extensions' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import { task } from 'hardhat/config' -import { deployContract, callContract } from '../helpers/utils' -import EthValidatorsRegistry from '../test/shared/artifacts/EthValidatorsRegistry.json' -import { NetworkConfig, Networks } from '../helpers/types' -import { NETWORKS } from '../helpers/constants' - -const DEPLOYMENTS_DIR = 'deployments' - -task('eth-full-deploy-local', 'deploys StakeWise V3 for Ethereum to local network').setAction( - async (taskArgs, hre) => { - const ethers = hre.ethers - const networkName = hre.network.name - const networkConfig: NetworkConfig = NETWORKS[Networks.hoodi] - const accounts = await ethers.getSigners() - const deployer = accounts[0] - const governor = accounts[0] - const treasury = accounts[1] - const oracles = accounts.slice(2, 5) - const rewardsMinOracles = 2 - const validatorsMinOracles = 2 - - if (networkConfig.foxVault === undefined) { - throw new Error('FoxVault config is missing') - } - - // Create the signer for the mnemonic - console.log('Deploying StakeWise V3 for Ethereum to', networkName, 'from', deployer.address) - - // deploy VaultsRegistry - const vaultsRegistry = await deployContract(hre, 'VaultsRegistry', []) - const vaultsRegistryAddress = await vaultsRegistry.getAddress() - - // deploy ValidatorsRegistry - const validatorsRegistry = await ( - await ethers.getContractFactory( - EthValidatorsRegistry.abi, - EthValidatorsRegistry.bytecode, - deployer - ) - ).deploy() - await validatorsRegistry.waitForDeployment() - const validatorsRegistryAddress = await validatorsRegistry.getAddress() - console.log('ValidatorsRegistry deployed at', validatorsRegistryAddress) - - // deploy SharedMevEscrow - const sharedMevEscrow = await deployContract(hre, 'SharedMevEscrow', [vaultsRegistryAddress]) - const sharedMevEscrowAddress = await sharedMevEscrow.getAddress() - - // calculate osToken and keeper addresses - const osTokenAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 1, - }) - const keeperAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 2, - }) - - // deploy OsTokenVaultController - const osTokenVaultController = await deployContract(hre, 'OsTokenVaultController', [ - keeperAddress, - vaultsRegistryAddress, - osTokenAddress, - treasury, - governor, - networkConfig.osTokenFeePercent, - networkConfig.osTokenCapacity, - ]) - const osTokenVaultControllerAddress = await osTokenVaultController.getAddress() - - // Deploy OsToken - const osToken = await deployContract(hre, 'OsToken', [ - governor, - osTokenVaultControllerAddress, - networkConfig.osTokenName, - networkConfig.osTokenSymbol, - ]) - if ((await osToken.getAddress()) !== osTokenAddress) { - throw new Error('OsToken address mismatch') - } - - // Deploy Keeper - const keeper = await deployContract(hre, 'Keeper', [ - sharedMevEscrowAddress, - vaultsRegistryAddress, - osTokenVaultControllerAddress, - networkConfig.rewardsDelay, - networkConfig.maxAvgRewardPerSecond, - validatorsRegistryAddress, - ]) - if ((await keeper.getAddress()) !== keeperAddress) { - throw new Error('Keeper address mismatch') - } - - // Configure Keeper - for (let i = 0; i < oracles.length; i++) { - const oracleAddr = oracles[i].address - await callContract(keeper.addOracle(oracleAddr)) - console.log('Added oracle', oracleAddr) - } - await callContract(keeper.updateConfig(networkConfig.oraclesConfigIpfsHash)) - console.log('Updated oracles config to', networkConfig.oraclesConfigIpfsHash) - - await callContract(keeper.setRewardsMinOracles(rewardsMinOracles)) - console.log('Set rewards min oracles to', rewardsMinOracles) - - await callContract(keeper.setValidatorsMinOracles(validatorsMinOracles)) - console.log('Set validators min oracles to', validatorsMinOracles) - - // Deploy OsTokenConfig - const osTokenConfig = await deployContract(hre, 'OsTokenConfig', [ - governor.address, - { - liqThresholdPercent: networkConfig.liqThresholdPercent, - liqBonusPercent: networkConfig.liqBonusPercent, - ltvPercent: networkConfig.ltvPercent, - }, - governor.address, - ]) - const osTokenConfigAddress = await osTokenConfig.getAddress() - - // Deploy DepositDataRegistry - const depositDataRegistry = await deployContract(hre, 'DepositDataRegistry', [ - vaultsRegistryAddress, - ]) - const depositDataRegistryAddress = await depositDataRegistry.getAddress() - - // Deploy ValidatorsChecker - const ethValidatorsChecker = await deployContract(hre, 'EthValidatorsChecker', [ - validatorsRegistryAddress, - keeperAddress, - vaultsRegistryAddress, - depositDataRegistryAddress, - ]) - const ethValidatorsCheckerAddress = await ethValidatorsChecker.getAddress() - - const factories: string[] = [] - for (const vaultType of [ - 'EthVault', - 'EthPrivVault', - 'EthBlocklistVault', - 'EthErc20Vault', - 'EthPrivErc20Vault', - 'EthBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - validatorsRegistryAddress, - osTokenVaultControllerAddress, - osTokenConfigAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract(hre, vaultType, constructorArgs) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // Deploy Vault Factory - const vaultFactory = await deployContract(hre, 'EthVaultFactory', [ - vaultImplAddress, - vaultsRegistryAddress, - ]) - const vaultFactoryAddress = await vaultFactory.getAddress() - - // Add factory to registry - await callContract(vaultsRegistry.addFactory(vaultFactoryAddress)) - console.log(`Added ${vaultType}Factory to VaultsRegistry`) - - // Add implementation to registry - await callContract(vaultsRegistry.addVaultImpl(vaultImplAddress)) - console.log(`Added ${vaultType} implementation to VaultsRegistry`) - factories.push(vaultFactoryAddress) - } - - // Deploy EthGenesisVault implementation - let constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - validatorsRegistryAddress, - osTokenVaultControllerAddress, - osTokenConfigAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.genesisVault.poolEscrow, - networkConfig.genesisVault.rewardToken, - networkConfig.exitedAssetsClaimDelay, - ] - const genesisVaultImpl = await deployContract(hre, 'EthGenesisVault', constructorArgs) - const genesisVaultImplAddress = await genesisVaultImpl.getAddress() - const genesisVaultFactory = await ethers.getContractFactory('EthGenesisVault') - await simulateDeployImpl(hre, genesisVaultFactory, { constructorArgs }, genesisVaultImplAddress) - - // Deploy and initialize EthGenesisVault proxy - let initCall = ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [ - networkConfig.genesisVault.admin, - [networkConfig.genesisVault.capacity, networkConfig.genesisVault.feePercent, ''], - ] - ) - let proxy = await deployContract( - hre, - 'ERC1967Proxy', - [ - genesisVaultImplAddress, - genesisVaultFactory.interface.encodeFunctionData('initialize', [initCall]), - ], - undefined, - { value: networkConfig.securityDeposit } - ) - const genesisVaultAddress = await proxy.getAddress() - - await callContract(vaultsRegistry.addVault(genesisVaultAddress)) - console.log('Added EthGenesisVault to VaultsRegistry') - - await callContract(vaultsRegistry.addVaultImpl(genesisVaultImplAddress)) - console.log('Added EthGenesisVault implementation to VaultsRegistry') - - // Deploy EthFoxVault implementation - constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const foxVaultImpl = await deployContract(hre, 'EthFoxVault', constructorArgs) - const foxVaultImplAddress = await foxVaultImpl.getAddress() - const foxVaultFactory = await ethers.getContractFactory('EthFoxVault') - await simulateDeployImpl(hre, foxVaultFactory, { constructorArgs }, foxVaultImplAddress) - - const foxVaultAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 1, - }) - - // Deploy ownMevEscrow for EthFoxVault - const ownMevEscrowFactory = await ethers.getContractFactory('OwnMevEscrow') - const ownMevEscrow = await ownMevEscrowFactory.deploy(foxVaultAddress) - - // Deploy and initialize EthFoxVault proxy - initCall = ethers.AbiCoder.defaultAbiCoder().encode( - [ - 'tuple(address admin, address ownMevEscrow, uint256 capacity, uint16 feePercent, string metadataIpfsHash)', - ], - [ - [ - networkConfig.foxVault.admin, - await ownMevEscrow.getAddress(), - networkConfig.foxVault.capacity, - networkConfig.foxVault.feePercent, - networkConfig.foxVault.metadataIpfsHash, - ], - ] - ) - - proxy = await deployContract( - hre, - 'ERC1967Proxy', - [foxVaultImplAddress, foxVaultFactory.interface.encodeFunctionData('initialize', [initCall])], - undefined, - { - value: networkConfig.securityDeposit, - } - ) - if ((await proxy.getAddress()) !== foxVaultAddress) { - throw new Error('EthFoxVault address mismatch') - } - - await callContract(vaultsRegistry.addVault(foxVaultAddress)) - console.log('Added EthFoxVault to VaultsRegistry') - - // Deploy PriceFeed - const priceFeed = await deployContract(hre, 'PriceFeed', [ - osTokenVaultControllerAddress, - networkConfig.priceFeedDescription, - ]) - const priceFeedAddress = await priceFeed.getAddress() - - // Deploy RewardSplitter Implementation - const rewardSplitterImpl = await deployContract(hre, 'RewardSplitter', []) - const rewardSplitterImplAddress = await rewardSplitterImpl.getAddress() - - // Deploy RewardSplitter factory - const rewardSplitterFactory = await deployContract(hre, 'RewardSplitterFactory', [ - rewardSplitterImplAddress, - ]) - const rewardSplitterFactoryAddress = await rewardSplitterFactory.getAddress() - - // transfer ownership to governor - await callContract(vaultsRegistry.initialize(networkConfig.governor)) - console.log('VaultsRegistry ownership transferred to', networkConfig.governor) - - await callContract(keeper.initialize(networkConfig.governor)) - console.log('Keeper ownership transferred to', networkConfig.governor) - - // Save the addresses - const addresses = { - VaultsRegistry: vaultsRegistryAddress, - Keeper: keeperAddress, - DepositDataRegistry: depositDataRegistryAddress, - EthValidatorsChecker: ethValidatorsCheckerAddress, - EthFoxVault: foxVaultAddress, - EthVaultFactory: factories[0], - EthPrivVaultFactory: factories[1], - EthBlocklistVaultFactory: factories[2], - EthErc20VaultFactory: factories[3], - EthPrivErc20VaultFactory: factories[4], - EthBlocklistErc20VaultFactory: factories[5], - SharedMevEscrow: sharedMevEscrowAddress, - OsToken: osTokenAddress, - OsTokenConfig: osTokenConfigAddress, - OsTokenVaultController: osTokenVaultControllerAddress, - PriceFeed: priceFeedAddress, - RewardSplitterFactory: rewardSplitterFactoryAddress, - } - const json = JSON.stringify(addresses, null, 2) - const fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` - - if (!fs.existsSync(DEPLOYMENTS_DIR)) { - fs.mkdirSync(DEPLOYMENTS_DIR) - } - - // save addresses - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Addresses saved to', fileName) - - console.log( - 'NB! EthGenesisVault is not configured properly as ' + - 'it requires StakeWise V2 tokens and PoolEscrow contracts' - ) - } -) diff --git a/tasks/eth-full-deploy.ts b/tasks/eth-full-deploy.ts deleted file mode 100644 index 8f4afca0..00000000 --- a/tasks/eth-full-deploy.ts +++ /dev/null @@ -1,388 +0,0 @@ -import fs from 'fs' -import '@openzeppelin/hardhat-upgrades/dist/type-extensions' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import { task } from 'hardhat/config' -import { deployContract, callContract } from '../helpers/utils' -import { NETWORKS } from '../helpers/constants' -import { NetworkConfig } from '../helpers/types' - -const DEPLOYMENTS_DIR = 'deployments' - -task('eth-full-deploy', 'deploys StakeWise V3 for Ethereum').setAction(async (taskArgs, hre) => { - const ethers = hre.ethers - const networkName = hre.network.name - const networkConfig: NetworkConfig = NETWORKS[networkName] - const deployer = await ethers.provider.getSigner() - - if (networkConfig.foxVault === undefined) { - throw new Error('FoxVault config is missing') - } - - // Create the signer for the mnemonic - console.log('Deploying StakeWise V3 for Ethereum to', networkName, 'from', deployer.address) - - // deploy VaultsRegistry - const vaultsRegistry = await deployContract( - hre, - 'VaultsRegistry', - [], - 'contracts/vaults/VaultsRegistry.sol:VaultsRegistry' - ) - const vaultsRegistryAddress = await vaultsRegistry.getAddress() - - // deploy SharedMevEscrow - const sharedMevEscrow = await deployContract( - hre, - 'SharedMevEscrow', - [vaultsRegistryAddress], - 'contracts/vaults/ethereum/mev/SharedMevEscrow.sol:SharedMevEscrow' - ) - const sharedMevEscrowAddress = await sharedMevEscrow.getAddress() - - // calculate osToken and keeper addresses - const osTokenAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 1, - }) - const keeperAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 2, - }) - - // deploy OsTokenVaultController - const osTokenVaultController = await deployContract( - hre, - 'OsTokenVaultController', - [ - keeperAddress, - vaultsRegistryAddress, - osTokenAddress, - networkConfig.treasury, - networkConfig.governor, - networkConfig.osTokenFeePercent, - networkConfig.osTokenCapacity, - ], - 'contracts/tokens/OsTokenVaultController.sol:OsTokenVaultController' - ) - const osTokenVaultControllerAddress = await osTokenVaultController.getAddress() - - // Deploy OsToken - const osToken = await deployContract( - hre, - 'OsToken', - [ - networkConfig.governor, - osTokenVaultControllerAddress, - networkConfig.osTokenName, - networkConfig.osTokenSymbol, - ], - 'contracts/tokens/OsToken.sol:OsToken' - ) - if ((await osToken.getAddress()) !== osTokenAddress) { - throw new Error('OsToken address mismatch') - } - - // Deploy Keeper - const keeper = await deployContract( - hre, - 'Keeper', - [ - sharedMevEscrowAddress, - vaultsRegistryAddress, - osTokenVaultControllerAddress, - networkConfig.rewardsDelay, - networkConfig.maxAvgRewardPerSecond, - networkConfig.validatorsRegistry, - ], - 'contracts/keeper/Keeper.sol:Keeper' - ) - if ((await keeper.getAddress()) !== keeperAddress) { - throw new Error('Keeper address mismatch') - } - - // Configure Keeper - for (let i = 0; i < networkConfig.oracles.length; i++) { - const oracleAddr = networkConfig.oracles[i] - await callContract(keeper.addOracle(oracleAddr)) - console.log('Added oracle', oracleAddr) - } - await callContract(keeper.updateConfig(networkConfig.oraclesConfigIpfsHash)) - console.log('Updated oracles config to', networkConfig.oraclesConfigIpfsHash) - - await callContract(keeper.setRewardsMinOracles(networkConfig.rewardsMinOracles)) - console.log('Set rewards min oracles to', networkConfig.rewardsMinOracles) - - await callContract(keeper.setValidatorsMinOracles(networkConfig.validatorsMinOracles)) - console.log('Set validators min oracles to', networkConfig.validatorsMinOracles) - - // Deploy OsTokenConfig - const osTokenConfig = await deployContract( - hre, - 'OsTokenConfig', - [ - networkConfig.governor, - { - liqThresholdPercent: networkConfig.liqThresholdPercent, - liqBonusPercent: networkConfig.liqBonusPercent, - ltvPercent: networkConfig.ltvPercent, - }, - networkConfig.governor, - ], - 'contracts/tokens/OsTokenConfig.sol:OsTokenConfig' - ) - const osTokenConfigAddress = await osTokenConfig.getAddress() - - // Deploy DepositDataRegistry - const depositDataRegistry = await deployContract( - hre, - 'DepositDataRegistry', - [vaultsRegistryAddress], - 'contracts/validators/DepositDataRegistry.sol:DepositDataRegistry' - ) - const depositDataRegistryAddress = await depositDataRegistry.getAddress() - - // Deploy ValidatorsChecker - const ethValidatorsChecker = await deployContract( - hre, - 'EthValidatorsChecker', - [ - networkConfig.validatorsRegistry, - keeperAddress, - vaultsRegistryAddress, - depositDataRegistryAddress, - ], - 'contracts/validators/EthValidatorsChecker.sol:EthValidatorsChecker' - ) - const ethValidatorsCheckerAddress = await ethValidatorsChecker.getAddress() - - const factories: string[] = [] - for (const vaultType of [ - 'EthVault', - 'EthPrivVault', - 'EthBlocklistVault', - 'EthErc20Vault', - 'EthPrivErc20Vault', - 'EthBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract( - hre, - vaultType, - constructorArgs, - `contracts/vaults/ethereum/${vaultType}.sol:${vaultType}` - ) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // Deploy Vault Factory - const vaultFactory = await deployContract( - hre, - 'EthVaultFactory', - [vaultImplAddress, vaultsRegistryAddress], - 'contracts/vaults/ethereum/EthVaultFactory.sol:EthVaultFactory' - ) - const vaultFactoryAddress = await vaultFactory.getAddress() - - // Add factory to registry - await callContract(vaultsRegistry.addFactory(vaultFactoryAddress)) - console.log(`Added ${vaultType}Factory to VaultsRegistry`) - - // Add implementation to registry - await callContract(vaultsRegistry.addVaultImpl(vaultImplAddress)) - console.log(`Added ${vaultType} implementation to VaultsRegistry`) - factories.push(vaultFactoryAddress) - } - - // Deploy EthGenesisVault implementation - let constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.genesisVault.poolEscrow, - networkConfig.genesisVault.rewardToken, - networkConfig.exitedAssetsClaimDelay, - ] - const genesisVaultImpl = await deployContract( - hre, - 'EthGenesisVault', - constructorArgs, - 'contracts/vaults/ethereum/EthGenesisVault.sol:EthGenesisVault' - ) - const genesisVaultImplAddress = await genesisVaultImpl.getAddress() - const genesisVaultFactory = await ethers.getContractFactory('EthGenesisVault') - await simulateDeployImpl(hre, genesisVaultFactory, { constructorArgs }, genesisVaultImplAddress) - - // Deploy and initialize EthGenesisVault proxy - let initCall = ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [ - networkConfig.genesisVault.admin, - [networkConfig.genesisVault.capacity, networkConfig.genesisVault.feePercent, ''], - ] - ) - let proxy = await deployContract( - hre, - 'ERC1967Proxy', - [ - genesisVaultImplAddress, - genesisVaultFactory.interface.encodeFunctionData('initialize', [initCall]), - ], - '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy', - { value: networkConfig.securityDeposit } - ) - const genesisVaultAddress = await proxy.getAddress() - - await callContract(vaultsRegistry.addVault(genesisVaultAddress)) - console.log('Added EthGenesisVault to VaultsRegistry') - - await callContract(vaultsRegistry.addVaultImpl(genesisVaultImplAddress)) - console.log(`Added EthGenesisVault implementation to VaultsRegistry`) - - // Deploy EthFoxVault implementation - constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const foxVaultImpl = await deployContract( - hre, - 'EthFoxVault', - constructorArgs, - 'contracts/vaults/ethereum/custom/EthFoxVault.sol:EthFoxVault' - ) - const foxVaultImplAddress = await foxVaultImpl.getAddress() - const foxVaultFactory = await ethers.getContractFactory('EthFoxVault') - await simulateDeployImpl(hre, foxVaultFactory, { constructorArgs }, foxVaultImplAddress) - - // calculate EthFoxVault address - const foxVaultAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 1, - }) - - // Deploy OwnMevEscrow for EthFoxVault - const ownMevEscrowFactory = await ethers.getContractFactory('OwnMevEscrow') - const ownMevEscrow = await ownMevEscrowFactory.deploy(foxVaultAddress) - - // Deploy and initialize EthFoxVault proxy - initCall = ethers.AbiCoder.defaultAbiCoder().encode( - [ - 'tuple(address admin, address ownMevEscrow, uint256 capacity, uint16 feePercent, string metadataIpfsHash)', - ], - [ - [ - networkConfig.foxVault.admin, - await ownMevEscrow.getAddress(), - networkConfig.foxVault.capacity, - networkConfig.foxVault.feePercent, - networkConfig.foxVault.metadataIpfsHash, - ], - ] - ) - - proxy = await deployContract( - hre, - 'ERC1967Proxy', - [foxVaultImplAddress, foxVaultFactory.interface.encodeFunctionData('initialize', [initCall])], - '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy', - { - value: networkConfig.securityDeposit, - } - ) - if ((await proxy.getAddress()) !== foxVaultAddress) { - throw new Error('EthFoxVault address mismatch') - } - - await callContract(vaultsRegistry.addVault(foxVaultAddress)) - console.log('Added EthFoxVault to VaultsRegistry') - - // Deploy PriceFeed - const priceFeed = await deployContract( - hre, - 'PriceFeed', - [osTokenVaultControllerAddress, networkConfig.priceFeedDescription], - 'contracts/tokens/PriceFeed.sol:PriceFeed' - ) - const priceFeedAddress = await priceFeed.getAddress() - - // Deploy RewardSplitter Implementation - const rewardSplitterImpl = await deployContract( - hre, - 'RewardSplitter', - [], - 'contracts/misc/RewardSplitter.sol:RewardSplitter' - ) - const rewardSplitterImplAddress = await rewardSplitterImpl.getAddress() - - // Deploy RewardSplitter factory - const rewardSplitterFactory = await deployContract( - hre, - 'RewardSplitterFactory', - [rewardSplitterImplAddress], - 'contracts/misc/RewardSplitterFactory.sol:RewardSplitterFactory' - ) - const rewardSplitterFactoryAddress = await rewardSplitterFactory.getAddress() - - // transfer ownership to governor - await callContract(vaultsRegistry.initialize(networkConfig.governor)) - console.log('VaultsRegistry ownership transferred to', networkConfig.governor) - - await callContract(keeper.initialize(networkConfig.governor)) - console.log('Keeper ownership transferred to', networkConfig.governor) - - // Save the addresses - const addresses = { - VaultsRegistry: vaultsRegistryAddress, - Keeper: keeperAddress, - DepositDataRegistry: depositDataRegistryAddress, - EthValidatorsChecker: ethValidatorsCheckerAddress, - EthGenesisVault: genesisVaultAddress, - EthFoxVault: foxVaultAddress, - EthVaultFactory: factories[0], - EthPrivVaultFactory: factories[1], - EthBlocklistVaultFactory: factories[2], - EthErc20VaultFactory: factories[3], - EthPrivErc20VaultFactory: factories[4], - EthBlocklistErc20VaultFactory: factories[5], - SharedMevEscrow: sharedMevEscrowAddress, - OsToken: osTokenAddress, - OsTokenConfig: osTokenConfigAddress, - OsTokenVaultController: osTokenVaultControllerAddress, - PriceFeed: priceFeedAddress, - RewardSplitterFactory: rewardSplitterFactoryAddress, - } - const json = JSON.stringify(addresses, null, 2) - const fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` - - if (!fs.existsSync(DEPLOYMENTS_DIR)) { - fs.mkdirSync(DEPLOYMENTS_DIR) - } - - // save addresses - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Addresses saved to', fileName) - - console.log('NB! Commit and accept StakeWise V2 PoolEscrow ownership to EthGenesisVault') -}) diff --git a/tasks/eth-upgrade.ts b/tasks/eth-upgrade.ts deleted file mode 100644 index 09a812ad..00000000 --- a/tasks/eth-upgrade.ts +++ /dev/null @@ -1,182 +0,0 @@ -import fs from 'fs' -import '@openzeppelin/hardhat-upgrades/dist/type-extensions' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import { task } from 'hardhat/config' -import { deployContract, encodeGovernorContractCall } from '../helpers/utils' -import { NETWORKS } from '../helpers/constants' -import { GovernorCall, NetworkConfig } from '../helpers/types' - -const DEPLOYMENTS_DIR = 'deployments' - -task('eth-upgrade', 'upgrades StakeWise for Ethereum').setAction(async (taskArgs, hre) => { - const ethers = hre.ethers - const networkName = hre.network.name - const networkConfig: NetworkConfig = NETWORKS[networkName] - const deployer = await ethers.provider.getSigner() - - if (networkConfig.foxVault === undefined) { - throw new Error('FoxVault config is missing') - } - - // Create the signer for the mnemonic - console.log('Upgrading StakeWise V3 for Ethereum to', networkName, 'from', deployer.address) - - const { default: deployment } = await import(`../${DEPLOYMENTS_DIR}/${networkName}.json`) - - // read addresses - const vaultsRegistryAddress = deployment.VaultsRegistry - const sharedMevEscrowAddress = deployment.SharedMevEscrow - const osTokenAddress = deployment.OsToken - const keeperAddress = deployment.Keeper - const osTokenVaultControllerAddress = deployment.OsTokenVaultController - const genesisVaultAddress = deployment.EthGenesisVault - const foxVaultAddress = deployment.EthFoxVault - const priceFeedAddress = deployment.PriceFeed - const osTokenConfigAddress = deployment.OsTokenConfig - const depositDataRegistryAddress = deployment.DepositDataRegistry - const ethValidatorsCheckerAddress = deployment.EthValidatorsChecker - const rewardSplitterFactoryAddress = deployment.RewardSplitterFactory - const osTokenVaultEscrowAddress = deployment.EthOsTokenVaultEscrow - const osTokenFlashLoansAddress = deployment.OsTokenFlashLoans - - // accumulate governor transaction - const governorTransaction: GovernorCall[] = [] - const vaultUpgrades: Record> = {} - const vaultsRegistry = await ethers.getContractAt('VaultsRegistry', vaultsRegistryAddress) - - for (const vaultType of [ - 'EthVault', - 'EthPrivVault', - 'EthBlocklistVault', - 'EthErc20Vault', - 'EthPrivErc20Vault', - 'EthBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - osTokenVaultEscrowAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract( - hre, - vaultType, - constructorArgs, - `contracts/vaults/ethereum/${vaultType}.sol:${vaultType}` - ) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // add vault implementation updates - const vault = await ethers.getContractAt('EthVault', vaultImplAddress) - const vaultId = await vault.vaultId() - if (!(vaultId in vaultUpgrades)) { - vaultUpgrades[vaultId] = {} - } - const vaultVersion = await vault.version() - vaultUpgrades[vaultId][vaultVersion.toString()] = vaultImplAddress - - // encode governor calls - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'addVaultImpl(address)', [vaultImplAddress]) - ) - } - - // Deploy EthGenesisVault implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - osTokenVaultEscrowAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.genesisVault.poolEscrow, - networkConfig.genesisVault.rewardToken, - networkConfig.exitedAssetsClaimDelay, - ] - const genesisVaultImpl = await deployContract( - hre, - 'EthGenesisVault', - constructorArgs, - 'contracts/vaults/ethereum/EthGenesisVault.sol:EthGenesisVault' - ) - const genesisVaultImplAddress = await genesisVaultImpl.getAddress() - const genesisVaultFactory = await ethers.getContractFactory('EthGenesisVault') - await simulateDeployImpl(hre, genesisVaultFactory, { constructorArgs }, genesisVaultImplAddress) - - // add vault implementation update - const vault = await ethers.getContractAt('EthVault', genesisVaultImplAddress) - const vaultId = await vault.vaultId() - if (!(vaultId in vaultUpgrades)) { - vaultUpgrades[vaultId] = {} - } - const vaultVersion = await vault.version() - vaultUpgrades[vaultId][vaultVersion.toString()] = genesisVaultImplAddress - - // encode governor calls - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'addVaultImpl(address)', [ - genesisVaultImplAddress, - ]) - ) - console.log(`NB! Upgrade EthGenesisVault to V4: ${genesisVaultImplAddress}`) - - // Save the addresses - const addresses = { - VaultsRegistry: vaultsRegistryAddress, - Keeper: keeperAddress, - DepositDataRegistry: depositDataRegistryAddress, - EthValidatorsChecker: ethValidatorsCheckerAddress, - EthGenesisVault: genesisVaultAddress, - EthFoxVault: foxVaultAddress, - EthVaultFactory: deployment.EthVaultFactory, - EthPrivVaultFactory: deployment.EthPrivVaultFactory, - EthBlocklistVaultFactory: deployment.EthBlocklistVaultFactory, - EthErc20VaultFactory: deployment.EthErc20VaultFactory, - EthPrivErc20VaultFactory: deployment.EthPrivErc20VaultFactory, - EthBlocklistErc20VaultFactory: deployment.EthBlocklistErc20VaultFactory, - SharedMevEscrow: sharedMevEscrowAddress, - OsToken: osTokenAddress, - OsTokenConfig: osTokenConfigAddress, - OsTokenVaultController: osTokenVaultControllerAddress, - EthOsTokenVaultEscrow: osTokenVaultEscrowAddress, - OsTokenFlashLoans: osTokenFlashLoansAddress, - PriceFeed: priceFeedAddress, - RewardSplitterFactory: rewardSplitterFactoryAddress, - } - let json = JSON.stringify(addresses, null, 2) - let fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` - - if (!fs.existsSync(DEPLOYMENTS_DIR)) { - fs.mkdirSync(DEPLOYMENTS_DIR) - } - - // save addresses - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Addresses saved to', fileName) - - // save governor transactions - json = JSON.stringify(governorTransaction, null, 2) - fileName = `${DEPLOYMENTS_DIR}/${networkName}-upgrade-v4-tx.json` - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Governor transaction saved to', fileName) - - // save vault upgrades - json = JSON.stringify(vaultUpgrades, null, 2) - fileName = `${DEPLOYMENTS_DIR}/${networkName}-vault-v4-upgrades.json` - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Vault upgrades saved to', fileName) -}) diff --git a/tasks/gno-full-deploy.ts b/tasks/gno-full-deploy.ts deleted file mode 100644 index 4612e4b8..00000000 --- a/tasks/gno-full-deploy.ts +++ /dev/null @@ -1,382 +0,0 @@ -import fs from 'fs' -import '@openzeppelin/hardhat-upgrades/dist/type-extensions' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import { task } from 'hardhat/config' -import { deployContract, callContract } from '../helpers/utils' -import { NETWORKS } from '../helpers/constants' -import { NetworkConfig } from '../helpers/types' - -const DEPLOYMENTS_DIR = 'deployments' - -task('gno-full-deploy', 'deploys StakeWise V3 for Gnosis').setAction(async (taskArgs, hre) => { - const ethers = hre.ethers - const networkName = hre.network.name - const networkConfig: NetworkConfig = NETWORKS[networkName] - const deployer = await ethers.provider.getSigner() - - if (networkConfig.gnosis === undefined) { - throw new Error('Gnosis data is required for this network') - } - - // Create the signer for the mnemonic - console.log('Deploying StakeWise V3 for Gnosis to', networkName, 'from', deployer.address) - - // deploy VaultsRegistry - const vaultsRegistry = await deployContract( - hre, - 'VaultsRegistry', - [], - 'contracts/vaults/VaultsRegistry.sol:VaultsRegistry' - ) - const vaultsRegistryAddress = await vaultsRegistry.getAddress() - - // deploy SharedMevEscrow - const sharedMevEscrow = await deployContract( - hre, - 'GnoSharedMevEscrow', - [vaultsRegistryAddress], - 'contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol:GnoSharedMevEscrow' - ) - const sharedMevEscrowAddress = await sharedMevEscrow.getAddress() - - // calculate osToken and keeper addresses - const osTokenAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 1, - }) - const keeperAddress = ethers.getCreateAddress({ - from: deployer.address, - nonce: (await ethers.provider.getTransactionCount(deployer.address)) + 2, - }) - - // deploy OsTokenVaultController - const osTokenVaultController = await deployContract( - hre, - 'OsTokenVaultController', - [ - keeperAddress, - vaultsRegistryAddress, - osTokenAddress, - networkConfig.treasury, - networkConfig.governor, - networkConfig.osTokenFeePercent, - networkConfig.osTokenCapacity, - ], - 'contracts/tokens/OsTokenVaultController.sol:OsTokenVaultController' - ) - const osTokenVaultControllerAddress = await osTokenVaultController.getAddress() - - // Deploy OsToken - const osToken = await deployContract( - hre, - 'OsToken', - [ - networkConfig.governor, - osTokenVaultControllerAddress, - networkConfig.osTokenName, - networkConfig.osTokenSymbol, - ], - 'contracts/tokens/OsToken.sol:OsToken' - ) - if ((await osToken.getAddress()) !== osTokenAddress) { - throw new Error('OsToken address mismatch') - } - - // Deploy Keeper - const keeper = await deployContract( - hre, - 'Keeper', - [ - sharedMevEscrowAddress, - vaultsRegistryAddress, - osTokenVaultControllerAddress, - networkConfig.rewardsDelay, - networkConfig.maxAvgRewardPerSecond, - networkConfig.validatorsRegistry, - ], - 'contracts/keeper/Keeper.sol:Keeper' - ) - if ((await keeper.getAddress()) !== keeperAddress) { - throw new Error('Keeper address mismatch') - } - - // Configure Keeper - for (let i = 0; i < networkConfig.oracles.length; i++) { - const oracleAddr = networkConfig.oracles[i] - await callContract(keeper.addOracle(oracleAddr)) - console.log('Added oracle', oracleAddr) - } - await callContract(keeper.updateConfig(networkConfig.oraclesConfigIpfsHash)) - console.log('Updated oracles config to', networkConfig.oraclesConfigIpfsHash) - - await callContract(keeper.setRewardsMinOracles(networkConfig.rewardsMinOracles)) - console.log('Set rewards min oracles to', networkConfig.rewardsMinOracles) - - await callContract(keeper.setValidatorsMinOracles(networkConfig.validatorsMinOracles)) - console.log('Set validators min oracles to', networkConfig.validatorsMinOracles) - - // Deploy OsTokenConfig - const osTokenConfig = await deployContract( - hre, - 'OsTokenConfig', - [ - networkConfig.governor, - { - liqThresholdPercent: networkConfig.liqThresholdPercent, - liqBonusPercent: networkConfig.liqBonusPercent, - ltvPercent: networkConfig.ltvPercent, - }, - networkConfig.governor, - ], - 'contracts/tokens/OsTokenConfig.sol:OsTokenConfig' - ) - const osTokenConfigAddress = await osTokenConfig.getAddress() - - // Deploy DepositDataRegistry - const depositDataRegistry = await deployContract( - hre, - 'DepositDataRegistry', - [vaultsRegistryAddress], - 'contracts/validators/DepositDataRegistry.sol:DepositDataRegistry' - ) - const depositDataRegistryAddress = await depositDataRegistry.getAddress() - - // Deploy ValidatorsChecker - const gnoValidatorsChecker = await deployContract( - hre, - 'GnoValidatorsChecker', - [ - networkConfig.validatorsRegistry, - keeperAddress, - vaultsRegistryAddress, - depositDataRegistryAddress, - ], - 'contracts/validators/GnoValidatorsChecker.sol:GnoValidatorsChecker' - ) - const gnoValidatorsCheckerAddress = await gnoValidatorsChecker.getAddress() - - // Deploy XdaiExchange implementation - const xdaiExchangeConstructorArgs = [ - networkConfig.gnosis.gnoToken, - networkConfig.gnosis.balancerVault, - vaultsRegistryAddress, - networkConfig.gnosis.daiPriceFeed, - networkConfig.gnosis.gnoPriceFeed, - ] - const xDaiExchangeImpl = await deployContract( - hre, - 'XdaiExchange', - xdaiExchangeConstructorArgs, - 'contracts/misc/XdaiExchange.sol:XdaiExchange' - ) - const xDaiExchangeImplAddress = await xDaiExchangeImpl.getAddress() - const xDaiExchangeFactory = await ethers.getContractFactory('XdaiExchange') - await simulateDeployImpl( - hre, - xDaiExchangeFactory, - { constructorArgs: xdaiExchangeConstructorArgs }, - xDaiExchangeImplAddress - ) - - // Deploy and initialize XdaiExchange proxy - let proxy = await deployContract( - hre, - 'ERC1967Proxy', - [ - xDaiExchangeImplAddress, - xDaiExchangeFactory.interface.encodeFunctionData('initialize', [ - networkConfig.governor, - networkConfig.gnosis.maxSlippage, - networkConfig.gnosis.stalePriceTimeDelta, - networkConfig.gnosis.balancerPoolId, - ]), - ], - '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy' - ) - const xdaiExchangeAddress = await proxy.getAddress() - - const factories: string[] = [] - for (const vaultType of [ - 'GnoVault', - 'GnoPrivVault', - 'GnoBlocklistVault', - 'GnoErc20Vault', - 'GnoPrivErc20Vault', - 'GnoBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.gnosis.gnoToken, - xdaiExchangeAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract( - hre, - vaultType, - constructorArgs, - `contracts/vaults/gnosis/${vaultType}.sol:${vaultType}` - ) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // Deploy Vault Factory - const vaultFactory = await deployContract( - hre, - 'GnoVaultFactory', - [vaultImplAddress, vaultsRegistryAddress, networkConfig.gnosis.gnoToken], - 'contracts/vaults/gnosis/GnoVaultFactory.sol:GnoVaultFactory' - ) - const vaultFactoryAddress = await vaultFactory.getAddress() - - // Add factory to registry - await callContract(vaultsRegistry.addFactory(vaultFactoryAddress)) - console.log(`Added ${vaultType}Factory to VaultsRegistry`) - - // Add implementation to registry - await callContract(vaultsRegistry.addVaultImpl(vaultImplAddress)) - console.log(`Added ${vaultType} implementation to VaultsRegistry`) - factories.push(vaultFactoryAddress) - } - - // Deploy GnoGenesisVault implementation - const genesisVaultConstructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.gnosis.gnoToken, - xdaiExchangeAddress, - networkConfig.genesisVault.poolEscrow, - networkConfig.genesisVault.rewardToken, - networkConfig.exitedAssetsClaimDelay, - ] - const genesisVaultImpl = await deployContract( - hre, - 'GnoGenesisVault', - genesisVaultConstructorArgs, - 'contracts/vaults/gnosis/GnoGenesisVault.sol:GnoGenesisVault' - ) - const genesisVaultImplAddress = await genesisVaultImpl.getAddress() - const genesisVaultFactory = await ethers.getContractFactory('GnoGenesisVault') - await simulateDeployImpl( - hre, - genesisVaultFactory, - { constructorArgs: genesisVaultConstructorArgs }, - genesisVaultImplAddress - ) - - // Deploy GnoGenesisVault proxy - proxy = await deployContract( - hre, - 'ERC1967Proxy', - [genesisVaultImplAddress, '0x'], - '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy' - ) - const genesisVaultAddress = await proxy.getAddress() - const genesisVault = genesisVaultFactory.attach(genesisVaultAddress) - - // Initialize GnoGenesisVault - const erc20TokenFactory = await ethers.getContractFactory('ERC20Mock') - const erc20Token = erc20TokenFactory.attach(networkConfig.gnosis.gnoToken) - await callContract(erc20Token.approve(genesisVaultAddress, networkConfig.securityDeposit)) - await callContract( - genesisVault.initialize( - ethers.AbiCoder.defaultAbiCoder().encode( - ['address', 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)'], - [ - networkConfig.genesisVault.admin, - [networkConfig.genesisVault.capacity, networkConfig.genesisVault.feePercent, ''], - ] - ) - ) - ) - - await callContract(vaultsRegistry.addVault(genesisVaultAddress)) - console.log('Added GnoGenesisVault to VaultsRegistry') - - await callContract(vaultsRegistry.addVaultImpl(genesisVaultImplAddress)) - console.log(`Added GnoGenesisVault implementation to VaultsRegistry`) - - // Deploy PriceFeed - const priceFeed = await deployContract( - hre, - 'PriceFeed', - [osTokenVaultControllerAddress, networkConfig.priceFeedDescription], - 'contracts/tokens/PriceFeed.sol:PriceFeed' - ) - const priceFeedAddress = await priceFeed.getAddress() - - // Deploy RewardSplitter Implementation - const rewardSplitterImpl = await deployContract( - hre, - 'RewardSplitter', - [], - 'contracts/misc/RewardSplitter.sol:RewardSplitter' - ) - const rewardSplitterImplAddress = await rewardSplitterImpl.getAddress() - - // Deploy RewardSplitter factory - const rewardSplitterFactory = await deployContract( - hre, - 'RewardSplitterFactory', - [rewardSplitterImplAddress], - 'contracts/misc/RewardSplitterFactory.sol:RewardSplitterFactory' - ) - const rewardSplitterFactoryAddress = await rewardSplitterFactory.getAddress() - - // transfer ownership to governor - await callContract(vaultsRegistry.initialize(networkConfig.governor)) - console.log('VaultsRegistry ownership transferred to', networkConfig.governor) - - await callContract(keeper.initialize(networkConfig.governor)) - console.log('Keeper ownership transferred to', networkConfig.governor) - - // Save the addresses - const addresses = { - VaultsRegistry: vaultsRegistryAddress, - Keeper: keeperAddress, - DepositDataRegistry: depositDataRegistryAddress, - GnoValidatorsChecker: gnoValidatorsCheckerAddress, - XdaiExchange: xdaiExchangeAddress, - GnoGenesisVault: genesisVaultAddress, - GnoVaultFactory: factories[0], - GnoPrivVaultFactory: factories[1], - GnoBlocklistVaultFactory: factories[2], - GnoErc20VaultFactory: factories[3], - GnoPrivErc20VaultFactory: factories[4], - GnoBlocklistErc20VaultFactory: factories[5], - SharedMevEscrow: sharedMevEscrowAddress, - OsToken: osTokenAddress, - OsTokenConfig: osTokenConfigAddress, - OsTokenVaultController: osTokenVaultControllerAddress, - PriceFeed: priceFeedAddress, - RewardSplitterFactory: rewardSplitterFactoryAddress, - } - const json = JSON.stringify(addresses, null, 2) - const fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` - - if (!fs.existsSync(DEPLOYMENTS_DIR)) { - fs.mkdirSync(DEPLOYMENTS_DIR) - } - - // save addresses - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Addresses saved to', fileName) - - console.log('NB! Commit and accept StakeWise V2 PoolEscrow ownership to GnoGenesisVault') -}) diff --git a/tasks/gno-upgrade.ts b/tasks/gno-upgrade.ts deleted file mode 100644 index 71b6ad79..00000000 --- a/tasks/gno-upgrade.ts +++ /dev/null @@ -1,247 +0,0 @@ -import fs from 'fs' -import '@openzeppelin/hardhat-upgrades/dist/type-extensions' -import { simulateDeployImpl } from '@openzeppelin/hardhat-upgrades/dist/utils' -import { task } from 'hardhat/config' -import { deployContract, encodeGovernorContractCall } from '../helpers/utils' -import { NETWORKS } from '../helpers/constants' -import { GovernorCall, NetworkConfig } from '../helpers/types' - -const DEPLOYMENTS_DIR = 'deployments' - -task('gno-upgrade', 'upgrades StakeWise for Gnosis').setAction(async (taskArgs, hre) => { - const ethers = hre.ethers - const networkName = hre.network.name - const networkConfig: NetworkConfig = NETWORKS[networkName] - const deployer = await ethers.provider.getSigner() - - if (networkConfig.gnosis === undefined) { - throw new Error('Gnosis data is required for this network') - } - - // Create the signer for the mnemonic - console.log('Upgrading StakeWise V3 for Gnosis to', networkName, 'from', deployer.address) - - const { default: deployment } = await import(`../${DEPLOYMENTS_DIR}/${networkName}.json`) - - // read addresses - const vaultsRegistryAddress = deployment.VaultsRegistry - const keeperAddress = deployment.Keeper - const depositDataRegistryAddress = deployment.DepositDataRegistry - const gnoValidatorsCheckerAddress = deployment.GnoValidatorsChecker - const xdaiExchangeAddress = deployment.XdaiExchange - const genesisVaultAddress = deployment.GnoGenesisVault - const sharedMevEscrowAddress = deployment.SharedMevEscrow - const osTokenAddress = deployment.OsToken - const osTokenConfigAddress = deployment.OsTokenConfig - const osTokenVaultControllerAddress = deployment.OsTokenVaultController - const priceFeedAddress = deployment.PriceFeed - const rewardSplitterFactoryAddress = deployment.RewardSplitterFactory - - // accumulate governor transaction - const governorTransaction: GovernorCall[] = [] - const vaultUpgrades: Record> = {} - const vaultsRegistry = await ethers.getContractAt('VaultsRegistry', vaultsRegistryAddress) - const osToken = await ethers.getContractAt('OsToken', osTokenAddress) - - // Deploy GnoOsTokenVaultEscrow - const osTokenVaultEscrow = await deployContract( - hre, - 'GnoOsTokenVaultEscrow', - [ - osTokenVaultControllerAddress, - osTokenConfigAddress, - networkConfig.governor, - networkConfig.osTokenVaultEscrow.authenticator, - networkConfig.osTokenVaultEscrow.liqThresholdPercent, - networkConfig.osTokenVaultEscrow.liqBonusPercent, - networkConfig.gnosis.gnoToken, - ], - 'contracts/tokens/GnoOsTokenVaultEscrow.sol:GnoOsTokenVaultEscrow' - ) - const osTokenVaultEscrowAddress = await osTokenVaultEscrow.getAddress() - - // encode governor call to add escrow to the vaults registry - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'addVault(address)', [ - osTokenVaultEscrowAddress, - ]) - ) - - // Deploy OsTokenFlashLoans - const osTokenFlashLoans = await deployContract( - hre, - 'OsTokenFlashLoans', - [osTokenAddress], - 'contracts/tokens/OsTokenFlashLoans.sol:OsTokenFlashLoans' - ) - const osTokenFlashLoansAddress = await osTokenFlashLoans.getAddress() - - // encode governor call to add OsTokenFlashLoans as the OsToken controller - governorTransaction.push( - await encodeGovernorContractCall(osToken, 'setController(address,bool)', [ - osTokenFlashLoansAddress, - true, - ]) - ) - - const factories: string[] = [] - for (const vaultType of [ - 'GnoVault', - 'GnoPrivVault', - 'GnoBlocklistVault', - 'GnoErc20Vault', - 'GnoPrivErc20Vault', - 'GnoBlocklistErc20Vault', - ]) { - // Deploy Vault Implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - osTokenVaultEscrowAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.gnosis.gnoToken, - xdaiExchangeAddress, - networkConfig.exitedAssetsClaimDelay, - ] - const vaultImpl = await deployContract( - hre, - vaultType, - constructorArgs, - `contracts/vaults/gnosis/${vaultType}.sol:${vaultType}` - ) - const vaultImplAddress = await vaultImpl.getAddress() - await simulateDeployImpl( - hre, - await ethers.getContractFactory(vaultType), - { constructorArgs }, - vaultImplAddress - ) - - // Deploy Vault Factory - const vaultFactory = await deployContract( - hre, - 'GnoVaultFactory', - [vaultImplAddress, vaultsRegistryAddress, networkConfig.gnosis.gnoToken], - 'contracts/vaults/gnosis/GnoVaultFactory.sol:GnoVaultFactory' - ) - const vaultFactoryAddress = await vaultFactory.getAddress() - factories.push(vaultFactoryAddress) - - // add vault implementation updates - const vault = await ethers.getContractAt('GnoVault', vaultImplAddress) - const vaultId = await vault.vaultId() - if (!(vaultId in vaultUpgrades)) { - vaultUpgrades[vaultId] = {} - } - const vaultVersion = await vault.version() - vaultUpgrades[vaultId][vaultVersion.toString()] = vaultImplAddress - - // encode governor calls - if (vaultType + 'Factory' in deployment) { - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'removeFactory(address)', [ - deployment[vaultType + 'Factory'], - ]) - ) - } - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'addFactory(address)', [vaultFactoryAddress]) - ) - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'addVaultImpl(address)', [vaultImplAddress]) - ) - } - - // Deploy GnoGenesisVault implementation - const constructorArgs = [ - keeperAddress, - vaultsRegistryAddress, - networkConfig.validatorsRegistry, - osTokenVaultControllerAddress, - osTokenConfigAddress, - osTokenVaultEscrowAddress, - sharedMevEscrowAddress, - depositDataRegistryAddress, - networkConfig.gnosis.gnoToken, - xdaiExchangeAddress, - networkConfig.genesisVault.poolEscrow, - networkConfig.genesisVault.rewardToken, - networkConfig.exitedAssetsClaimDelay, - ] - const genesisVaultImpl = await deployContract( - hre, - 'GnoGenesisVault', - constructorArgs, - 'contracts/vaults/gnosis/GnoGenesisVault.sol:GnoGenesisVault' - ) - const genesisVaultImplAddress = await genesisVaultImpl.getAddress() - const genesisVaultFactory = await ethers.getContractFactory('GnoGenesisVault') - await simulateDeployImpl(hre, genesisVaultFactory, { constructorArgs }, genesisVaultImplAddress) - - // add vault implementation update - const vault = await ethers.getContractAt('GnoVault', genesisVaultImplAddress) - const vaultId = await vault.vaultId() - if (!(vaultId in vaultUpgrades)) { - vaultUpgrades[vaultId] = {} - } - const vaultVersion = await vault.version() - vaultUpgrades[vaultId][vaultVersion.toString()] = genesisVaultImplAddress - - // encode governor calls - governorTransaction.push( - await encodeGovernorContractCall(vaultsRegistry, 'addVaultImpl(address)', [ - genesisVaultImplAddress, - ]) - ) - console.log(`NB! Upgrade GnoGenesisVault to V3: ${genesisVaultImplAddress}`) - - // Save the addresses - const addresses = { - VaultsRegistry: vaultsRegistryAddress, - Keeper: keeperAddress, - DepositDataRegistry: depositDataRegistryAddress, - GnoValidatorsChecker: gnoValidatorsCheckerAddress, - XdaiExchange: xdaiExchangeAddress, - GnoGenesisVault: genesisVaultAddress, - GnoVaultFactory: factories[0], - GnoPrivVaultFactory: factories[1], - GnoBlocklistVaultFactory: factories[2], - GnoErc20VaultFactory: factories[3], - GnoPrivErc20VaultFactory: factories[4], - GnoBlocklistErc20VaultFactory: factories[5], - SharedMevEscrow: sharedMevEscrowAddress, - OsToken: osTokenAddress, - OsTokenConfig: osTokenConfigAddress, - OsTokenVaultController: osTokenVaultControllerAddress, - GnoOsTokenVaultEscrow: osTokenVaultEscrowAddress, - OsTokenFlashLoans: osTokenFlashLoansAddress, - PriceFeed: priceFeedAddress, - RewardSplitterFactory: rewardSplitterFactoryAddress, - } - let json = JSON.stringify(addresses, null, 2) - let fileName = `${DEPLOYMENTS_DIR}/${networkName}.json` - - if (!fs.existsSync(DEPLOYMENTS_DIR)) { - fs.mkdirSync(DEPLOYMENTS_DIR) - } - - // save addresses - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Addresses saved to', fileName) - - // save governor transactions - json = JSON.stringify(governorTransaction, null, 2) - fileName = `${DEPLOYMENTS_DIR}/${networkName}-upgrade-v3-tx.json` - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Governor transaction saved to', fileName) - - // save vault upgrades - json = JSON.stringify(vaultUpgrades, null, 2) - fileName = `${DEPLOYMENTS_DIR}/${networkName}-vault-v3-upgrades.json` - fs.writeFileSync(fileName, json, 'utf-8') - console.log('Vault upgrades saved to', fileName) -}) diff --git a/test/DepositDataRegistry.t.sol b/test/DepositDataRegistry.t.sol index fd7f52da..a229fe83 100644 --- a/test/DepositDataRegistry.t.sol +++ b/test/DepositDataRegistry.t.sol @@ -51,7 +51,7 @@ contract DepositDataRegistryTest is Test, EthHelpers { ), false ); - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = IEthVault( + (uint128 queuedShares, uint128 unclaimedAssets, , uint128 totalExitingAssets, ) = IEthVault( validVault ).getExitQueueData(); exitingAssets = diff --git a/test/EthBlocklistErc20Vault.t.sol b/test/EthBlocklistErc20Vault.t.sol index 320929ee..9d24ec51 100644 --- a/test/EthBlocklistErc20Vault.t.sol +++ b/test/EthBlocklistErc20Vault.t.sol @@ -265,6 +265,7 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = blocklistVault.getExitQueueData(); @@ -281,6 +282,7 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { assertEq(queuedShares, 0); assertEq(totalTickets, 0); assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalExitingAssets, 0); assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(blocklistVault.totalSupply(), _securityDeposit); @@ -326,7 +328,7 @@ contract EthBlocklistErc20VaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthBlocklistErc20Vault, address(blocklistVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); assertEq(blocklistVault.version(), 5); assertEq(blocklistVault.admin(), admin); diff --git a/test/EthBlocklistVault.t.sol b/test/EthBlocklistVault.t.sol index 4390f41b..2d2b4912 100644 --- a/test/EthBlocklistVault.t.sol +++ b/test/EthBlocklistVault.t.sol @@ -232,6 +232,7 @@ contract EthBlocklistVaultTest is Test, EthHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = blocklistVault.getExitQueueData(); @@ -248,6 +249,7 @@ contract EthBlocklistVaultTest is Test, EthHelpers { assertEq(blocklistVault.validatorsManagerNonce(), 0); assertEq(queuedShares, 0); assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(unclaimedAssets, 0); assertEq(totalTickets, 0); } @@ -283,7 +285,7 @@ contract EthBlocklistVaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthBlocklistVault, address(blocklistVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); assertEq(blocklistVault.version(), 5); diff --git a/test/EthErc20Vault.t.sol b/test/EthErc20Vault.t.sol index 02182d99..9384ec94 100644 --- a/test/EthErc20Vault.t.sol +++ b/test/EthErc20Vault.t.sol @@ -80,6 +80,7 @@ contract EthErc20VaultTest is Test, EthHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = erc20Vault.getExitQueueData(); @@ -98,6 +99,7 @@ contract EthErc20VaultTest is Test, EthHelpers { assertEq(erc20Vault.name(), 'SW ETH Vault'); assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalExitingAssets, 0); assertEq(totalTickets, 0); } @@ -140,7 +142,7 @@ contract EthErc20VaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthErc20Vault, address(erc20Vault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); assertEq(erc20Vault.version(), 5); @@ -480,7 +482,7 @@ contract EthErc20VaultTest is Test, EthHelpers { // Verify the exit queue was processed correctly // The queue might not be fully processed in one update, so we'll check that progress was made - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , , ) = vault.getExitQueueData(); assertLt(queuedShares, exitShares, 'Exit queue should be at least partially processed'); } diff --git a/test/EthFoxVault.t.sol b/test/EthFoxVault.t.sol index 588385bf..80b96bfd 100644 --- a/test/EthFoxVault.t.sol +++ b/test/EthFoxVault.t.sol @@ -51,7 +51,7 @@ contract EthFoxVaultTest is Test, EthHelpers { ); address _vault = _getOrCreateVault(VaultType.EthFoxVault, admin, initParams, false); vault = EthFoxVault(payable(_vault)); - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , ,) = vault.getExitQueueData(); exitingAssets = vault.convertToAssets(queuedShares) + address(vault).balance; } @@ -195,7 +195,7 @@ contract EthFoxVaultTest is Test, EthHelpers { // Deposit ETH to get vault shares _depositToVault(address(vault), amount, sender, sender); - (uint256 queuedSharesBefore, , , ) = vault.getExitQueueData(); + (uint256 queuedSharesBefore, , , ,) = vault.getExitQueueData(); // Set blocklist manager vm.prank(admin); @@ -215,7 +215,7 @@ contract EthFoxVaultTest is Test, EthHelpers { // User's shares should be in exit queue assertEq(vault.getShares(sender), 0); - (uint256 queuedShares, , , ) = vault.getExitQueueData(); + (uint256 queuedShares, , , ,) = vault.getExitQueueData(); assertApproxEqAbs(queuedShares, queuedSharesBefore + shares, 1); } @@ -224,7 +224,7 @@ contract EthFoxVaultTest is Test, EthHelpers { vm.prank(admin); vault.setBlocklistManager(blocklistManager); - (uint256 queuedSharesBefore, , , ) = vault.getExitQueueData(); + (uint256 queuedSharesBefore, , , ,) = vault.getExitQueueData(); // Eject user with no shares _startSnapshotGas('EthFoxVaultTest_test_ejectUserWithNoShares'); @@ -236,7 +236,7 @@ contract EthFoxVaultTest is Test, EthHelpers { assertTrue(vault.blockedAccounts(sender)); // No shares should be in exit queue - (uint256 queuedShares, , , ) = vault.getExitQueueData(); + (uint256 queuedShares, , , ,) = vault.getExitQueueData(); assertEq(queuedShares, queuedSharesBefore); } diff --git a/test/EthGenesisVault.t.sol b/test/EthGenesisVault.t.sol index 7069b027..42dacd9b 100644 --- a/test/EthGenesisVault.t.sol +++ b/test/EthGenesisVault.t.sol @@ -97,7 +97,7 @@ contract EthGenesisVaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthGenesisVault, address(existingVault)); _stopSnapshotGas(); - (uint128 queuedSharesAfter, , uint128 totalExitingAssetsAfter, ) = existingVault + (uint128 queuedSharesAfter, , , uint128 totalExitingAssetsAfter, ) = existingVault .getExitQueueData(); assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); assertEq(existingVault.version(), 5); @@ -262,7 +262,7 @@ contract EthGenesisVaultTest is Test, EthHelpers { // Add some ETH to the pool escrow uint256 escrowAmount = 40 ether; vm.deal(poolEscrow, poolEscrow.balance + escrowAmount); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); vm.deal( address(vault), address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets @@ -341,7 +341,7 @@ contract EthGenesisVaultTest is Test, EthHelpers { address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); uint256 vaultAmount = address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets; diff --git a/test/EthOsTokenVaultEscrow.t.sol b/test/EthOsTokenVaultEscrow.t.sol index 9f46a540..d5f14ef5 100644 --- a/test/EthOsTokenVaultEscrow.t.sol +++ b/test/EthOsTokenVaultEscrow.t.sol @@ -60,7 +60,7 @@ contract EthOsTokenVaultEscrowTest is Test, EthHelpers { vault = IEthVault(_vault); // Ensure the vault has enough ETH to process exit requests - (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); vm.deal( address(vault), address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets diff --git a/test/EthPrivErc20Vault.t.sol b/test/EthPrivErc20Vault.t.sol index a5b72a09..2cdc6e42 100644 --- a/test/EthPrivErc20Vault.t.sol +++ b/test/EthPrivErc20Vault.t.sol @@ -372,6 +372,7 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = privErc20Vault.getExitQueueData(); @@ -392,6 +393,7 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { assertEq(privErc20Vault.name(), 'SW ETH Vault'); assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalExitingAssets, 0); assertEq(totalTickets, 0); } @@ -433,7 +435,7 @@ contract EthPrivErc20VaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthPrivErc20Vault, address(privErc20Vault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); assertEq(privErc20Vault.version(), 5); assertEq(privErc20Vault.admin(), admin); diff --git a/test/EthPrivVault.t.sol b/test/EthPrivVault.t.sol index 557e271b..133740a1 100644 --- a/test/EthPrivVault.t.sol +++ b/test/EthPrivVault.t.sol @@ -313,6 +313,7 @@ contract EthPrivVaultTest is Test, EthHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = privVault.getExitQueueData(); @@ -330,6 +331,7 @@ contract EthPrivVaultTest is Test, EthHelpers { assertEq(privVault.validatorsManagerNonce(), 0); assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalExitingAssets, 0); assertEq(totalTickets, 0); } @@ -374,7 +376,7 @@ contract EthPrivVaultTest is Test, EthHelpers { _upgradeVault(VaultType.EthPrivVault, address(privVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); assertEq(privVault.vaultId(), keccak256('EthPrivVault')); assertEq(privVault.version(), 5); assertEq(privVault.admin(), admin); diff --git a/test/EthValidatorsChecker.t.sol b/test/EthValidatorsChecker.t.sol index ae3d4acd..6496a0d7 100644 --- a/test/EthValidatorsChecker.t.sol +++ b/test/EthValidatorsChecker.t.sol @@ -7,6 +7,9 @@ import {IValidatorsChecker} from '../contracts/interfaces/IValidatorsChecker.sol import {IDepositDataRegistry} from '../contracts/interfaces/IDepositDataRegistry.sol'; import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; +import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; +import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; +import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; import {EthHelpers} from './helpers/EthHelpers.sol'; interface IVaultValidatorsV1 { @@ -396,7 +399,7 @@ contract EthValidatorsCheckerTest is Test, EthHelpers { // 5. Create the message hash that matches the contract's implementation bytes32 validatorsManagerTypeHash = keccak256( - 'VaultValidators(bytes32 nonce,bytes validators)' + 'VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)' ); bytes32 messageHash = keccak256( abi.encode(validatorsManagerTypeHash, validRegistryRoot, keccak256(validatorData)) @@ -487,4 +490,186 @@ contract EthValidatorsCheckerTest is Test, EthHelpers { ); assertEq(blockNumber, block.number); } + + function testGetExitQueueCumulativeTickets_EmptyQueue() public view { + // Test with empty exit queue (new vault with no exit requests) + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(emptyVault); + + // Verify expected values for empty queue + assertEq(cumulativeTickets, 0, 'Cumulative tickets should be 0 for empty vault'); + } + + function testGetExitQueueMissingAssets_EmptyQueue() public view { + // Test with empty exit queue and no pending assets + uint256 targetCumulativeTickets = 0; + uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( + emptyVault, + 0, // No pending assets + targetCumulativeTickets + ); + + // Verify expected values for empty queue + assertEq(missingAssets, 0, 'Missing assets should be 0 for empty queue with 0 target tickets'); + } + + function testGetExitQueueMissingAssets_WithPendingAssets() public { + // Setup: deposit funds and enter exit queue + _depositToVault(vault, 5 ether, user, user); + vm.deal(vault, 0); // Empty the vault balance + + // Enter exit queue with some shares + uint256 sharesToExit = IVaultState(vault).convertToShares(1 ether); + vm.prank(user); + IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); + + // Get current cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + assertGt( + cumulativeTickets, + 0, + 'Cumulative tickets should be non-zero after entering exit queue' + ); + + // Test with no pending assets + uint256 missingAssetsNoPending = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, // No pending assets + cumulativeTickets + ); + + // Test with some pending assets + uint256 pendingAssets = 0.5 ether; + uint256 missingAssetsWithPending = validatorsChecker.getExitQueueMissingAssets( + vault, + pendingAssets, + cumulativeTickets + ); + + // Pending assets should reduce missing assets + assertGt( + missingAssetsNoPending, + missingAssetsWithPending, + 'Pending assets should reduce missing assets' + ); + } + + function testGetExitQueueMissingAssets_WithMultipleExits() public { + // Setup multiple exit queue entries + _depositToVault(vault, 10 ether, user, user); + + // Enter exit queue with different amounts + uint256 user1Shares = IVaultState(vault).convertToShares(2 ether); + uint256 user2Shares = IVaultState(vault).convertToShares(3 ether); + + vm.startPrank(user); + IVaultEnterExit(vault).enterExitQueue(user1Shares, user); + IVaultEnterExit(vault).enterExitQueue(user2Shares, user); + vm.stopPrank(); + + // Get cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + + // Empty the vault balance to force missing assets + vm.deal(vault, 0); + + // Get initial missing assets + uint256 initialMissingAssets = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, // No pending assets + cumulativeTickets + ); + + // Add pending assets and check changes + uint256 pendingAssets = 4 ether; + uint256 updatedMissingAssets = validatorsChecker.getExitQueueMissingAssets( + vault, + pendingAssets, + cumulativeTickets + ); + + // Verify missing assets decrease with pending assets + assertLt( + updatedMissingAssets, + initialMissingAssets, + 'Missing assets should decrease with pending assets' + ); + } + + function testGetExitQueueMissingAssets_WithExcessPendingAssets() public { + // Setup: deposit and enter exit queue + _depositToVault(vault, 5 ether, user, user); + + uint256 sharesToExit = IVaultState(vault).convertToShares(1 ether); + vm.prank(user); + IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); + + // Get cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + + // Get missing assets with no pending assets + uint256 missingAssetsBefore = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, + cumulativeTickets + ); + + // Test with large amount of pending assets (more than missing) + uint256 excessPendingAssets = missingAssetsBefore * 2; + uint256 missingAssetsAfter = validatorsChecker.getExitQueueMissingAssets( + vault, + excessPendingAssets, + cumulativeTickets + ); + + // No missing assets with excess pending assets + assertEq(missingAssetsAfter, 0, 'No missing assets with excess pending assets'); + } + + function testGetExitQueueMissingAssets_ZeroAvailableAssets() public { + // Setup: Create exit queue entries but make available assets zero + _depositToVault(vault, 5 ether, user, user); + + uint256 sharesToExit = IVaultState(vault).convertToShares(2 ether); + vm.prank(user); + IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); + + // Get cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + + // Set vault balance to zero + vm.deal(vault, 0); + + // With zero available assets and no pending assets, missing assets should be non-zero + uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, // No pending assets + cumulativeTickets + ); + + assertGt(missingAssets, 0, 'Missing assets should be non-zero with no available assets'); + } + + function testUpdateVaultState() public { + // Setup: Create rewards for the vault + int160 totalReward = int160(int256(0.5 ether)); + uint160 unlockedMevReward = 0.1 ether; + + uint256 totalAssetsBefore = IEthVault(vault).totalAssets(); + + // Create harvest params with the setup rewards + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + totalReward, + unlockedMevReward + ); + + // Call updateVaultState via the validatorsChecker + validatorsChecker.updateVaultState(vault, harvestParams); + + assertEq( + IEthVault(vault).totalAssets(), + totalAssetsBefore + 0.5 ether, + "Balance shouldn't change on second update" + ); + } } diff --git a/test/EthVault.t.sol b/test/EthVault.t.sol index 0cfbfc1f..6f8567ac 100644 --- a/test/EthVault.t.sol +++ b/test/EthVault.t.sol @@ -58,7 +58,7 @@ contract EthVaultTest is Test, EthHelpers { vm.prank(admin); vault.setValidatorsManager(validatorsManager); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = IEthVault(vault).getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = IEthVault(vault).getExitQueueData(); exitingAssets = totalExitingAssets + IEthVault(vault).convertToAssets(queuedShares) + @@ -89,6 +89,7 @@ contract EthVaultTest is Test, EthHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = newVault.getExitQueueData(); @@ -107,6 +108,7 @@ contract EthVaultTest is Test, EthHelpers { assertEq(newVault.totalShares(), _securityDeposit); assertEq(newVault.totalAssets(), _securityDeposit); assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(newVault.validatorsManagerNonce(), 0); } @@ -149,7 +151,7 @@ contract EthVaultTest is Test, EthHelpers { _stopSnapshotGas(); // Check that the vault was upgraded correctly - (uint128 queuedShares, , uint128 totalExitingAssets, ) = prevVault.getExitQueueData(); + (uint128 queuedShares, , uint128 totalExitingAssets, , ) = prevVault.getExitQueueData(); assertEq(prevVault.vaultId(), keccak256('EthVault')); assertEq(prevVault.version(), 5); assertEq(prevVault.admin(), admin); @@ -180,6 +182,7 @@ contract EthVaultTest is Test, EthHelpers { ( uint128 queuedSharesBefore, uint128 unclaimedAssetsBefore, + , uint128 totalExitingAssetsBefore, uint256 totalTicketsBefore ) = vault.getExitQueueData(); @@ -197,6 +200,7 @@ contract EthVaultTest is Test, EthHelpers { ( uint128 queuedSharesAfter, uint128 unclaimedAssetsAfter, + , uint128 totalExitingAssetsAfter, uint256 totalTicketsAfter ) = vault.getExitQueueData(); @@ -221,7 +225,7 @@ contract EthVaultTest is Test, EthHelpers { IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); vault.updateState(harvestParams); - (queuedSharesAfter, unclaimedAssetsAfter, totalExitingAssetsAfter, totalTicketsAfter) = vault + (queuedSharesAfter, unclaimedAssetsAfter, , totalExitingAssetsAfter, totalTicketsAfter) = vault .getExitQueueData(); assertLt( queuedSharesAfter, diff --git a/test/VaultEnterExit.t.sol b/test/VaultEnterExit.t.sol index f71e3264..c3bc3b07 100644 --- a/test/VaultEnterExit.t.sol +++ b/test/VaultEnterExit.t.sol @@ -47,7 +47,7 @@ contract VaultEnterExitTest is Test, EthHelpers { address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); vault = EthVault(payable(vaultAddr)); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (uint128 queuedShares, , uint128 totalExitingAssets, ,) = vault.getExitQueueData(); vm.deal( address(vault), address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets @@ -264,7 +264,7 @@ contract VaultEnterExitTest is Test, EthHelpers { // 3. Enter exit queue uint256 shares = vault.getShares(sender); - (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); + (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); vm.prank(sender); uint256 timestamp = vm.getBlockTimestamp(); @@ -273,7 +273,7 @@ contract VaultEnterExitTest is Test, EthHelpers { _stopSnapshotGas(); // 4. Verify the position ticket was created and shares moved to the queue - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , ,) = vault.getExitQueueData(); assertEq( queuedShares, queuedSharesBefore + shares, @@ -483,7 +483,7 @@ contract VaultEnterExitTest is Test, EthHelpers { uint256 shares1 = vault.getShares(sender); uint256 shares2 = vault.getShares(sender2); - (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); + (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); vm.prank(sender); uint256 timestamp1 = vm.getBlockTimestamp(); @@ -498,7 +498,7 @@ contract VaultEnterExitTest is Test, EthHelpers { _stopSnapshotGas(); // 4. Verify the queued shares - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , ,) = vault.getExitQueueData(); assertEq( queuedShares, queuedSharesBefore + shares1 + shares2, @@ -572,7 +572,7 @@ contract VaultEnterExitTest is Test, EthHelpers { // 2. Collateralize the vault _collateralizeEthVault(address(vault)); - (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); + (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); // 3. Enter exit queue with half of the shares uint256 totalShares = vault.getShares(sender); @@ -586,7 +586,7 @@ contract VaultEnterExitTest is Test, EthHelpers { _stopSnapshotGas(); // 4. Verify the position ticket and remaining shares - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , ,) = vault.getExitQueueData(); assertEq( queuedShares, queuedSharesBefore + halfShares, diff --git a/test/VaultEthStaking.t.sol b/test/VaultEthStaking.t.sol index cc274dc0..8d64b4eb 100644 --- a/test/VaultEthStaking.t.sol +++ b/test/VaultEthStaking.t.sol @@ -421,7 +421,7 @@ contract VaultEthStakingTest is Test, EthHelpers { _collateralizeEthVault(address(vault)); // Deposit ETH to the vault - (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (uint128 queuedShares, , uint128 totalExitingAssets, ,) = vault.getExitQueueData(); uint256 senderDeposit = vault.convertToAssets(queuedShares) + totalExitingAssets + depositAmount; diff --git a/test/VaultState.t.sol b/test/VaultState.t.sol index b2618aea..5cc3f2e2 100644 --- a/test/VaultState.t.sol +++ b/test/VaultState.t.sol @@ -47,7 +47,7 @@ contract VaultStateTest is Test, EthHelpers { address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); vault = EthVault(payable(vaultAddr)); - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ,) = vault .getExitQueueData(); vm.deal( address(vault), @@ -279,7 +279,7 @@ contract VaultStateTest is Test, EthHelpers { // Record owner's ETH balance before uint256 ownerBalanceBefore = owner.balance; - (uint128 queuedSharesBefore, , , ) = vault.getExitQueueData(); + (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); vm.expectEmit(true, true, true, false); emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); @@ -298,7 +298,7 @@ contract VaultStateTest is Test, EthHelpers { ); // Verify queued shares increased - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , ,) = vault.getExitQueueData(); assertEq( queuedShares, queuedSharesBefore + exitShares, @@ -482,7 +482,7 @@ contract VaultStateTest is Test, EthHelpers { // Step 2: User enters exit queue with all shares uint256 user1Shares = vault.getShares(user1); - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ,) = vault .getExitQueueData(); uint256 vaultBalance = totalExitingAssets + vault.convertToAssets(queuedShares) + diff --git a/test/VaultToken.t.sol b/test/VaultToken.t.sol index 4b38adf6..2d011022 100644 --- a/test/VaultToken.t.sol +++ b/test/VaultToken.t.sol @@ -346,7 +346,7 @@ contract VaultTokenTest is Test, EthHelpers { assertEq(ownerFinalBalance, ownerInitialBalance - exitShares, 'Owner balance should decrease'); // Verify queued shares - (uint128 queuedShares, , , ) = vault.getExitQueueData(); + (uint128 queuedShares, , , ,) = vault.getExitQueueData(); assertEq(queuedShares, exitShares, 'Queued shares should match exit amount'); } diff --git a/test/VaultValidators.t.sol b/test/VaultValidators.t.sol index 1ccc9b9e..ced6ef85 100644 --- a/test/VaultValidators.t.sol +++ b/test/VaultValidators.t.sol @@ -528,7 +528,7 @@ contract VaultValidatorsTest is Test, EthHelpers { bytes32 structHash = keccak256( abi.encode( - keccak256('VaultValidators(bytes32 nonce,bytes validators)'), + keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'), validatorsRegistryRoot, keccak256(validators) ) diff --git a/test/gnosis/GnoBlocklistErc20Vault.t.sol b/test/gnosis/GnoBlocklistErc20Vault.t.sol index 8c9b6d11..c7d1931d 100644 --- a/test/gnosis/GnoBlocklistErc20Vault.t.sol +++ b/test/gnosis/GnoBlocklistErc20Vault.t.sol @@ -250,7 +250,7 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, - uint256 totalTickets + uint256 totalTickets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); assertEq(blocklistVault.version(), 3); @@ -314,7 +314,7 @@ contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoBlocklistErc20Vault, address(blocklistVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); assertEq(blocklistVault.version(), 3); assertEq(blocklistVault.admin(), admin); diff --git a/test/gnosis/GnoBlocklistVault.t.sol b/test/gnosis/GnoBlocklistVault.t.sol index ad3f05fc..b5fa9ef5 100644 --- a/test/gnosis/GnoBlocklistVault.t.sol +++ b/test/gnosis/GnoBlocklistVault.t.sol @@ -176,6 +176,7 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = blocklistVault.getExitQueueData(); @@ -194,6 +195,7 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalTickets, 0); } @@ -232,7 +234,7 @@ contract GnoBlocklistVaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoBlocklistVault, address(blocklistVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); assertEq(blocklistVault.version(), 3); assertEq(blocklistVault.admin(), admin); diff --git a/test/gnosis/GnoErc20Vault.t.sol b/test/gnosis/GnoErc20Vault.t.sol index a87b6bb2..391653cc 100644 --- a/test/gnosis/GnoErc20Vault.t.sol +++ b/test/gnosis/GnoErc20Vault.t.sol @@ -80,6 +80,7 @@ contract GnoErc20VaultTest is Test, GnoHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = erc20Vault.getExitQueueData(); @@ -100,6 +101,7 @@ contract GnoErc20VaultTest is Test, GnoHelpers { assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalTickets, 0); } @@ -140,7 +142,7 @@ contract GnoErc20VaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoErc20Vault, address(erc20Vault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); assertEq(erc20Vault.version(), 3); assertEq(erc20Vault.admin(), admin); diff --git a/test/gnosis/GnoGenesisVault.t.sol b/test/gnosis/GnoGenesisVault.t.sol index ef6c6325..45ef6ba5 100644 --- a/test/gnosis/GnoGenesisVault.t.sol +++ b/test/gnosis/GnoGenesisVault.t.sol @@ -89,7 +89,7 @@ contract GnoGenesisVaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoGenesisVault, address(existingVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = existingVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = existingVault.getExitQueueData(); assertEq(existingVault.vaultId(), keccak256('GnoGenesisVault')); assertEq(existingVault.version(), 4); assertEq(existingVault.admin(), adminBefore); diff --git a/test/gnosis/GnoOsTokenVaultEscrow.t.sol b/test/gnosis/GnoOsTokenVaultEscrow.t.sol index 40068e90..ff3e935d 100644 --- a/test/gnosis/GnoOsTokenVaultEscrow.t.sol +++ b/test/gnosis/GnoOsTokenVaultEscrow.t.sol @@ -93,7 +93,7 @@ contract GnoOsTokenVaultEscrowTest is Test, GnoHelpers { assertEq(escrowOsTokenShares, osTokenShares, 'Incorrect osToken shares in escrow'); IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (uint128 queuedShares, , uint128 totalExitingAssets, ,) = vault.getExitQueueData(); _mintGnoToken(address(vault), totalExitingAssets + vault.convertToAssets(queuedShares)); vault.updateState(harvestParams); diff --git a/test/gnosis/GnoPrivErc20Vault.t.sol b/test/gnosis/GnoPrivErc20Vault.t.sol index 82aef29e..72b43262 100644 --- a/test/gnosis/GnoPrivErc20Vault.t.sol +++ b/test/gnosis/GnoPrivErc20Vault.t.sol @@ -271,6 +271,7 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = privErc20Vault.getExitQueueData(); @@ -291,6 +292,7 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalTickets, 0); } @@ -335,7 +337,7 @@ contract GnoPrivErc20VaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoPrivErc20Vault, address(privErc20Vault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); assertEq(privErc20Vault.version(), 3); assertEq(privErc20Vault.admin(), admin); diff --git a/test/gnosis/GnoPrivVault.t.sol b/test/gnosis/GnoPrivVault.t.sol index 8f3a8f11..9f9333a7 100644 --- a/test/gnosis/GnoPrivVault.t.sol +++ b/test/gnosis/GnoPrivVault.t.sol @@ -228,6 +228,7 @@ contract GnoPrivVaultTest is Test, GnoHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = privVault.getExitQueueData(); @@ -244,6 +245,7 @@ contract GnoPrivVaultTest is Test, GnoHelpers { assertEq(privVault.validatorsManagerNonce(), 0); assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalExitingAssets, 0); assertEq(totalTickets, 0); } @@ -292,7 +294,7 @@ contract GnoPrivVaultTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoPrivVault, address(privVault)); _stopSnapshotGas(); - (uint128 queuedShares, , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); assertEq(privVault.version(), 3); assertEq(privVault.admin(), admin); diff --git a/test/gnosis/GnoValidatorsChecker.t.sol b/test/gnosis/GnoValidatorsChecker.t.sol new file mode 100644 index 00000000..b958004f --- /dev/null +++ b/test/gnosis/GnoValidatorsChecker.t.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from 'forge-std/Test.sol'; +import {GnoValidatorsChecker} from '../../contracts/validators/GnoValidatorsChecker.sol'; +import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; +import {IVaultEnterExit} from '../../contracts/interfaces/IVaultEnterExit.sol'; +import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; +import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {GnoHelpers} from '../helpers/GnoHelpers.sol'; + +contract GnoValidatorsCheckerTest is Test, GnoHelpers { + // Test contracts + ForkContracts public contracts; + GnoValidatorsChecker public validatorsChecker; + address public vault; + address public prevVersionVault; + address public emptyVault; + address public admin; + address public user; + bytes32 public validRegistryRoot; + + function setUp() public { + // Setup fork and contracts + contracts = _activateGnosisFork(); + + // Deploy a fresh GnoValidatorsChecker + validatorsChecker = new GnoValidatorsChecker( + address(contracts.validatorsRegistry), + address(contracts.keeper), + address(contracts.vaultsRegistry), + address(_depositDataRegistry), + address(contracts.gnoToken) + ); + + // Setup accounts + admin = makeAddr('admin'); + user = makeAddr('user'); + _mintGnoToken(user, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Create and prepare a vault with sufficient funds + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' + }) + ); + vault = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + _depositToVault(vault, 33 ether, user, user); // Deposit enough for 1 validator + _collateralizeGnoVault(address(vault)); + + // Create a previous version vault for testing totalExitingAssets + prevVersionVault = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); + _depositToVault(prevVersionVault, 33 ether, user, user); + _collateralizeGnoVault(address(prevVersionVault)); + + // Create another vault without sufficient funds + emptyVault = _createVault(VaultType.GnoVault, admin, initParams, false); + + // Get valid registry root + validRegistryRoot = contracts.validatorsRegistry.get_deposit_root(); + } + + // Test getExitQueueCumulativeTickets and getExitQueueMissingAssets with an empty exit queue + function testGetExitQueueFunctions_EmptyQueue() public view { + // Get cumulative tickets for empty queue + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(emptyVault); + + // Get missing assets with zero pending assets + uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( + emptyVault, + 0, // withdrawingAssets + cumulativeTickets // targetCumulativeTickets (same as current since queue is empty) + ); + + // Verify expected values for empty queue + assertEq(cumulativeTickets, 0, 'Cumulative tickets should be 0 for empty vault'); + assertEq(missingAssets, 0, 'Missing assets should be 0 for empty vault'); + } + + // Test getExitQueueCumulativeTickets and getExitQueueMissingAssets after updating state + function testGetExitQueueFunctions_AfterStateUpdate() public { + // Enter exit queue + uint256 sharesToExit = IVaultState(prevVersionVault).convertToShares(2 ether); + vm.prank(user); + IVaultEnterExit(prevVersionVault).enterExitQueue(sharesToExit, user); + + _upgradeVault(VaultType.GnoVault, address(prevVersionVault)); + + // Get initial exit queue state + uint256 initialCumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets( + prevVersionVault + ); + uint256 initialMissingAssets = validatorsChecker.getExitQueueMissingAssets( + prevVersionVault, + 0, // withdrawingAssets + initialCumulativeTickets // targetCumulativeTickets + ); + + // Update vault state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + prevVersionVault, + int160(int256(0)), + uint160(0) + ); + validatorsChecker.updateVaultState(prevVersionVault, harvestParams); + + // Get exit queue state after update + uint256 updatedCumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets( + prevVersionVault + ); + uint256 updatedMissingAssets = validatorsChecker.getExitQueueMissingAssets( + prevVersionVault, + 0, // withdrawingAssets + initialCumulativeTickets // use same target as before for fair comparison + ); + + // After state update, the queue data may change depending on implementation + // At minimum, verify the function doesn't revert and returns reasonable values + assertTrue( + updatedCumulativeTickets >= initialCumulativeTickets, + 'Cumulative tickets should not decrease after state update' + ); + + // Missing assets should not increase after a state update + assertTrue( + updatedMissingAssets <= initialMissingAssets, + 'Missing assets should not increase after state update' + ); + } +} diff --git a/test/gnosis/GnoVault.t.sol b/test/gnosis/GnoVault.t.sol index ae2ed1d4..22c8a7b8 100644 --- a/test/gnosis/GnoVault.t.sol +++ b/test/gnosis/GnoVault.t.sol @@ -83,6 +83,7 @@ contract GnoVaultTest is Test, GnoHelpers { ( uint128 queuedShares, uint128 unclaimedAssets, + uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets ) = newVault.getExitQueueData(); @@ -99,6 +100,7 @@ contract GnoVaultTest is Test, GnoHelpers { assertEq(queuedShares, 0); assertEq(unclaimedAssets, 0); assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); assertEq(totalTickets, 0); } @@ -147,7 +149,7 @@ contract GnoVaultTest is Test, GnoHelpers { _stopSnapshotGas(); // Check that the vault was upgraded correctly - (uint128 queuedShares, , uint128 totalExitingAssets, ) = prevVault.getExitQueueData(); + (uint128 queuedShares, , , uint128 totalExitingAssets, ) = prevVault.getExitQueueData(); assertEq(prevVault.vaultId(), keccak256('GnoVault')); assertEq(prevVault.version(), 3); assertEq(prevVault.admin(), admin); @@ -184,6 +186,7 @@ contract GnoVaultTest is Test, GnoHelpers { ( uint128 queuedSharesBefore, uint128 unclaimedAssetsBefore, + , uint128 totalExitingAssetsBefore, uint256 totalTicketsBefore ) = vault.getExitQueueData(); @@ -201,6 +204,7 @@ contract GnoVaultTest is Test, GnoHelpers { ( uint128 queuedSharesAfter, uint128 unclaimedAssetsAfter, + , uint128 totalExitingAssetsAfter, uint256 totalTicketsAfter ) = vault.getExitQueueData(); @@ -230,7 +234,7 @@ contract GnoVaultTest is Test, GnoHelpers { IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); vault.updateState(harvestParams); - (queuedSharesAfter, unclaimedAssetsAfter, totalExitingAssetsAfter, totalTicketsAfter) = vault + (queuedSharesAfter, unclaimedAssetsAfter, , totalExitingAssetsAfter, totalTicketsAfter) = vault .getExitQueueData(); assertLt( queuedSharesAfter, diff --git a/test/gnosis/GnoVaultExitQueue.t.sol b/test/gnosis/GnoVaultExitQueue.t.sol index 5c036cbd..07cbc864 100644 --- a/test/gnosis/GnoVaultExitQueue.t.sol +++ b/test/gnosis/GnoVaultExitQueue.t.sol @@ -298,7 +298,7 @@ contract GnoVaultExitQueueTest is Test, GnoHelpers { _upgradeVault(VaultType.GnoVault, vaultAddr); // Calculate what the penalty should be - (, , uint128 totalExitingAssets, ) = vault.getExitQueueData(); + (, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); int256 penalty = -1 ether; // 1 GNO worth of penalty uint256 expectedPenalty = (uint256(-penalty) * uint256(totalExitingAssets)) / (uint256(totalExitingAssets) + uint256(vault.totalAssets())); @@ -319,7 +319,7 @@ contract GnoVaultExitQueueTest is Test, GnoHelpers { _stopSnapshotGas(); // Verify the exiting assets were penalized - (, , totalExitingAssets, ) = vault.getExitQueueData(); + (, , , totalExitingAssets, ) = vault.getExitQueueData(); assertLt( totalExitingAssets, totalExitingAssetsBefore + exitAmount, diff --git a/test/gnosis/VaultGnoStaking.t.sol b/test/gnosis/VaultGnoStaking.t.sol index f6329982..674a53aa 100644 --- a/test/gnosis/VaultGnoStaking.t.sol +++ b/test/gnosis/VaultGnoStaking.t.sol @@ -189,7 +189,7 @@ contract VaultGnoStakingTest is Test, GnoHelpers { function test_vaultAssets() public { // Initial check uint256 initialAssets = vault.totalAssets(); - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + (uint128 queuedShares, uint128 unclaimedAssets, , uint128 totalExitingAssets, ) = vault .getExitQueueData(); uint256 senderDeposit = vault.convertToAssets(queuedShares) + totalExitingAssets + @@ -493,7 +493,7 @@ contract VaultGnoStakingTest is Test, GnoHelpers { _collateralizeGnoVault(address(vault)); // Deposit GNO to the vault - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ) = vault + (uint128 queuedShares, uint128 unclaimedAssets, , uint128 totalExitingAssets, ) = vault .getExitQueueData(); uint256 senderDeposit = vault.convertToAssets(queuedShares) + totalExitingAssets + diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index a148f2d8..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "strict": true, - "esModuleInterop": true, - "outDir": "dist", - "noImplicitAny": false, - "resolveJsonModule": true - }, - "include": ["./test"], - "files": ["./hardhat.config.ts"] -} From 7eea4c173486c0e581d7a1ca880352b63653bf51 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Sun, 13 Apr 2025 18:32:47 +0300 Subject: [PATCH 09/15] Fix actions (#109) * Format solidity codes according to foundry * Remove prettier * Fix github workflows * Remove redundant builds in actions * Fix slither * Fix test action * Add snapshot files and check * Add config for slither * Fix snapshot * Add skip snapshots env var * Fix coverage env var in actions * Fix coverage * Update readme * Update snapshots * Update snapshots * Update snapshots --- .env.example | 1 + .github/workflows/coverage.yaml | 6 +- .github/workflows/lint.yaml | 12 - .github/workflows/slither.yaml | 2 +- .github/workflows/test-fork.yaml | 9 +- .github/workflows/test.yaml | 10 +- .prettierignore | 8 - .prettierrc | 18 - README.md | 155 +- contracts/base/ERC20Upgradeable.sol | 289 +- contracts/base/Multicall.sol | 34 +- .../interfaces/IBalancerRateProvider.sol | 10 +- contracts/interfaces/IBalancerVault.sol | 126 +- contracts/interfaces/IChainlinkAggregator.sol | 20 +- .../interfaces/IChainlinkV3Aggregator.sol | 54 +- .../interfaces/IConsolidationsChecker.sol | 42 +- contracts/interfaces/IDepositDataRegistry.sol | 198 +- .../interfaces/IEthBlocklistErc20Vault.sol | 4 +- contracts/interfaces/IEthBlocklistVault.sol | 4 +- contracts/interfaces/IEthErc20Vault.sol | 199 +- contracts/interfaces/IEthFoxVault.sol | 132 +- contracts/interfaces/IEthGenesisVault.sol | 51 +- contracts/interfaces/IEthPoolEscrow.sol | 96 +- contracts/interfaces/IEthPrivErc20Vault.sol | 4 +- contracts/interfaces/IEthPrivVault.sol | 4 +- .../interfaces/IEthValidatorsRegistry.sol | 26 +- contracts/interfaces/IEthVault.sol | 187 +- contracts/interfaces/IEthVaultFactory.sol | 68 +- .../interfaces/IGnoBlocklistErc20Vault.sol | 4 +- contracts/interfaces/IGnoBlocklistVault.sol | 4 +- contracts/interfaces/IGnoDaiDistributor.sol | 20 +- contracts/interfaces/IGnoErc20Vault.sol | 150 +- contracts/interfaces/IGnoGenesisVault.sol | 51 +- contracts/interfaces/IGnoPoolEscrow.sol | 112 +- contracts/interfaces/IGnoPrivErc20Vault.sol | 4 +- contracts/interfaces/IGnoPrivVault.sol | 4 +- .../interfaces/IGnoValidatorsRegistry.sol | 62 +- contracts/interfaces/IGnoVault.sol | 138 +- contracts/interfaces/IGnoVaultFactory.sol | 65 +- contracts/interfaces/IKeeper.sol | 16 +- contracts/interfaces/IKeeperOracles.sol | 98 +- contracts/interfaces/IKeeperRewards.sol | 377 ++- contracts/interfaces/IKeeperValidators.sol | 147 +- contracts/interfaces/IMerkleDistributor.sol | 42 +- contracts/interfaces/IMulticall.sol | 12 +- contracts/interfaces/IOsToken.sol | 68 +- contracts/interfaces/IOsTokenConfig.sol | 109 +- .../interfaces/IOsTokenFlashLoanRecipient.sol | 12 +- contracts/interfaces/IOsTokenFlashLoans.sol | 24 +- .../interfaces/IOsTokenVaultController.sol | 336 +- contracts/interfaces/IOsTokenVaultEscrow.sol | 420 ++- .../interfaces/IOsTokenVaultEscrowAuth.sol | 26 +- contracts/interfaces/IOwnMevEscrow.sol | 46 +- contracts/interfaces/IRewardEthToken.sol | 36 +- contracts/interfaces/IRewardGnoToken.sol | 36 +- contracts/interfaces/IRewardSplitter.sol | 390 ++- .../interfaces/IRewardSplitterFactory.sol | 36 +- contracts/interfaces/ISavingsXDaiAdapter.sol | 12 +- contracts/interfaces/ISharedMevEscrow.sol | 38 +- contracts/interfaces/IValidatorsChecker.sol | 159 +- contracts/interfaces/IValidatorsRegistry.sol | 16 +- contracts/interfaces/IVaultAdmin.sol | 54 +- contracts/interfaces/IVaultBlocklist.sol | 82 +- contracts/interfaces/IVaultEnterExit.sol | 193 +- contracts/interfaces/IVaultEthStaking.sol | 56 +- contracts/interfaces/IVaultFee.sol | 76 +- contracts/interfaces/IVaultGnoStaking.sol | 36 +- contracts/interfaces/IVaultMev.sol | 12 +- contracts/interfaces/IVaultOsToken.sol | 216 +- contracts/interfaces/IVaultState.sol | 172 +- contracts/interfaces/IVaultToken.sol | 10 +- contracts/interfaces/IVaultValidators.sol | 248 +- contracts/interfaces/IVaultVersion.sol | 34 +- contracts/interfaces/IVaultWhitelist.sol | 82 +- contracts/interfaces/IVaultsRegistry.sol | 148 +- contracts/keeper/Keeper.sol | 80 +- contracts/keeper/KeeperOracles.sol | 169 +- contracts/keeper/KeeperRewards.sol | 408 ++- contracts/keeper/KeeperValidators.sol | 197 +- contracts/libraries/EIP712Utils.sol | 42 +- contracts/libraries/Errors.sol | 88 +- contracts/libraries/ExitQueue.sol | 314 +- contracts/libraries/OsTokenUtils.sol | 133 +- contracts/libraries/ValidatorUtils.sol | 575 ++-- contracts/misc/EthRewardSplitter.sol | 42 +- contracts/misc/GnoDaiDistributor.sol | 89 +- contracts/misc/GnoRewardSplitter.sol | 44 +- contracts/misc/RewardSplitter.sol | 487 ++- contracts/misc/RewardSplitterFactory.sol | 40 +- contracts/mocks/EthVaultV6Mock.sol | 26 +- contracts/mocks/EthVaultV7Mock.sol | 16 +- contracts/mocks/MulticallMock.sol | 96 +- .../mocks/OsTokenFlashLoanRecipientMock.sol | 94 +- .../mocks/ValidatorsConsolidationsMock.sol | 26 +- contracts/mocks/ValidatorsWithdrawalsMock.sol | 26 +- contracts/tokens/EthOsTokenVaultEscrow.sol | 92 +- contracts/tokens/GnoOsTokenVaultEscrow.sol | 74 +- contracts/tokens/OsToken.sol | 97 +- contracts/tokens/OsTokenConfig.sol | 142 +- contracts/tokens/OsTokenFlashLoans.sol | 78 +- contracts/tokens/OsTokenVaultController.sol | 571 ++-- contracts/tokens/OsTokenVaultEscrow.sol | 614 ++-- contracts/tokens/PriceFeed.sol | 96 +- .../validators/ConsolidationsChecker.sol | 164 +- contracts/validators/DepositDataRegistry.sol | 327 +- contracts/validators/EthValidatorsChecker.sol | 41 +- contracts/validators/GnoValidatorsChecker.sol | 56 +- contracts/validators/ValidatorsChecker.sol | 416 ++- contracts/vaults/VaultsRegistry.sol | 104 +- .../ethereum/EthBlocklistErc20Vault.sol | 179 +- .../vaults/ethereum/EthBlocklistVault.sol | 156 +- contracts/vaults/ethereum/EthErc20Vault.sol | 411 ++- contracts/vaults/ethereum/EthGenesisVault.sol | 308 +- .../vaults/ethereum/EthPrivErc20Vault.sol | 172 +- contracts/vaults/ethereum/EthPrivVault.sol | 156 +- contracts/vaults/ethereum/EthVault.sol | 298 +- contracts/vaults/ethereum/EthVaultFactory.sol | 98 +- .../vaults/ethereum/custom/EthFoxVault.sol | 243 +- .../vaults/ethereum/mev/OwnMevEscrow.sol | 56 +- .../vaults/ethereum/mev/SharedMevEscrow.sol | 44 +- .../vaults/gnosis/GnoBlocklistErc20Vault.sol | 168 +- contracts/vaults/gnosis/GnoBlocklistVault.sol | 136 +- contracts/vaults/gnosis/GnoErc20Vault.sol | 382 ++- contracts/vaults/gnosis/GnoGenesisVault.sol | 253 +- contracts/vaults/gnosis/GnoPrivErc20Vault.sol | 161 +- contracts/vaults/gnosis/GnoPrivVault.sol | 136 +- contracts/vaults/gnosis/GnoVault.sol | 271 +- contracts/vaults/gnosis/GnoVaultFactory.sol | 133 +- .../vaults/gnosis/mev/GnoOwnMevEscrow.sol | 66 +- .../vaults/gnosis/mev/GnoSharedMevEscrow.sol | 50 +- contracts/vaults/modules/VaultAdmin.sol | 103 +- contracts/vaults/modules/VaultBlocklist.sol | 98 +- contracts/vaults/modules/VaultEnterExit.sol | 367 +-- contracts/vaults/modules/VaultEthStaking.sol | 176 +- contracts/vaults/modules/VaultFee.sol | 168 +- contracts/vaults/modules/VaultGnoStaking.sol | 286 +- contracts/vaults/modules/VaultImmutables.sol | 84 +- contracts/vaults/modules/VaultMev.sol | 118 +- contracts/vaults/modules/VaultOsToken.sol | 614 ++-- contracts/vaults/modules/VaultState.sol | 658 ++-- contracts/vaults/modules/VaultToken.sol | 110 +- contracts/vaults/modules/VaultValidators.sol | 541 ++-- contracts/vaults/modules/VaultVersion.sol | 88 +- contracts/vaults/modules/VaultWhitelist.sol | 98 +- script/Network.sol | 290 +- script/UpgradeEthNetwork.s.sol | 313 +- slither.config.json | 6 + snapshots/ConsolidationsCheckerTest.json | 12 + snapshots/DepositDataRegistryTest.json | 9 + snapshots/EthBlocklistErc20VaultTest.json | 8 + snapshots/EthBlocklistVaultTest.json | 7 + snapshots/EthErc20VaultTest.json | 16 + snapshots/EthFoxVaultTest.json | 8 + snapshots/EthGenesisVaultTest.json | 8 + snapshots/EthOsTokenVaultEscrowTest.json | 35 + snapshots/EthPrivErc20VaultTest.json | 9 + snapshots/EthPrivVaultTest.json | 11 + snapshots/EthRewardSplitterTest.json | 14 + snapshots/EthVaultTest.json | 11 + snapshots/GnoBlocklistErc20VaultTest.json | 7 + snapshots/GnoBlocklistVaultTest.json | 6 + snapshots/GnoErc20VaultTest.json | 12 + snapshots/GnoGenesisVaultTest.json | 5 + snapshots/GnoOsTokenVaultEscrowTest.json | 5 + snapshots/GnoOwnMevEscrowTest.json | 3 + snapshots/GnoPrivErc20VaultTest.json | 7 + snapshots/GnoPrivVaultTest.json | 8 + snapshots/GnoRewardSplitterTest.json | 14 + snapshots/GnoSharedMevEscrowTest.json | 3 + snapshots/GnoVaultExitQueueTest.json | 7 + snapshots/GnoVaultTest.json | 8 + snapshots/KeeperOraclesTest.json | 12 + snapshots/KeeperRewardsTest.json | 20 + snapshots/KeeperValidatorsTest.json | 15 + snapshots/OsTokenConfigTest.json | 17 + snapshots/OsTokenTest.json | 19 + snapshots/OwnMevEscrowTest.json | 8 + snapshots/PriceFeedTest.json | 5 + snapshots/VaultAdminTest.json | 10 + snapshots/VaultEnterExitTest.json | 24 + snapshots/VaultEthStakingTest.json | 18 + snapshots/VaultFeeTest.json | 15 + snapshots/VaultGnoStakingTest.json | 14 + snapshots/VaultOsTokenTest.json | 48 + snapshots/VaultTokenTest.json | 22 + snapshots/VaultValidatorsTest.json | 43 + snapshots/VaultVersionTest.json | 12 + snapshots/VaultsRegistryTest.json | 20 + test/ConsolidationsChecker.t.sol | 832 +++-- test/DepositDataRegistry.t.sol | 1423 ++++----- test/EthBlocklistErc20Vault.t.sol | 687 ++-- test/EthBlocklistVault.t.sol | 588 ++-- test/EthErc20Vault.t.sol | 947 +++--- test/EthFoxVault.t.sol | 582 ++-- test/EthGenesisVault.t.sol | 695 ++-- test/EthOsTokenVaultEscrow.t.sol | 2637 +++++++-------- test/EthPrivErc20Vault.t.sol | 888 +++--- test/EthPrivVault.t.sol | 954 +++--- test/EthRewardSplitter.t.sol | 980 +++--- test/EthValidatorsChecker.t.sol | 1264 ++++---- test/EthVault.t.sol | 832 +++-- test/KeeperOracles.t.sol | 380 +-- test/KeeperRewards.t.sol | 1101 +++---- test/KeeperValidators.t.sol | 900 +++--- test/Multicall.t.sol | 265 +- test/OsToken.t.sol | 754 +++-- test/OsTokenConfig.t.sol | 794 +++-- test/OsTokenFlashLoans.t.sol | 366 ++- test/OwnMevEscrow.t.sol | 394 ++- test/PriceFeed.t.sol | 283 +- test/SharedMevEscrow.t.sol | 364 ++- test/VaultAdmin.t.sol | 284 +- test/VaultEnterExit.t.sol | 1465 ++++----- test/VaultEthStaking.t.sol | 1043 +++--- test/VaultFee.t.sol | 793 +++-- test/VaultOsToken.t.sol | 2819 ++++++++-------- test/VaultState.t.sol | 1010 +++--- test/VaultToken.t.sol | 1222 ++++--- test/VaultValidators.t.sol | 2820 ++++++++--------- test/VaultVersion.t.sol | 554 ++-- test/VaultsRegistry.t.sol | 563 ++-- test/gnosis/GnoBlocklistErc20Vault.t.sol | 660 ++-- test/gnosis/GnoBlocklistVault.t.sol | 503 ++- test/gnosis/GnoErc20Vault.t.sol | 730 +++-- test/gnosis/GnoGenesisVault.t.sol | 446 ++- test/gnosis/GnoOsTokenVaultEscrow.t.sol | 233 +- test/gnosis/GnoOwnMevEscrow.t.sol | 182 +- test/gnosis/GnoPrivErc20Vault.t.sol | 715 +++-- test/gnosis/GnoPrivVault.t.sol | 704 ++-- test/gnosis/GnoRewardSplitter.t.sol | 1025 +++--- test/gnosis/GnoSharedMevEscrow.t.sol | 224 +- test/gnosis/GnoValidatorsChecker.t.sol | 246 +- test/gnosis/GnoVault.t.sol | 689 ++-- test/gnosis/GnoVaultExitQueue.t.sol | 602 ++-- test/gnosis/VaultGnoStaking.t.sol | 1055 +++--- test/helpers/EthHelpers.sol | 761 +++-- test/helpers/GnoHelpers.sol | 792 +++-- test/helpers/KeeperHelpers.sol | 237 +- test/helpers/ValidatorsHelpers.sol | 343 +- 239 files changed, 30287 insertions(+), 32015 deletions(-) delete mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 slither.config.json create mode 100644 snapshots/ConsolidationsCheckerTest.json create mode 100644 snapshots/DepositDataRegistryTest.json create mode 100644 snapshots/EthBlocklistErc20VaultTest.json create mode 100644 snapshots/EthBlocklistVaultTest.json create mode 100644 snapshots/EthErc20VaultTest.json create mode 100644 snapshots/EthFoxVaultTest.json create mode 100644 snapshots/EthGenesisVaultTest.json create mode 100644 snapshots/EthOsTokenVaultEscrowTest.json create mode 100644 snapshots/EthPrivErc20VaultTest.json create mode 100644 snapshots/EthPrivVaultTest.json create mode 100644 snapshots/EthRewardSplitterTest.json create mode 100644 snapshots/EthVaultTest.json create mode 100644 snapshots/GnoBlocklistErc20VaultTest.json create mode 100644 snapshots/GnoBlocklistVaultTest.json create mode 100644 snapshots/GnoErc20VaultTest.json create mode 100644 snapshots/GnoGenesisVaultTest.json create mode 100644 snapshots/GnoOsTokenVaultEscrowTest.json create mode 100644 snapshots/GnoOwnMevEscrowTest.json create mode 100644 snapshots/GnoPrivErc20VaultTest.json create mode 100644 snapshots/GnoPrivVaultTest.json create mode 100644 snapshots/GnoRewardSplitterTest.json create mode 100644 snapshots/GnoSharedMevEscrowTest.json create mode 100644 snapshots/GnoVaultExitQueueTest.json create mode 100644 snapshots/GnoVaultTest.json create mode 100644 snapshots/KeeperOraclesTest.json create mode 100644 snapshots/KeeperRewardsTest.json create mode 100644 snapshots/KeeperValidatorsTest.json create mode 100644 snapshots/OsTokenConfigTest.json create mode 100644 snapshots/OsTokenTest.json create mode 100644 snapshots/OwnMevEscrowTest.json create mode 100644 snapshots/PriceFeedTest.json create mode 100644 snapshots/VaultAdminTest.json create mode 100644 snapshots/VaultEnterExitTest.json create mode 100644 snapshots/VaultEthStakingTest.json create mode 100644 snapshots/VaultFeeTest.json create mode 100644 snapshots/VaultGnoStakingTest.json create mode 100644 snapshots/VaultOsTokenTest.json create mode 100644 snapshots/VaultTokenTest.json create mode 100644 snapshots/VaultValidatorsTest.json create mode 100644 snapshots/VaultVersionTest.json create mode 100644 snapshots/VaultsRegistryTest.json diff --git a/.env.example b/.env.example index 0de3d705..a4d553cf 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ MAINNET_RPC_URL=http://localhost:8545 GNOSIS_RPC_URL=http://localhost:8546 USE_FORK_VAULTS=false +SKIP_SNAPSHOTS=false \ No newline at end of file diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index f2eba612..403135d3 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -24,9 +24,6 @@ jobs: with: version: stable - - name: Build - run: forge build - - name: Run forge coverage id: coverage run: | @@ -44,6 +41,9 @@ jobs: } >> "$GITHUB_OUTPUT" env: MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + GNOSIS_RPC_URL: ${{ secrets.GNOSIS_RPC_URL }} + SKIP_SNAPSHOTS: true + USE_FORK_VAULTS: false - name: Check coverage is updated uses: actions/github-script@v5 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index aefccf97..668b1b64 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -22,15 +22,3 @@ jobs: - name: Lint run: forge fmt --check - - - uses: actions/cache@v3 - name: Configure npm caching - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/workflows/prettier.yml') }} - restore-keys: | - ${{ runner.os }}-npm- - - - name: Check code formatting - run: |- - npx prettier --check . diff --git a/.github/workflows/slither.yaml b/.github/workflows/slither.yaml index a21e5256..46c8655f 100644 --- a/.github/workflows/slither.yaml +++ b/.github/workflows/slither.yaml @@ -35,7 +35,7 @@ jobs: pip3 install slither-analyzer - name: Build - run: forge build + run: forge compile --skip test - name: Run Slither run: | diff --git a/.github/workflows/test-fork.yaml b/.github/workflows/test-fork.yaml index a47c81cd..ced24763 100644 --- a/.github/workflows/test-fork.yaml +++ b/.github/workflows/test-fork.yaml @@ -7,8 +7,8 @@ on: pull_request: jobs: - forge-tests: - name: Forge Tests + forge-fork-tests: + name: Forge Fork Tests runs-on: ubuntu-latest steps: @@ -21,13 +21,12 @@ jobs: with: version: stable - - name: Build - run: forge build - - name: Run tests run: forge test --isolate -vvv env: FORGE_SNAPSHOT_CHECK: false USE_FORK_VAULTS: true + SKIP_SNAPSHOTS: true MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + GNOSIS_RPC_URL: ${{ secrets.GNOSIS_RPC_URL }} FOUNDRY_PROFILE: test diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cb7bdf36..2401c297 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -21,13 +21,11 @@ jobs: with: version: stable - - name: Build - run: forge build - - name: Run tests - run: forge test --isolate -vvv + run: forge test --isolate --gas-snapshot-check=true -vvv env: - FORGE_SNAPSHOT_CHECK: true USE_FORK_VAULTS: false + SKIP_SNAPSHOTS: false MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} - FOUNDRY_PROFILE: test \ No newline at end of file + GNOSIS_RPC_URL: ${{ secrets.GNOSIS_RPC_URL }} + FOUNDRY_PROFILE: test diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index a3b978a2..00000000 --- a/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -.prettierrc -foundry.toml -out -lib/ -cache/ -*.sol -dist/ -snapshots/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index f8b6e02a..00000000 --- a/.prettierrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "printWidth": 100, - "trailingComma": "es5", - "semi": false, - "singleQuote": true, - "tabWidth": 2, - "plugins": ["prettier-plugin-solidity"], - "overrides": [ - { - "files": "*.sol", - "options": { - "semi": true, - "printWidth": 100, - "tabWidth": 2 - } - } - ] -} diff --git a/README.md b/README.md index f1284aad..e271ae4d 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,150 @@ # StakeWise Protocol V3 -[//]: # '[![Build pass](https://github.com/stakewise/v3-core/actions/workflows/CI.yaml/badge.svg)](https://github.com/stakewise/v3-core/actions/workflows/CI.yaml)' -[//]: # '[![codecov](https://codecov.io/gh/stakewise/v3-core/branch/main/graph/badge.svg?token=U50KN38G67)](https://codecov.io/gh/stakewise/v3-core)' +StakeWise V3 is a decentralized liquid staking protocol that operates on Ethereum and other EVM-compatible chains such as Gnosis Chain. The protocol allows users to stake their assets (ETH, GNO) and receive liquid staking tokens in return, enabling them to maintain liquidity while earning staking rewards. [![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/stakewise) -This repository contains the [StakeWise](https://stakewise.io/) V3 smart contracts for decentralized liquid staking on -Ethereum. +## Architecture Overview -## Documentation +The StakeWise V3 protocol consists of several key components: -You can find the documentation for every contract in the `contracts` directory. For integration, check -the `contracts/interfaces` directory. +### Vaults + +Modular smart contracts that manage staked assets: + +- **EthVault**: For Ethereum staking +- **GnoVault**: For Gnosis Chain staking +- **Specialized variants**: Blocklist vaults, private vaults, ERC20 vaults + +### Token System + +- **OsToken**: Over-collateralized staked token +- **OsTokenVaultController**: Manages the minting and burning of OsToken shares +- **OsTokenConfig**: Configuration parameters for OsToken operations + +### Validator Management + +- **ValidatorsRegistry**: Interface with the blockchain's validator system +- **KeeperValidators**: Approves validator registrations +- **ValidatorsChecker**: Validates deposit data + +### MEV Management + +- **OwnMevEscrow**: Accumulates MEV for individual vaults +- **SharedMevEscrow**: Collects and distributes MEV rewards accross multiple vaults + +### Auxiliary Components + +- **Keeper**: Updates vault rewards and approves validator registrations +- **VaultsRegistry**: Tracks all deployed vaults and factories +- **RewardSplitter**: Distributes fee based on configured shares + +## Key Features + +- **Modular Architecture**: Components can be developed independently +- **Multi-Chain Support**: Works on Ethereum and Gnosis Chain +- **MEV Capture**: Captures and distributes MEV rewards +- **Validator Management**: Full lifecycle management of validators +- **Customizable Vaults**: Different vault types for various use cases +- **Over-Collateralized Tokens**: Liquid staking with osToken system +- **Governance Controls**: Admin functions for parameter updates + +## Installation + +This project uses Foundry as the development environment. + +1. Install Foundry: + +```shell +curl -L https://foundry.paradigm.xyz | bash +foundryup +``` + +2. Clone the repository and install dependencies: + +```shell +git clone https://github.com/stakewise/v3-core.git +cd v3-core +forge install +``` ## Development -1. Install dependencies: +### Compilation + +Compile contracts with Foundry: + +```shell +forge build --skip test +``` - ```shell script - npm install - ``` +### Testing -2. Compile contracts: +Run tests with Foundry: - ```shell script - npm run compile - ``` +```shell +FOUNDRY_PROFILE=test forge test --isolate +``` -3. Run tests: +### Local Deployment - ```shell script - npm run quick-test - ``` +1. Start a local Anvil node (Foundry's local chain): -## Deploy locally +```shell +anvil +``` -1. Install dependencies: +2. Deploy contracts using Foundry scripts: - ```shell script - npm install - ``` +```shell +forge script script/UpgradeEthNetwork.s.sol:UpgradeEthNetwork --rpc-url http://localhost:8545 --broadcast +``` -2. Compile contracts: +### Gas Analysis - ```shell script - npm run compile - ``` +Generate a gas report: -3. Start local hardhat node in a separate terminal: +```shell +FOUNDRY_PROFILE=test forge test --isolate --gas-report +``` - ```shell script - npm run node - ``` +## Contract Documentation -4. Deploy contracts: +Detailed documentation for each contract is available in the `contracts` directory. For integration purposes, review the interfaces in the `contracts/interfaces` directory. - ```shell script - npm run full-deploy:local - ``` +Key interfaces include: + +- `IEthVault.sol`: Ethereum staking vaults +- `IGnoVault.sol`: Gnosis Chain staking vaults +- `IOsToken.sol`: Over-collateralized staked tokens +- `IKeeper.sol`: Validator and rewards management + +## Protocol Architecture + +The protocol follows a modular design with several key components: + +1. **Vaults**: Hold staked assets and manage validator operations +2. **Tokens**: Represent staked positions with liquid tokens +3. **Keepers**: External services that update rewards and approve validators +4. **MEV Escrows**: Capture and distribute MEV rewards ## Contributing -Development of the project happens in the open on GitHub, and we are grateful to the community for contributing bug -fixes and improvements. +Contributions are welcome! The project follows standard GitHub flow: + +1. Fork the repository +2. Create a feature branch +3. Implement changes with tests +4. Submit a pull request + +Development happens in the open on GitHub, and we are grateful to the community for contributing bug fixes and improvements. -## Contact us +## Contact - [Discord](https://chat.stakewise.io/) - [Telegram](https://t.me/stakewise_io) - [Twitter](https://twitter.com/stakewise_io) -### License +## License The license for StakeWise V3 Core is the Business Source License 1.1 (BUSL-1.1), see [LICENSE](./LICENSE.md). diff --git a/contracts/base/ERC20Upgradeable.sol b/contracts/base/ERC20Upgradeable.sol index 4658dc18..a8a81279 100644 --- a/contracts/base/ERC20Upgradeable.sol +++ b/contracts/base/ERC20Upgradeable.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol'; -import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {EIP712Utils} from '../libraries/EIP712Utils.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {EIP712Utils} from "../libraries/EIP712Utils.sol"; /** * @title ERC20 Upgradeable @@ -15,150 +15,139 @@ import {EIP712Utils} from '../libraries/EIP712Utils.sol'; * @notice Modern and gas efficient ERC20 + EIP-2612 implementation */ abstract contract ERC20Upgradeable is Initializable, IERC20Permit, IERC20, IERC20Metadata { - bytes32 private constant _permitTypeHash = - keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'); - - /// @inheritdoc IERC20Metadata - string public override name; - - /// @inheritdoc IERC20Metadata - string public override symbol; - - /// @inheritdoc IERC20Metadata - uint8 public constant override decimals = 18; - - /// @inheritdoc IERC20 - mapping(address => mapping(address => uint256)) public override allowance; - - /// @inheritdoc IERC20Permit - mapping(address => uint256) public override nonces; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - uint256 private immutable _initialChainId; - - bytes32 private _initialDomainSeparator; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - // disable initializers for the implementation contract - _disableInitializers(); - _initialChainId = block.chainid; - } - - /// @inheritdoc IERC20 - function approve(address spender, uint256 amount) public override returns (bool) { - if (spender == address(0)) revert Errors.ZeroAddress(); - allowance[msg.sender][spender] = amount; - - emit Approval(msg.sender, spender, amount); - - return true; - } - - /// @inheritdoc IERC20 - function transfer(address to, uint256 amount) public virtual override returns (bool) { - _transfer(msg.sender, to, amount); - return true; - } - - /// @inheritdoc IERC20 - function transferFrom( - address from, - address to, - uint256 amount - ) public virtual override returns (bool) { - // Saves gas for limited approvals - uint256 allowed = allowance[from][msg.sender]; - if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; - - _transfer(from, to, amount); - - return true; - } - - /// @inheritdoc IERC20Permit - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) public override { - if (spender == address(0)) revert Errors.ZeroAddress(); - if (deadline < block.timestamp) revert Errors.DeadlineExpired(); - - // Unchecked because the only math done is incrementing - // the owner's nonce which cannot realistically overflow - unchecked { - address recoveredAddress = ecrecover( - keccak256( - abi.encodePacked( - '\x19\x01', - DOMAIN_SEPARATOR(), - keccak256(abi.encode(_permitTypeHash, owner, spender, value, nonces[owner]++, deadline)) - ) - ), - v, - r, - s - ); - - if (recoveredAddress == address(0) || recoveredAddress != owner) - revert Errors.PermitInvalidSigner(); - - allowance[recoveredAddress][spender] = value; + bytes32 private constant _permitTypeHash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + /// @inheritdoc IERC20Metadata + string public override name; + + /// @inheritdoc IERC20Metadata + string public override symbol; + + /// @inheritdoc IERC20Metadata + uint8 public constant override decimals = 18; + + /// @inheritdoc IERC20 + mapping(address => mapping(address => uint256)) public override allowance; + + /// @inheritdoc IERC20Permit + mapping(address => uint256) public override nonces; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + uint256 private immutable _initialChainId; + + bytes32 private _initialDomainSeparator; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + // disable initializers for the implementation contract + _disableInitializers(); + _initialChainId = block.chainid; + } + + /// @inheritdoc IERC20 + function approve(address spender, uint256 amount) public override returns (bool) { + if (spender == address(0)) revert Errors.ZeroAddress(); + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + /// @inheritdoc IERC20 + function transfer(address to, uint256 amount) public virtual override returns (bool) { + _transfer(msg.sender, to, amount); + return true; + } + + /// @inheritdoc IERC20 + function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { + // Saves gas for limited approvals + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + _transfer(from, to, amount); + + return true; + } + + /// @inheritdoc IERC20Permit + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) + public + override + { + if (spender == address(0)) revert Errors.ZeroAddress(); + if (deadline < block.timestamp) revert Errors.DeadlineExpired(); + + // Unchecked because the only math done is incrementing + // the owner's nonce which cannot realistically overflow + unchecked { + address recoveredAddress = ecrecover( + keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR(), + keccak256(abi.encode(_permitTypeHash, owner, spender, value, nonces[owner]++, deadline)) + ) + ), + v, + r, + s + ); + + if (recoveredAddress == address(0) || recoveredAddress != owner) { + revert Errors.PermitInvalidSigner(); + } + + allowance[recoveredAddress][spender] = value; + } + + emit Approval(owner, spender, value); + } + + /// @inheritdoc IERC20Permit + function DOMAIN_SEPARATOR() public view override returns (bytes32) { + return block.chainid == _initialChainId ? _initialDomainSeparator : _computeDomainSeparator(); + } + + /** + * @notice Computes the hash of the EIP712 typed data + * @dev This function is used to compute the hash of the EIP712 typed data + */ + function _computeDomainSeparator() private view returns (bytes32) { + return EIP712Utils.computeDomainSeparator(name, address(this)); + } + + /** + * @dev Moves `amount` of tokens from `from` to `to`. + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 amount) internal virtual; + + /** + * @dev Initializes the ERC20Upgradeable contract + * @param _name The name of the ERC20 token + * @param _symbol The symbol of the ERC20 token + */ + function __ERC20Upgradeable_init(string memory _name, string memory _symbol) internal onlyInitializing { + // initialize ERC20 + name = _name; + symbol = _symbol; + + // initialize EIP-2612 + _initialDomainSeparator = _computeDomainSeparator(); } - emit Approval(owner, spender, value); - } - - /// @inheritdoc IERC20Permit - function DOMAIN_SEPARATOR() public view override returns (bytes32) { - return block.chainid == _initialChainId ? _initialDomainSeparator : _computeDomainSeparator(); - } - - /** - * @notice Computes the hash of the EIP712 typed data - * @dev This function is used to compute the hash of the EIP712 typed data - */ - function _computeDomainSeparator() private view returns (bytes32) { - return EIP712Utils.computeDomainSeparator(name, address(this)); - } - - /** - * @dev Moves `amount` of tokens from `from` to `to`. - * Emits a {Transfer} event. - */ - function _transfer(address from, address to, uint256 amount) internal virtual; - - /** - * @dev Initializes the ERC20Upgradeable contract - * @param _name The name of the ERC20 token - * @param _symbol The symbol of the ERC20 token - */ - function __ERC20Upgradeable_init( - string memory _name, - string memory _symbol - ) internal onlyInitializing { - // initialize ERC20 - name = _name; - symbol = _symbol; - - // initialize EIP-2612 - _initialDomainSeparator = _computeDomainSeparator(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/base/Multicall.sol b/contracts/base/Multicall.sol index 598c7dea..19ceb0f7 100644 --- a/contracts/base/Multicall.sol +++ b/contracts/base/Multicall.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import '../interfaces/IMulticall.sol'; +import "../interfaces/IMulticall.sol"; /** * @title Multicall @@ -11,23 +11,23 @@ import '../interfaces/IMulticall.sol'; * @notice Enables calling multiple methods in a single call to the contract */ abstract contract Multicall is IMulticall { - /// @inheritdoc IMulticall - function multicall(bytes[] calldata data) external override returns (bytes[] memory results) { - uint256 dataLength = data.length; - results = new bytes[](dataLength); - for (uint256 i = 0; i < dataLength; i++) { - (bool success, bytes memory result) = address(this).delegatecall(data[i]); + /// @inheritdoc IMulticall + function multicall(bytes[] calldata data) external override returns (bytes[] memory results) { + uint256 dataLength = data.length; + results = new bytes[](dataLength); + for (uint256 i = 0; i < dataLength; i++) { + (bool success, bytes memory result) = address(this).delegatecall(data[i]); - if (!success) { - // Next 5 lines from https://ethereum.stackexchange.com/a/83577 - if (result.length < 68) revert(); - assembly { - result := add(result, 0x04) - } - revert(abi.decode(result, (string))); - } + if (!success) { + // Next 5 lines from https://ethereum.stackexchange.com/a/83577 + if (result.length < 68) revert(); + assembly { + result := add(result, 0x04) + } + revert(abi.decode(result, (string))); + } - results[i] = result; + results[i] = result; + } } - } } diff --git a/contracts/interfaces/IBalancerRateProvider.sol b/contracts/interfaces/IBalancerRateProvider.sol index fb4cfd69..0157c4c2 100644 --- a/contracts/interfaces/IBalancerRateProvider.sol +++ b/contracts/interfaces/IBalancerRateProvider.sol @@ -15,9 +15,9 @@ pragma solidity ^0.8.22; interface IBalancerRateProvider { - /** - * @notice Returns the price of a unit of osToken (e.g price of osETH in ETH) - * @return The price of a unit of osToken (with 18 decimals) - */ - function getRate() external view returns (uint256); + /** + * @notice Returns the price of a unit of osToken (e.g price of osETH in ETH) + * @return The price of a unit of osToken (with 18 decimals) + */ + function getRate() external view returns (uint256); } diff --git a/contracts/interfaces/IBalancerVault.sol b/contracts/interfaces/IBalancerVault.sol index a147698f..41ddb775 100644 --- a/contracts/interfaces/IBalancerVault.sol +++ b/contracts/interfaces/IBalancerVault.sol @@ -8,71 +8,69 @@ pragma solidity ^0.8.22; * @notice Interface for the Balancer Vault contract */ interface IBalancerVault { - enum SwapKind { - GIVEN_IN, - GIVEN_OUT - } + enum SwapKind { + GIVEN_IN, + GIVEN_OUT + } - /** - * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on - * the `kind` value. - * - * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address). - * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault. - * - * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be - * used to extend swap behavior. - */ - struct SingleSwap { - bytes32 poolId; - SwapKind kind; - address assetIn; - address assetOut; - uint256 amount; - bytes userData; - } + /** + * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on + * the `kind` value. + * + * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address). + * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault. + * + * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be + * used to extend swap behavior. + */ + struct SingleSwap { + bytes32 poolId; + SwapKind kind; + address assetIn; + address assetOut; + uint256 amount; + bytes userData; + } - /** - * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the - * `recipient` account. - * - * If the caller is not `sender`, it must be an authorized relayer for them. - * - * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20 - * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender` - * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of - * `joinPool`. - * - * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of - * transferred. This matches the behavior of `exitPool`. - * - * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a - * revert. - */ - struct FundManagement { - address sender; - bool fromInternalBalance; - address payable recipient; - bool toInternalBalance; - } + /** + * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the + * `recipient` account. + * + * If the caller is not `sender`, it must be an authorized relayer for them. + * + * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20 + * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender` + * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of + * `joinPool`. + * + * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of + * transferred. This matches the behavior of `exitPool`. + * + * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a + * revert. + */ + struct FundManagement { + address sender; + bool fromInternalBalance; + address payable recipient; + bool toInternalBalance; + } - /** - * @dev Performs a swap with a single Pool. - * - * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens - * taken from the Pool, which must be greater than or equal to `limit`. - * - * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens - * sent to the Pool, which must be less than or equal to `limit`. - * - * Internal Balance usage and the recipient are determined by the `funds` struct. - * - * Emits a `Swap` event. - */ - function swap( - SingleSwap memory singleSwap, - FundManagement memory funds, - uint256 limit, - uint256 deadline - ) external payable returns (uint256); + /** + * @dev Performs a swap with a single Pool. + * + * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens + * taken from the Pool, which must be greater than or equal to `limit`. + * + * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens + * sent to the Pool, which must be less than or equal to `limit`. + * + * Internal Balance usage and the recipient are determined by the `funds` struct. + * + * Emits a `Swap` event. + */ + function swap(SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline) + external + payable + returns (uint256); } diff --git a/contracts/interfaces/IChainlinkAggregator.sol b/contracts/interfaces/IChainlinkAggregator.sol index 08bf51d3..72506d41 100644 --- a/contracts/interfaces/IChainlinkAggregator.sol +++ b/contracts/interfaces/IChainlinkAggregator.sol @@ -9,15 +9,15 @@ pragma solidity ^0.8.22; * @notice Interface for Chainlink aggregator contract */ interface IChainlinkAggregator { - /** - * @notice Returns the price of a unit of osToken (e.g price of osETH in ETH) - * @return The price of a unit of osToken (with 18 decimals) - */ - function latestAnswer() external view returns (int256); + /** + * @notice Returns the price of a unit of osToken (e.g price of osETH in ETH) + * @return The price of a unit of osToken (with 18 decimals) + */ + function latestAnswer() external view returns (int256); - /** - * @notice The last updated at block timestamp - * @return The timestamp of the last update - */ - function latestTimestamp() external view returns (uint256); + /** + * @notice The last updated at block timestamp + * @return The timestamp of the last update + */ + function latestTimestamp() external view returns (uint256); } diff --git a/contracts/interfaces/IChainlinkV3Aggregator.sol b/contracts/interfaces/IChainlinkV3Aggregator.sol index 5f1aab78..430adec0 100644 --- a/contracts/interfaces/IChainlinkV3Aggregator.sol +++ b/contracts/interfaces/IChainlinkV3Aggregator.sol @@ -9,37 +9,31 @@ pragma solidity ^0.8.22; * @notice Interface for Chainlink V3 aggregator contract */ interface IChainlinkV3Aggregator { - /** - * @notice The number of decimals the price is formatted with - */ - function decimals() external view returns (uint8); + /** + * @notice The number of decimals the price is formatted with + */ + function decimals() external view returns (uint8); - /** - * @notice The description of the aggregator - */ - function description() external view returns (string memory); + /** + * @notice The description of the aggregator + */ + function description() external view returns (string memory); - /** - * @notice The version number of the aggregator - */ - function version() external view returns (uint256); + /** + * @notice The version number of the aggregator + */ + function version() external view returns (uint256); - /** - * @notice Get the data from the latest round - * @return roundId The round ID - * @return answer The current price - * @return startedAt The timestamp of when the round started - * @return updatedAt The timestamp of when the round was updated - * @return answeredInRound (Deprecated) Previously used when answers could take multiple rounds to be computed - */ - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); + /** + * @notice Get the data from the latest round + * @return roundId The round ID + * @return answer The current price + * @return startedAt The timestamp of when the round started + * @return updatedAt The timestamp of when the round was updated + * @return answeredInRound (Deprecated) Previously used when answers could take multiple rounds to be computed + */ + function latestRoundData() + external + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); } diff --git a/contracts/interfaces/IConsolidationsChecker.sol b/contracts/interfaces/IConsolidationsChecker.sol index 0e0e1e1a..ad84d580 100644 --- a/contracts/interfaces/IConsolidationsChecker.sol +++ b/contracts/interfaces/IConsolidationsChecker.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; +import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol"; /** * @title IConsolidationsChecker @@ -10,28 +10,22 @@ import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; * @notice Defines the interface for the ConsolidationsChecker contract */ interface IConsolidationsChecker is IERC5267 { - /** - * @notice Verifies the signatures of oracles for validators consolidations. Reverts if the signatures are invalid. - * @param vault The address of the vault - * @param validators The concatenation of the validators' data - * @param signatures The concatenation of the oracles' signatures - */ - function verifySignatures( - address vault, - bytes calldata validators, - bytes calldata signatures - ) external; + /** + * @notice Verifies the signatures of oracles for validators consolidations. Reverts if the signatures are invalid. + * @param vault The address of the vault + * @param validators The concatenation of the validators' data + * @param signatures The concatenation of the oracles' signatures + */ + function verifySignatures(address vault, bytes calldata validators, bytes calldata signatures) external; - /** - * @notice Function for checking signatures of oracles for validators consolidations - * @param vault The address of the vault - * @param validators The concatenation of the validators' data - * @param signatures The concatenation of the oracles' signatures - * @return `true` if the signatures are valid, `false` otherwise - */ - function isValidSignatures( - address vault, - bytes calldata validators, - bytes calldata signatures - ) external returns (bool); + /** + * @notice Function for checking signatures of oracles for validators consolidations + * @param vault The address of the vault + * @param validators The concatenation of the validators' data + * @param signatures The concatenation of the oracles' signatures + * @return `true` if the signatures are valid, `false` otherwise + */ + function isValidSignatures(address vault, bytes calldata validators, bytes calldata signatures) + external + returns (bool); } diff --git a/contracts/interfaces/IDepositDataRegistry.sol b/contracts/interfaces/IDepositDataRegistry.sol index dca902c0..ee433b62 100644 --- a/contracts/interfaces/IDepositDataRegistry.sol +++ b/contracts/interfaces/IDepositDataRegistry.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {IKeeperValidators} from './IKeeperValidators.sol'; -import {IKeeperRewards} from './IKeeperRewards.sol'; -import {IMulticall} from './IMulticall.sol'; +import {IKeeperValidators} from "./IKeeperValidators.sol"; +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IMulticall} from "./IMulticall.sol"; /** * @title IDepositDataRegistry @@ -12,116 +12,106 @@ import {IMulticall} from './IMulticall.sol'; * @notice Defines the interface for DepositDataRegistry */ interface IDepositDataRegistry is IMulticall { - /** - * @notice Event emitted on deposit data manager update - * @param vault The address of the vault - * @param depositDataManager The address of the new deposit data manager - */ - event DepositDataManagerUpdated(address indexed vault, address depositDataManager); + /** + * @notice Event emitted on deposit data manager update + * @param vault The address of the vault + * @param depositDataManager The address of the new deposit data manager + */ + event DepositDataManagerUpdated(address indexed vault, address depositDataManager); - /** - * @notice Event emitted on deposit data root update - * @param vault The address of the vault - * @param depositDataRoot The new deposit data Merkle tree root - */ - event DepositDataRootUpdated(address indexed vault, bytes32 depositDataRoot); + /** + * @notice Event emitted on deposit data root update + * @param vault The address of the vault + * @param depositDataRoot The new deposit data Merkle tree root + */ + event DepositDataRootUpdated(address indexed vault, bytes32 depositDataRoot); - /** - * @notice Event emitted on deposit data migration - * @param vault The address of the vault - * @param depositDataRoot The deposit data root - * @param validatorIndex The index of the next validator to be registered - * @param depositDataManager The address of the deposit data manager - */ - event DepositDataMigrated( - address indexed vault, - bytes32 depositDataRoot, - uint256 validatorIndex, - address depositDataManager - ); + /** + * @notice Event emitted on deposit data migration + * @param vault The address of the vault + * @param depositDataRoot The deposit data root + * @param validatorIndex The index of the next validator to be registered + * @param depositDataManager The address of the deposit data manager + */ + event DepositDataMigrated( + address indexed vault, bytes32 depositDataRoot, uint256 validatorIndex, address depositDataManager + ); - /** - * @notice The vault deposit data index - * @param vault The address of the vault - * @return validatorIndex The index of the next validator to be registered - */ - function depositDataIndexes(address vault) external view returns (uint256 validatorIndex); + /** + * @notice The vault deposit data index + * @param vault The address of the vault + * @return validatorIndex The index of the next validator to be registered + */ + function depositDataIndexes(address vault) external view returns (uint256 validatorIndex); - /** - * @notice The vault deposit data root - * @param vault The address of the vault - * @return depositDataRoot The deposit data root - */ - function depositDataRoots(address vault) external view returns (bytes32 depositDataRoot); + /** + * @notice The vault deposit data root + * @param vault The address of the vault + * @return depositDataRoot The deposit data root + */ + function depositDataRoots(address vault) external view returns (bytes32 depositDataRoot); - /** - * @notice The vault deposit data manager. Defaults to the vault admin if not set. - * @param vault The address of the vault - * @return depositDataManager The address of the deposit data manager - */ - function getDepositDataManager(address vault) external view returns (address); + /** + * @notice The vault deposit data manager. Defaults to the vault admin if not set. + * @param vault The address of the vault + * @return depositDataManager The address of the deposit data manager + */ + function getDepositDataManager(address vault) external view returns (address); - /** - * @notice Function for setting the deposit data manager for the vault. Can only be called by the vault admin. - * @param vault The address of the vault - * @param depositDataManager The address of the new deposit data manager - */ - function setDepositDataManager(address vault, address depositDataManager) external; + /** + * @notice Function for setting the deposit data manager for the vault. Can only be called by the vault admin. + * @param vault The address of the vault + * @param depositDataManager The address of the new deposit data manager + */ + function setDepositDataManager(address vault, address depositDataManager) external; - /** - * @notice Function for setting the deposit data root for the vault. Can only be called by the deposit data manager. - * @param vault The address of the vault - * @param depositDataRoot The new deposit data Merkle tree root - */ - function setDepositDataRoot(address vault, bytes32 depositDataRoot) external; + /** + * @notice Function for setting the deposit data root for the vault. Can only be called by the deposit data manager. + * @param vault The address of the vault + * @param depositDataRoot The new deposit data Merkle tree root + */ + function setDepositDataRoot(address vault, bytes32 depositDataRoot) external; - /** - * @notice Updates the vault state. Can be used in multicall to update state and register validator(s). - * @param vault The address of the vault - * @param harvestParams The harvest params to use for updating the vault state - */ - function updateVaultState( - address vault, - IKeeperRewards.HarvestParams calldata harvestParams - ) external; + /** + * @notice Updates the vault state. Can be used in multicall to update state and register validator(s). + * @param vault The address of the vault + * @param harvestParams The harvest params to use for updating the vault state + */ + function updateVaultState(address vault, IKeeperRewards.HarvestParams calldata harvestParams) external; - /** - * @notice Function for registering single validator - * @param vault The address of the vault - * @param keeperParams The parameters for getting approval from Keeper oracles - * @param proof The proof used to verify that the validator is part of the deposit data merkle tree - */ - function registerValidator( - address vault, - IKeeperValidators.ApprovalParams calldata keeperParams, - bytes32[] calldata proof - ) external; + /** + * @notice Function for registering single validator + * @param vault The address of the vault + * @param keeperParams The parameters for getting approval from Keeper oracles + * @param proof The proof used to verify that the validator is part of the deposit data merkle tree + */ + function registerValidator( + address vault, + IKeeperValidators.ApprovalParams calldata keeperParams, + bytes32[] calldata proof + ) external; - /** - * @notice Function for registering multiple validators - * @param vault The address of the vault - * @param keeperParams The parameters for getting approval from Keeper oracles - * @param indexes The indexes of the leaves for the merkle tree multi proof verification - * @param proofFlags The multi proof flags for the merkle tree verification - * @param proof The proof used for the merkle tree verification - */ - function registerValidators( - address vault, - IKeeperValidators.ApprovalParams calldata keeperParams, - uint256[] calldata indexes, - bool[] calldata proofFlags, - bytes32[] calldata proof - ) external; + /** + * @notice Function for registering multiple validators + * @param vault The address of the vault + * @param keeperParams The parameters for getting approval from Keeper oracles + * @param indexes The indexes of the leaves for the merkle tree multi proof verification + * @param proofFlags The multi proof flags for the merkle tree verification + * @param proof The proof used for the merkle tree verification + */ + function registerValidators( + address vault, + IKeeperValidators.ApprovalParams calldata keeperParams, + uint256[] calldata indexes, + bool[] calldata proofFlags, + bytes32[] calldata proof + ) external; - /** - * @notice Function for migrating the deposit data of the Vault. Can only be called once by a vault during an upgrade. - * @param depositDataRoot The current deposit data root - * @param validatorIndex The current index of the next validator to be registered - * @param depositDataManager The address of the deposit data manager - */ - function migrate( - bytes32 depositDataRoot, - uint256 validatorIndex, - address depositDataManager - ) external; + /** + * @notice Function for migrating the deposit data of the Vault. Can only be called once by a vault during an upgrade. + * @param depositDataRoot The current deposit data root + * @param validatorIndex The current index of the next validator to be registered + * @param depositDataManager The address of the deposit data manager + */ + function migrate(bytes32 depositDataRoot, uint256 validatorIndex, address depositDataManager) external; } diff --git a/contracts/interfaces/IEthBlocklistErc20Vault.sol b/contracts/interfaces/IEthBlocklistErc20Vault.sol index 52cc4c6b..375a9579 100644 --- a/contracts/interfaces/IEthBlocklistErc20Vault.sol +++ b/contracts/interfaces/IEthBlocklistErc20Vault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IEthErc20Vault} from './IEthErc20Vault.sol'; +import {IVaultBlocklist} from "./IVaultBlocklist.sol"; +import {IEthErc20Vault} from "./IEthErc20Vault.sol"; /** * @title IEthBlocklistErc20Vault diff --git a/contracts/interfaces/IEthBlocklistVault.sol b/contracts/interfaces/IEthBlocklistVault.sol index f3fe83a2..f591f2ca 100644 --- a/contracts/interfaces/IEthBlocklistVault.sol +++ b/contracts/interfaces/IEthBlocklistVault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IEthVault} from './IEthVault.sol'; +import {IVaultBlocklist} from "./IVaultBlocklist.sol"; +import {IEthVault} from "./IEthVault.sol"; /** * @title IEthBlocklistVault diff --git a/contracts/interfaces/IEthErc20Vault.sol b/contracts/interfaces/IEthErc20Vault.sol index 5e044049..23c825dc 100644 --- a/contracts/interfaces/IEthErc20Vault.sol +++ b/contracts/interfaces/IEthErc20Vault.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.22; -import {IKeeperRewards} from './IKeeperRewards.sol'; -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultOsToken} from './IVaultOsToken.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultEthStaking} from './IVaultEthStaking.sol'; -import {IMulticall} from './IMulticall.sol'; -import {IVaultToken} from './IVaultToken.sol'; +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultMev} from "./IVaultMev.sol"; +import {IVaultEthStaking} from "./IVaultEthStaking.sol"; +import {IMulticall} from "./IMulticall.sol"; +import {IVaultToken} from "./IVaultToken.sol"; /** * @title IEthErc20Vault @@ -21,97 +21,96 @@ import {IVaultToken} from './IVaultToken.sol'; * @notice Defines the interface for the EthErc20Vault contract */ interface IEthErc20Vault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultOsToken, - IVaultMev, - IVaultToken, - IVaultEthStaking, - IMulticall + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultValidators, + IVaultEnterExit, + IVaultOsToken, + IVaultMev, + IVaultToken, + IVaultEthStaking, + IMulticall { - /** - * @dev Struct for deploying the EthErc20Vault contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for checking consolidations - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - struct EthErc20VaultConstructorArgs { - address keeper; - address vaultsRegistry; - address validatorsRegistry; - address validatorsWithdrawals; - address validatorsConsolidations; - address consolidationsChecker; - address osTokenVaultController; - address osTokenConfig; - address osTokenVaultEscrow; - address sharedMevEscrow; - address depositDataRegistry; - uint64 exitingAssetsClaimDelay; - } + /** + * @dev Struct for deploying the EthErc20Vault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct EthErc20VaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + uint64 exitingAssetsClaimDelay; + } - /** - * @dev Struct for initializing the EthErc20Vault contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param name The name of the ERC20 token - * @param symbol The symbol of the ERC20 token - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct EthErc20VaultInitParams { - uint256 capacity; - uint16 feePercent; - string name; - string symbol; - string metadataIpfsHash; - } + /** + * @dev Struct for initializing the EthErc20Vault contract + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param name The name of the ERC20 token + * @param symbol The symbol of the ERC20 token + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct EthErc20VaultInitParams { + uint256 capacity; + uint16 feePercent; + string name; + string symbol; + string metadataIpfsHash; + } - /** - * @notice Initializes or upgrades the EthErc20Vault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the EthErc20Vault contract - */ - function initialize(bytes calldata params) external payable; + /** + * @notice Initializes or upgrades the EthErc20Vault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the EthErc20Vault contract + */ + function initialize(bytes calldata params) external payable; - /** - * @notice Deposits assets to the vault and mints OsToken shares to the receiver - * @param receiver The address to receive the OsToken - * @param osTokenShares The amount of OsToken shares to mint. - * If set to type(uint256).max, max OsToken shares will be minted. - * @param referrer The address of the referrer - * @return The amount of OsToken assets minted - */ - function depositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) external payable returns (uint256); + /** + * @notice Deposits assets to the vault and mints OsToken shares to the receiver + * @param receiver The address to receive the OsToken + * @param osTokenShares The amount of OsToken shares to mint. + * If set to type(uint256).max, max OsToken shares will be minted. + * @param referrer The address of the referrer + * @return The amount of OsToken assets minted + */ + function depositAndMintOsToken(address receiver, uint256 osTokenShares, address referrer) + external + payable + returns (uint256); - /** - * @notice Updates the state, deposits assets to the vault and mints OsToken shares to the receiver - * @param receiver The address to receive the OsToken - * @param osTokenShares The amount of OsToken shares to mint. - * If set to type(uint256).max, max OsToken shares will be minted. - * @param referrer The address of the referrer - * @param harvestParams The parameters for the harvest - * @return The amount of OsToken assets minted - */ - function updateStateAndDepositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer, - IKeeperRewards.HarvestParams calldata harvestParams - ) external payable returns (uint256); + /** + * @notice Updates the state, deposits assets to the vault and mints OsToken shares to the receiver + * @param receiver The address to receive the OsToken + * @param osTokenShares The amount of OsToken shares to mint. + * If set to type(uint256).max, max OsToken shares will be minted. + * @param referrer The address of the referrer + * @param harvestParams The parameters for the harvest + * @return The amount of OsToken assets minted + */ + function updateStateAndDepositAndMintOsToken( + address receiver, + uint256 osTokenShares, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable returns (uint256); } diff --git a/contracts/interfaces/IEthFoxVault.sol b/contracts/interfaces/IEthFoxVault.sol index 8be05d2b..5d88a7e3 100644 --- a/contracts/interfaces/IEthFoxVault.sol +++ b/contracts/interfaces/IEthFoxVault.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultOsToken} from './IVaultOsToken.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultEthStaking} from './IVaultEthStaking.sol'; -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IMulticall} from './IMulticall.sol'; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultMev} from "./IVaultMev.sol"; +import {IVaultEthStaking} from "./IVaultEthStaking.sol"; +import {IVaultBlocklist} from "./IVaultBlocklist.sol"; +import {IMulticall} from "./IMulticall.sol"; /** * @title IEthFoxVault @@ -20,66 +20,62 @@ import {IMulticall} from './IMulticall.sol'; * @notice Defines the interface for the EthFoxVault contract */ interface IEthFoxVault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultMev, - IVaultEthStaking, - IVaultBlocklist, - IMulticall + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultValidators, + IVaultEnterExit, + IVaultMev, + IVaultEthStaking, + IVaultBlocklist, + IMulticall { - /** - * @notice Event emitted when a user is ejected from the Vault - * @param user The address of the user - * @param shares The amount of shares ejected - */ - event UserEjected(address user, uint256 shares); + /** + * @notice Event emitted when a user is ejected from the Vault + * @param user The address of the user + * @param shares The amount of shares ejected + */ + event UserEjected(address user, uint256 shares); - /** - * @dev Struct for initializing the EthFoxVault contract - * @param admin The address of the Vault admin - * @param ownMevEscrow The address of the MEV escrow contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct EthFoxVaultInitParams { - address admin; - address ownMevEscrow; - uint256 capacity; - uint16 feePercent; - string metadataIpfsHash; - } + /** + * @dev Struct for initializing the EthFoxVault contract + * @param admin The address of the Vault admin + * @param ownMevEscrow The address of the MEV escrow contract + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct EthFoxVaultInitParams { + address admin; + address ownMevEscrow; + uint256 capacity; + uint16 feePercent; + string metadataIpfsHash; + } - /** - * @notice Event emitted on EthFoxVault creation - * @param admin The address of the Vault admin - * @param ownMevEscrow The address of the MEV escrow contract - * @param capacity The capacity of the Vault - * @param feePercent The fee percent of the Vault - * @param metadataIpfsHash The IPFS hash of the Vault metadata - */ - event EthFoxVaultCreated( - address admin, - address ownMevEscrow, - uint256 capacity, - uint16 feePercent, - string metadataIpfsHash - ); + /** + * @notice Event emitted on EthFoxVault creation + * @param admin The address of the Vault admin + * @param ownMevEscrow The address of the MEV escrow contract + * @param capacity The capacity of the Vault + * @param feePercent The fee percent of the Vault + * @param metadataIpfsHash The IPFS hash of the Vault metadata + */ + event EthFoxVaultCreated( + address admin, address ownMevEscrow, uint256 capacity, uint16 feePercent, string metadataIpfsHash + ); - /** - * @notice Initializes or upgrades the EthFoxVault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the EthFoxVault contract - */ - function initialize(bytes calldata params) external payable; + /** + * @notice Initializes or upgrades the EthFoxVault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the EthFoxVault contract + */ + function initialize(bytes calldata params) external payable; - /** - * @notice Ejects user from the Vault. Can only be called by the blocklist manager. - * The ejected user will be added to the blocklist and all his shares will be sent to the exit queue. - * @param user The address of the user to eject - */ - function ejectUser(address user) external; + /** + * @notice Ejects user from the Vault. Can only be called by the blocklist manager. + * The ejected user will be added to the blocklist and all his shares will be sent to the exit queue. + * @param user The address of the user to eject + */ + function ejectUser(address user) external; } diff --git a/contracts/interfaces/IEthGenesisVault.sol b/contracts/interfaces/IEthGenesisVault.sol index 07d2fc19..095309a5 100644 --- a/contracts/interfaces/IEthGenesisVault.sol +++ b/contracts/interfaces/IEthGenesisVault.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IEthVault} from './IEthVault.sol'; +import {IEthVault} from "./IEthVault.sol"; /** * @title IEthGenesisVault @@ -10,33 +10,28 @@ import {IEthVault} from './IEthVault.sol'; * @notice Defines the interface for the EthGenesisVault contract */ interface IEthGenesisVault is IEthVault { - /** - * @notice Event emitted on migration from StakeWise Legacy - * @param receiver The address of the shares receiver - * @param assets The amount of assets migrated - * @param shares The amount of shares migrated - */ - event Migrated(address receiver, uint256 assets, uint256 shares); + /** + * @notice Event emitted on migration from StakeWise Legacy + * @param receiver The address of the shares receiver + * @param assets The amount of assets migrated + * @param shares The amount of shares migrated + */ + event Migrated(address receiver, uint256 assets, uint256 shares); - /** - * @notice Event emitted on EthGenesisVault creation (deprecated) - * @param admin The address of the Vault admin - * @param capacity The capacity of the Vault - * @param feePercent The fee percent of the Vault - * @param metadataIpfsHash The IPFS hash of the Vault metadata - */ - event GenesisVaultCreated( - address admin, - uint256 capacity, - uint16 feePercent, - string metadataIpfsHash - ); + /** + * @notice Event emitted on EthGenesisVault creation (deprecated) + * @param admin The address of the Vault admin + * @param capacity The capacity of the Vault + * @param feePercent The fee percent of the Vault + * @param metadataIpfsHash The IPFS hash of the Vault metadata + */ + event GenesisVaultCreated(address admin, uint256 capacity, uint16 feePercent, string metadataIpfsHash); - /** - * @notice Function for migrating from StakeWise Legacy. Can be called only by RewardEthToken contract. - * @param receiver The address of the receiver - * @param assets The amount of assets migrated - * @return shares The amount of shares minted - */ - function migrate(address receiver, uint256 assets) external returns (uint256 shares); + /** + * @notice Function for migrating from StakeWise Legacy. Can be called only by RewardEthToken contract. + * @param receiver The address of the receiver + * @param assets The amount of assets migrated + * @return shares The amount of shares minted + */ + function migrate(address receiver, uint256 assets) external returns (uint256 shares); } diff --git a/contracts/interfaces/IEthPoolEscrow.sol b/contracts/interfaces/IEthPoolEscrow.sol index e497abc2..ec717ae2 100644 --- a/contracts/interfaces/IEthPoolEscrow.sol +++ b/contracts/interfaces/IEthPoolEscrow.sol @@ -9,59 +9,59 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the PoolEscrow contract on Ethereum */ interface IEthPoolEscrow { - /** - * @notice Event for tracking withdrawn ether - * @param sender The address of the transaction sender - * @param payee The address where the funds were transferred to - * @param amount The amount of ether transferred to payee - */ - event Withdrawn(address indexed sender, address indexed payee, uint256 amount); + /** + * @notice Event for tracking withdrawn ether + * @param sender The address of the transaction sender + * @param payee The address where the funds were transferred to + * @param amount The amount of ether transferred to payee + */ + event Withdrawn(address indexed sender, address indexed payee, uint256 amount); - /** - * @notice Event for tracking ownership transfer commits - * @param currentOwner The address of the current owner - * @param futureOwner The address the ownership is planned to be transferred to - */ - event OwnershipTransferCommitted(address indexed currentOwner, address indexed futureOwner); + /** + * @notice Event for tracking ownership transfer commits + * @param currentOwner The address of the current owner + * @param futureOwner The address the ownership is planned to be transferred to + */ + event OwnershipTransferCommitted(address indexed currentOwner, address indexed futureOwner); - /** - * @notice Event for tracking ownership transfers - * @param previousOwner The address the ownership was transferred from - * @param newOwner The address the ownership was transferred to - */ - event OwnershipTransferApplied(address indexed previousOwner, address indexed newOwner); + /** + * @notice Event for tracking ownership transfers + * @param previousOwner The address the ownership was transferred from + * @param newOwner The address the ownership was transferred to + */ + event OwnershipTransferApplied(address indexed previousOwner, address indexed newOwner); - /** - * @dev Function for retrieving the address of the current owner - * @return The address of the current owner - */ - function owner() external view returns (address); + /** + * @dev Function for retrieving the address of the current owner + * @return The address of the current owner + */ + function owner() external view returns (address); - /** - * @notice Function for retrieving the address of the future owner - * @return The address of the future owner - */ - function futureOwner() external view returns (address); + /** + * @notice Function for retrieving the address of the future owner + * @return The address of the future owner + */ + function futureOwner() external view returns (address); - /** - * @notice Commit contract ownership transfer to a new account (`newOwner`). Can only be called by the current owner. - * @param newOwner The address the ownership is planned to be transferred to - */ - function commitOwnershipTransfer(address newOwner) external; + /** + * @notice Commit contract ownership transfer to a new account (`newOwner`). Can only be called by the current owner. + * @param newOwner The address the ownership is planned to be transferred to + */ + function commitOwnershipTransfer(address newOwner) external; - /** - * @notice Apply contract ownership transfer to a new account (`futureOwner`). Can only be called by the future owner. - */ - function applyOwnershipTransfer() external; + /** + * @notice Apply contract ownership transfer to a new account (`futureOwner`). Can only be called by the future owner. + */ + function applyOwnershipTransfer() external; - /** - * @notice Withdraw balance for a payee, forwarding all gas to the - * recipient. Can only be called by the current owner. - * @dev WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. - * Make sure you trust the recipient, or are either following the - * checks-effects-interactions pattern or using {ReentrancyGuard}. - * @param payee The address where the funds will be transferred to - * @param amount The amount of ether to transfer to payee - */ - function withdraw(address payable payee, uint256 amount) external; + /** + * @notice Withdraw balance for a payee, forwarding all gas to the + * recipient. Can only be called by the current owner. + * @dev WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. + * Make sure you trust the recipient, or are either following the + * checks-effects-interactions pattern or using {ReentrancyGuard}. + * @param payee The address where the funds will be transferred to + * @param amount The amount of ether to transfer to payee + */ + function withdraw(address payable payee, uint256 amount) external; } diff --git a/contracts/interfaces/IEthPrivErc20Vault.sol b/contracts/interfaces/IEthPrivErc20Vault.sol index 11941cc8..0e623231 100644 --- a/contracts/interfaces/IEthPrivErc20Vault.sol +++ b/contracts/interfaces/IEthPrivErc20Vault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultWhitelist} from './IVaultWhitelist.sol'; -import {IEthErc20Vault} from './IEthErc20Vault.sol'; +import {IVaultWhitelist} from "./IVaultWhitelist.sol"; +import {IEthErc20Vault} from "./IEthErc20Vault.sol"; /** * @title IEthPrivErc20Vault diff --git a/contracts/interfaces/IEthPrivVault.sol b/contracts/interfaces/IEthPrivVault.sol index 464c2835..8ea1f71c 100644 --- a/contracts/interfaces/IEthPrivVault.sol +++ b/contracts/interfaces/IEthPrivVault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultWhitelist} from './IVaultWhitelist.sol'; -import {IEthVault} from './IEthVault.sol'; +import {IVaultWhitelist} from "./IVaultWhitelist.sol"; +import {IEthVault} from "./IEthVault.sol"; /** * @title IEthPrivVault diff --git a/contracts/interfaces/IEthValidatorsRegistry.sol b/contracts/interfaces/IEthValidatorsRegistry.sol index c917d091..f2256ca8 100644 --- a/contracts/interfaces/IEthValidatorsRegistry.sol +++ b/contracts/interfaces/IEthValidatorsRegistry.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IValidatorsRegistry} from './IValidatorsRegistry.sol'; +import {IValidatorsRegistry} from "./IValidatorsRegistry.sol"; /** * @title IEthValidatorsRegistry @@ -12,16 +12,16 @@ import {IValidatorsRegistry} from './IValidatorsRegistry.sol'; * For more information see the Phase 0 specification under https://github.com/ethereum/consensus-specs. */ interface IEthValidatorsRegistry is IValidatorsRegistry { - /// @notice Submit a Phase 0 DepositData object. - /// @param pubkey A BLS12-381 public key. - /// @param withdrawal_credentials Commitment to a public key for withdrawals. - /// @param signature A BLS12-381 signature. - /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. - /// Used as a protection against malformed input. - function deposit( - bytes calldata pubkey, - bytes calldata withdrawal_credentials, - bytes calldata signature, - bytes32 deposit_data_root - ) external payable; + /// @notice Submit a Phase 0 DepositData object. + /// @param pubkey A BLS12-381 public key. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signature A BLS12-381 signature. + /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. + /// Used as a protection against malformed input. + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) external payable; } diff --git a/contracts/interfaces/IEthVault.sol b/contracts/interfaces/IEthVault.sol index b554b338..e63af9e5 100644 --- a/contracts/interfaces/IEthVault.sol +++ b/contracts/interfaces/IEthVault.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {IKeeperRewards} from './IKeeperRewards.sol'; -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultOsToken} from './IVaultOsToken.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultEthStaking} from './IVaultEthStaking.sol'; -import {IMulticall} from './IMulticall.sol'; +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultMev} from "./IVaultMev.sol"; +import {IVaultEthStaking} from "./IVaultEthStaking.sol"; +import {IMulticall} from "./IMulticall.sol"; /** * @title IEthVault @@ -20,92 +20,91 @@ import {IMulticall} from './IMulticall.sol'; * @notice Defines the interface for the EthVault contract */ interface IEthVault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultOsToken, - IVaultMev, - IVaultEthStaking, - IMulticall + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultValidators, + IVaultEnterExit, + IVaultOsToken, + IVaultMev, + IVaultEthStaking, + IMulticall { - /** - * @dev Struct for deploying the EthVault contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for checking consolidations - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - struct EthVaultConstructorArgs { - address keeper; - address vaultsRegistry; - address validatorsRegistry; - address validatorsWithdrawals; - address validatorsConsolidations; - address consolidationsChecker; - address osTokenVaultController; - address osTokenConfig; - address osTokenVaultEscrow; - address sharedMevEscrow; - address depositDataRegistry; - uint64 exitingAssetsClaimDelay; - } + /** + * @dev Struct for deploying the EthVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct EthVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + uint64 exitingAssetsClaimDelay; + } - /** - * @dev Struct for initializing the EthVault contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct EthVaultInitParams { - uint256 capacity; - uint16 feePercent; - string metadataIpfsHash; - } + /** + * @dev Struct for initializing the EthVault contract + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct EthVaultInitParams { + uint256 capacity; + uint16 feePercent; + string metadataIpfsHash; + } - /** - * @notice Initializes or upgrades the EthVault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the EthVault contract - */ - function initialize(bytes calldata params) external payable; + /** + * @notice Initializes or upgrades the EthVault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the EthVault contract + */ + function initialize(bytes calldata params) external payable; - /** - * @notice Deposits assets to the vault and mints OsToken shares to the receiver - * @param receiver The address to receive the OsToken - * @param osTokenShares The amount of OsToken shares to mint. - * If set to type(uint256).max, max OsToken shares will be minted. - * @param referrer The address of the referrer - * @return The amount of OsToken assets minted - */ - function depositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) external payable returns (uint256); + /** + * @notice Deposits assets to the vault and mints OsToken shares to the receiver + * @param receiver The address to receive the OsToken + * @param osTokenShares The amount of OsToken shares to mint. + * If set to type(uint256).max, max OsToken shares will be minted. + * @param referrer The address of the referrer + * @return The amount of OsToken assets minted + */ + function depositAndMintOsToken(address receiver, uint256 osTokenShares, address referrer) + external + payable + returns (uint256); - /** - * @notice Updates the state, deposits assets to the vault and mints OsToken shares to the receiver - * @param receiver The address to receive the OsToken - * @param osTokenShares The amount of OsToken shares to mint. - * If set to type(uint256).max, max OsToken shares will be minted. - * @param referrer The address of the referrer - * @param harvestParams The parameters for the harvest - * @return The amount of OsToken assets minted - */ - function updateStateAndDepositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer, - IKeeperRewards.HarvestParams calldata harvestParams - ) external payable returns (uint256); + /** + * @notice Updates the state, deposits assets to the vault and mints OsToken shares to the receiver + * @param receiver The address to receive the OsToken + * @param osTokenShares The amount of OsToken shares to mint. + * If set to type(uint256).max, max OsToken shares will be minted. + * @param referrer The address of the referrer + * @param harvestParams The parameters for the harvest + * @return The amount of OsToken assets minted + */ + function updateStateAndDepositAndMintOsToken( + address receiver, + uint256 osTokenShares, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable returns (uint256); } diff --git a/contracts/interfaces/IEthVaultFactory.sol b/contracts/interfaces/IEthVaultFactory.sol index 2ac615ad..43e43d3c 100644 --- a/contracts/interfaces/IEthVaultFactory.sol +++ b/contracts/interfaces/IEthVaultFactory.sol @@ -8,46 +8,38 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the ETH Vault Factory contract */ interface IEthVaultFactory { - /** - * @notice Event emitted on a Vault creation - * @param admin The address of the Vault admin - * @param vault The address of the created Vault - * @param ownMevEscrow The address of the own MEV escrow contract. Zero address if shared MEV escrow is used. - * @param params The encoded parameters for initializing the Vault contract - */ - event VaultCreated( - address indexed admin, - address indexed vault, - address ownMevEscrow, - bytes params - ); + /** + * @notice Event emitted on a Vault creation + * @param admin The address of the Vault admin + * @param vault The address of the created Vault + * @param ownMevEscrow The address of the own MEV escrow contract. Zero address if shared MEV escrow is used. + * @param params The encoded parameters for initializing the Vault contract + */ + event VaultCreated(address indexed admin, address indexed vault, address ownMevEscrow, bytes params); - /** - * @notice The address of the Vault implementation contract used for proxy creation - * @return The address of the Vault implementation contract - */ - function implementation() external view returns (address); + /** + * @notice The address of the Vault implementation contract used for proxy creation + * @return The address of the Vault implementation contract + */ + function implementation() external view returns (address); - /** - * @notice The address of the own MEV escrow contract used for Vault creation - * @return The address of the MEV escrow contract - */ - function ownMevEscrow() external view returns (address); + /** + * @notice The address of the own MEV escrow contract used for Vault creation + * @return The address of the MEV escrow contract + */ + function ownMevEscrow() external view returns (address); - /** - * @notice The address of the Vault admin used for Vault creation - * @return The address of the Vault admin - */ - function vaultAdmin() external view returns (address); + /** + * @notice The address of the Vault admin used for Vault creation + * @return The address of the Vault admin + */ + function vaultAdmin() external view returns (address); - /** - * @notice Create Vault. Must transfer security deposit together with a call. - * @param params The encoded parameters for initializing the Vault contract - * @param isOwnMevEscrow Whether to deploy own escrow contract or connect to a smoothing pool for priority fees and MEV rewards - * @return vault The address of the created Vault - */ - function createVault( - bytes calldata params, - bool isOwnMevEscrow - ) external payable returns (address vault); + /** + * @notice Create Vault. Must transfer security deposit together with a call. + * @param params The encoded parameters for initializing the Vault contract + * @param isOwnMevEscrow Whether to deploy own escrow contract or connect to a smoothing pool for priority fees and MEV rewards + * @return vault The address of the created Vault + */ + function createVault(bytes calldata params, bool isOwnMevEscrow) external payable returns (address vault); } diff --git a/contracts/interfaces/IGnoBlocklistErc20Vault.sol b/contracts/interfaces/IGnoBlocklistErc20Vault.sol index 9d6ac4c9..1f8d3662 100644 --- a/contracts/interfaces/IGnoBlocklistErc20Vault.sol +++ b/contracts/interfaces/IGnoBlocklistErc20Vault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IGnoErc20Vault} from './IGnoErc20Vault.sol'; +import {IVaultBlocklist} from "./IVaultBlocklist.sol"; +import {IGnoErc20Vault} from "./IGnoErc20Vault.sol"; /** * @title IGnoBlocklistErc20Vault diff --git a/contracts/interfaces/IGnoBlocklistVault.sol b/contracts/interfaces/IGnoBlocklistVault.sol index 1081525a..a803c014 100644 --- a/contracts/interfaces/IGnoBlocklistVault.sol +++ b/contracts/interfaces/IGnoBlocklistVault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultBlocklist} from './IVaultBlocklist.sol'; -import {IGnoVault} from './IGnoVault.sol'; +import {IVaultBlocklist} from "./IVaultBlocklist.sol"; +import {IGnoVault} from "./IGnoVault.sol"; /** * @title IGnoBlocklistVault diff --git a/contracts/interfaces/IGnoDaiDistributor.sol b/contracts/interfaces/IGnoDaiDistributor.sol index 16bea413..ac950d72 100644 --- a/contracts/interfaces/IGnoDaiDistributor.sol +++ b/contracts/interfaces/IGnoDaiDistributor.sol @@ -8,15 +8,15 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the GnoDaiDistributor */ interface IGnoDaiDistributor { - /** - * @notice Event emitted when sDAI is distributed to the users - * @param vault The address of the vault - * @param amount The amount of sDAI distributed - */ - event SDaiDistributed(address indexed vault, uint256 amount); + /** + * @notice Event emitted when sDAI is distributed to the users + * @param vault The address of the vault + * @param amount The amount of sDAI distributed + */ + event SDaiDistributed(address indexed vault, uint256 amount); - /** - * @notice Distribute sDAI to the users. Can be called only by the vaults. Must transfer xDAI together with the call. - */ - function distributeSDai() external payable; + /** + * @notice Distribute sDAI to the users. Can be called only by the vaults. Must transfer xDAI together with the call. + */ + function distributeSDai() external payable; } diff --git a/contracts/interfaces/IGnoErc20Vault.sol b/contracts/interfaces/IGnoErc20Vault.sol index 2f96c14e..4d3527bf 100644 --- a/contracts/interfaces/IGnoErc20Vault.sol +++ b/contracts/interfaces/IGnoErc20Vault.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultOsToken} from './IVaultOsToken.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultGnoStaking} from './IVaultGnoStaking.sol'; -import {IMulticall} from './IMulticall.sol'; -import {IVaultToken} from './IVaultToken.sol'; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultMev} from "./IVaultMev.sol"; +import {IVaultGnoStaking} from "./IVaultGnoStaking.sol"; +import {IMulticall} from "./IMulticall.sol"; +import {IVaultToken} from "./IVaultToken.sol"; /** * @title IGnoErc20Vault @@ -20,71 +20,71 @@ import {IVaultToken} from './IVaultToken.sol'; * @notice Defines the interface for the GnoErc20Vault contract */ interface IGnoErc20Vault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultOsToken, - IVaultMev, - IVaultToken, - IVaultGnoStaking, - IMulticall + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultValidators, + IVaultEnterExit, + IVaultOsToken, + IVaultMev, + IVaultToken, + IVaultGnoStaking, + IMulticall { - /** - * @notice Struct for initializing the GnoErc20Vault contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for checking consolidations - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param gnoDaiDistributor The address of the GnoDaiDistributor contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - struct GnoErc20VaultConstructorArgs { - address keeper; - address vaultsRegistry; - address validatorsRegistry; - address validatorsWithdrawals; - address validatorsConsolidations; - address consolidationsChecker; - address osTokenVaultController; - address osTokenConfig; - address osTokenVaultEscrow; - address sharedMevEscrow; - address depositDataRegistry; - address gnoToken; - address gnoDaiDistributor; - uint256 exitingAssetsClaimDelay; - } + /** + * @notice Struct for initializing the GnoErc20Vault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param gnoToken The address of the GNO token + * @param gnoDaiDistributor The address of the GnoDaiDistributor contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct GnoErc20VaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + address gnoToken; + address gnoDaiDistributor; + uint256 exitingAssetsClaimDelay; + } - /** - * @dev Struct for initializing the GnoErc20Vault contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param name The name of the ERC20 token - * @param symbol The symbol of the ERC20 token - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct GnoErc20VaultInitParams { - uint256 capacity; - uint16 feePercent; - string name; - string symbol; - string metadataIpfsHash; - } + /** + * @dev Struct for initializing the GnoErc20Vault contract + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param name The name of the ERC20 token + * @param symbol The symbol of the ERC20 token + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct GnoErc20VaultInitParams { + uint256 capacity; + uint16 feePercent; + string name; + string symbol; + string metadataIpfsHash; + } - /** - * @notice Initializes or upgrades the GnoErc20Vault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the GnoErc20Vault contract - */ - function initialize(bytes calldata params) external; + /** + * @notice Initializes or upgrades the GnoErc20Vault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the GnoErc20Vault contract + */ + function initialize(bytes calldata params) external; } diff --git a/contracts/interfaces/IGnoGenesisVault.sol b/contracts/interfaces/IGnoGenesisVault.sol index 715f73b3..1d18b234 100644 --- a/contracts/interfaces/IGnoGenesisVault.sol +++ b/contracts/interfaces/IGnoGenesisVault.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IGnoVault} from './IGnoVault.sol'; +import {IGnoVault} from "./IGnoVault.sol"; /** * @title IGnoGenesisVault @@ -10,33 +10,28 @@ import {IGnoVault} from './IGnoVault.sol'; * @notice Defines the interface for the GnoGenesisVault contract */ interface IGnoGenesisVault is IGnoVault { - /** - * @notice Event emitted on migration from StakeWise Legacy - * @param receiver The address of the shares receiver - * @param assets The amount of assets migrated - * @param shares The amount of shares migrated - */ - event Migrated(address receiver, uint256 assets, uint256 shares); + /** + * @notice Event emitted on migration from StakeWise Legacy + * @param receiver The address of the shares receiver + * @param assets The amount of assets migrated + * @param shares The amount of shares migrated + */ + event Migrated(address receiver, uint256 assets, uint256 shares); - /** - * @notice Event emitted on GnoGenesisVault creation (deprecated) - * @param admin The address of the Vault admin - * @param capacity The capacity of the Vault - * @param feePercent The fee percent of the Vault - * @param metadataIpfsHash The IPFS hash of the Vault metadata - */ - event GenesisVaultCreated( - address admin, - uint256 capacity, - uint16 feePercent, - string metadataIpfsHash - ); + /** + * @notice Event emitted on GnoGenesisVault creation (deprecated) + * @param admin The address of the Vault admin + * @param capacity The capacity of the Vault + * @param feePercent The fee percent of the Vault + * @param metadataIpfsHash The IPFS hash of the Vault metadata + */ + event GenesisVaultCreated(address admin, uint256 capacity, uint16 feePercent, string metadataIpfsHash); - /** - * @notice Function for migrating from StakeWise Legacy. Can be called only by RewardGnoToken contract. - * @param receiver The address of the receiver - * @param assets The amount of assets migrated - * @return shares The amount of shares minted - */ - function migrate(address receiver, uint256 assets) external returns (uint256 shares); + /** + * @notice Function for migrating from StakeWise Legacy. Can be called only by RewardGnoToken contract. + * @param receiver The address of the receiver + * @param assets The amount of assets migrated + * @return shares The amount of shares minted + */ + function migrate(address receiver, uint256 assets) external returns (uint256 shares); } diff --git a/contracts/interfaces/IGnoPoolEscrow.sol b/contracts/interfaces/IGnoPoolEscrow.sol index 9fcb4060..c45ca846 100644 --- a/contracts/interfaces/IGnoPoolEscrow.sol +++ b/contracts/interfaces/IGnoPoolEscrow.sol @@ -9,68 +9,68 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the PoolEscrow contract on Gnosis */ interface IGnoPoolEscrow { - /** - * @dev Event for tracking withdrawals. - * @param sender - the address of the transaction sender. - * @param payee - the address where the funds were transferred to. - * @param amount - the amount transferred to payee. - */ - event Withdrawn(address indexed sender, address indexed payee, uint256 amount); + /** + * @dev Event for tracking withdrawals. + * @param sender - the address of the transaction sender. + * @param payee - the address where the funds were transferred to. + * @param amount - the amount transferred to payee. + */ + event Withdrawn(address indexed sender, address indexed payee, uint256 amount); - /** - * @dev Event for tracking ownership transfer commits. - * @param currentOwner - the address of the current owner. - * @param futureOwner - the address the ownership is planned to be transferred to. - */ - event OwnershipTransferCommitted(address indexed currentOwner, address indexed futureOwner); + /** + * @dev Event for tracking ownership transfer commits. + * @param currentOwner - the address of the current owner. + * @param futureOwner - the address the ownership is planned to be transferred to. + */ + event OwnershipTransferCommitted(address indexed currentOwner, address indexed futureOwner); - /** - * @dev Event for tracking ownership transfers. - * @param previousOwner - the address the ownership was transferred from. - * @param newOwner - the address the ownership was transferred to. - */ - event OwnershipTransferApplied(address indexed previousOwner, address indexed newOwner); + /** + * @dev Event for tracking ownership transfers. + * @param previousOwner - the address the ownership was transferred from. + * @param newOwner - the address the ownership was transferred to. + */ + event OwnershipTransferApplied(address indexed previousOwner, address indexed newOwner); - /** - * @dev Function for retrieving the address of the current owner. - */ - function owner() external view returns (address); + /** + * @dev Function for retrieving the address of the current owner. + */ + function owner() external view returns (address); - /** - * @dev Function for retrieving the address of the future owner. - */ - function futureOwner() external view returns (address); + /** + * @dev Function for retrieving the address of the future owner. + */ + function futureOwner() external view returns (address); - /** - * @dev Commit contract ownership transfer to a new account (`newOwner`). - * Can only be called by the current owner. - */ - function commitOwnershipTransfer(address newOwner) external; + /** + * @dev Commit contract ownership transfer to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function commitOwnershipTransfer(address newOwner) external; - /** - * @dev Apply contract ownership transfer to a new account (`futureOwner`). - * Can only be called by the future owner. - */ - function applyOwnershipTransfer() external; + /** + * @dev Apply contract ownership transfer to a new account (`futureOwner`). + * Can only be called by the future owner. + */ + function applyOwnershipTransfer() external; - /** - * @dev Withdraw tokens from the escrow. Can only be called by the current owner. - * @param token - the address of the token to transfer. - * @param payee - the address where the funds will be transferred to. - * @param amount - the amount of tokens to transfer to payee. - */ - function withdrawTokens(address token, address payee, uint256 amount) external; + /** + * @dev Withdraw tokens from the escrow. Can only be called by the current owner. + * @param token - the address of the token to transfer. + * @param payee - the address where the funds will be transferred to. + * @param amount - the amount of tokens to transfer to payee. + */ + function withdrawTokens(address token, address payee, uint256 amount) external; - /** - * @dev Withdraw balance for a payee, forwarding all gas to the - * recipient. Can only be called by the current owner. - * - * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. - * Make sure you trust the recipient, or are either following the - * checks-effects-interactions pattern or using {ReentrancyGuard}. - * - * @param payee - the address where the funds will be transferred to. - * @param amount - the amount of xDAI to transfer to payee. - */ - function withdraw(address payable payee, uint256 amount) external; + /** + * @dev Withdraw balance for a payee, forwarding all gas to the + * recipient. Can only be called by the current owner. + * + * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. + * Make sure you trust the recipient, or are either following the + * checks-effects-interactions pattern or using {ReentrancyGuard}. + * + * @param payee - the address where the funds will be transferred to. + * @param amount - the amount of xDAI to transfer to payee. + */ + function withdraw(address payable payee, uint256 amount) external; } diff --git a/contracts/interfaces/IGnoPrivErc20Vault.sol b/contracts/interfaces/IGnoPrivErc20Vault.sol index 8ed745df..6a788f95 100644 --- a/contracts/interfaces/IGnoPrivErc20Vault.sol +++ b/contracts/interfaces/IGnoPrivErc20Vault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultWhitelist} from './IVaultWhitelist.sol'; -import {IGnoErc20Vault} from './IGnoErc20Vault.sol'; +import {IVaultWhitelist} from "./IVaultWhitelist.sol"; +import {IGnoErc20Vault} from "./IGnoErc20Vault.sol"; /** * @title IGnoPrivErc20Vault diff --git a/contracts/interfaces/IGnoPrivVault.sol b/contracts/interfaces/IGnoPrivVault.sol index c0019285..0475bae6 100644 --- a/contracts/interfaces/IGnoPrivVault.sol +++ b/contracts/interfaces/IGnoPrivVault.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultWhitelist} from './IVaultWhitelist.sol'; -import {IGnoVault} from './IGnoVault.sol'; +import {IVaultWhitelist} from "./IVaultWhitelist.sol"; +import {IGnoVault} from "./IGnoVault.sol"; /** * @title IGnoPrivVault diff --git a/contracts/interfaces/IGnoValidatorsRegistry.sol b/contracts/interfaces/IGnoValidatorsRegistry.sol index 51a86bd5..47b6677b 100644 --- a/contracts/interfaces/IGnoValidatorsRegistry.sol +++ b/contracts/interfaces/IGnoValidatorsRegistry.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IValidatorsRegistry} from './IValidatorsRegistry.sol'; +import {IValidatorsRegistry} from "./IValidatorsRegistry.sol"; /** * @title IGnoValidatorsRegistry @@ -11,37 +11,37 @@ import {IValidatorsRegistry} from './IValidatorsRegistry.sol'; * See https://github.com/gnosischain/deposit-contract/blob/master/contracts/SBCDepositContract.sol. */ interface IGnoValidatorsRegistry is IValidatorsRegistry { - /// @notice The amount of GNO that is withdrawable by the address - function withdrawableAmount(address _address) external view returns (uint256); + /// @notice The amount of GNO that is withdrawable by the address + function withdrawableAmount(address _address) external view returns (uint256); - /// @notice Submit a Phase 0 DepositData object. - /// @param pubkey A BLS12-381 public key. - /// @param withdrawal_credentials Commitment to a public key for withdrawals. - /// @param signature A BLS12-381 signature. - /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. - /// @param stake_amount The amount of GNO to stake. - /// Used as a protection against malformed input. - function deposit( - bytes memory pubkey, - bytes memory withdrawal_credentials, - bytes memory signature, - bytes32 deposit_data_root, - uint256 stake_amount - ) external; + /// @notice Submit a Phase 0 DepositData object. + /// @param pubkey A BLS12-381 public key. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signature A BLS12-381 signature. + /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. + /// @param stake_amount The amount of GNO to stake. + /// Used as a protection against malformed input. + function deposit( + bytes memory pubkey, + bytes memory withdrawal_credentials, + bytes memory signature, + bytes32 deposit_data_root, + uint256 stake_amount + ) external; - /// @notice Submit multiple Phase 0 DepositData objects. - /// @param pubkeys Concatenated array of BLS12-381 public keys. - /// @param withdrawal_credentials Commitment to a public key for withdrawals. - /// @param signatures Concatenated array of BLS12-381 signatures. - /// @param deposit_data_roots Array of SHA-256 hashes of the SSZ-encoded DepositData objects. - function batchDeposit( - bytes calldata pubkeys, - bytes calldata withdrawal_credentials, - bytes calldata signatures, - bytes32[] calldata deposit_data_roots - ) external; + /// @notice Submit multiple Phase 0 DepositData objects. + /// @param pubkeys Concatenated array of BLS12-381 public keys. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signatures Concatenated array of BLS12-381 signatures. + /// @param deposit_data_roots Array of SHA-256 hashes of the SSZ-encoded DepositData objects. + function batchDeposit( + bytes calldata pubkeys, + bytes calldata withdrawal_credentials, + bytes calldata signatures, + bytes32[] calldata deposit_data_roots + ) external; - /// @notice Claim withdrawal amount for an address. - /// @param _address Address to transfer withdrawable tokens. - function claimWithdrawal(address _address) external; + /// @notice Claim withdrawal amount for an address. + /// @param _address Address to transfer withdrawable tokens. + function claimWithdrawal(address _address) external; } diff --git a/contracts/interfaces/IGnoVault.sol b/contracts/interfaces/IGnoVault.sol index 3c3c3ccc..3333aae7 100644 --- a/contracts/interfaces/IGnoVault.sol +++ b/contracts/interfaces/IGnoVault.sol @@ -2,16 +2,16 @@ pragma solidity ^0.8.22; -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultVersion} from './IVaultVersion.sol'; -import {IVaultFee} from './IVaultFee.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IVaultOsToken} from './IVaultOsToken.sol'; -import {IVaultMev} from './IVaultMev.sol'; -import {IVaultGnoStaking} from './IVaultGnoStaking.sol'; -import {IMulticall} from './IMulticall.sol'; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultMev} from "./IVaultMev.sol"; +import {IVaultGnoStaking} from "./IVaultGnoStaking.sol"; +import {IMulticall} from "./IMulticall.sol"; /** * @title IGnoVault @@ -19,66 +19,66 @@ import {IMulticall} from './IMulticall.sol'; * @notice Defines the interface for the GnoVault contract */ interface IGnoVault is - IVaultAdmin, - IVaultVersion, - IVaultFee, - IVaultState, - IVaultValidators, - IVaultEnterExit, - IVaultOsToken, - IVaultMev, - IVaultGnoStaking, - IMulticall + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultValidators, + IVaultEnterExit, + IVaultOsToken, + IVaultMev, + IVaultGnoStaking, + IMulticall { - /** - * @notice Struct for initializing the GnoVault contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for checking consolidations - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the GNO token - * @param gnoDaiDistributor The address of the GnoDaiDistributor contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - struct GnoVaultConstructorArgs { - address keeper; - address vaultsRegistry; - address validatorsRegistry; - address validatorsWithdrawals; - address validatorsConsolidations; - address consolidationsChecker; - address osTokenVaultController; - address osTokenConfig; - address osTokenVaultEscrow; - address sharedMevEscrow; - address depositDataRegistry; - address gnoToken; - address gnoDaiDistributor; - uint256 exitingAssetsClaimDelay; - } + /** + * @notice Struct for initializing the GnoVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param gnoToken The address of the GNO token + * @param gnoDaiDistributor The address of the GnoDaiDistributor contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct GnoVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + address gnoToken; + address gnoDaiDistributor; + uint256 exitingAssetsClaimDelay; + } - /** - * @notice Struct for initializing the GnoVault contract - * @param capacity The Vault stops accepting deposits after exceeding the capacity - * @param feePercent The fee percent that is charged by the Vault - * @param metadataIpfsHash The IPFS hash of the Vault's metadata file - */ - struct GnoVaultInitParams { - uint256 capacity; - uint16 feePercent; - string metadataIpfsHash; - } + /** + * @notice Struct for initializing the GnoVault contract + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct GnoVaultInitParams { + uint256 capacity; + uint16 feePercent; + string metadataIpfsHash; + } - /** - * @notice Initializes or upgrades the GnoVault contract. Must transfer security deposit during the deployment. - * @param params The encoded parameters for initializing the GnoVault contract - */ - function initialize(bytes calldata params) external; + /** + * @notice Initializes or upgrades the GnoVault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the GnoVault contract + */ + function initialize(bytes calldata params) external; } diff --git a/contracts/interfaces/IGnoVaultFactory.sol b/contracts/interfaces/IGnoVaultFactory.sol index 2b71a544..1045960b 100644 --- a/contracts/interfaces/IGnoVaultFactory.sol +++ b/contracts/interfaces/IGnoVaultFactory.sol @@ -8,43 +8,38 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the GNO Vault Factory contract */ interface IGnoVaultFactory { - /** - * @notice Event emitted on a Vault creation - * @param admin The address of the Vault admin - * @param vault The address of the created Vault - * @param ownMevEscrow The address of the own MEV escrow contract. Zero address if shared MEV escrow is used. - * @param params The encoded parameters for initializing the Vault contract - */ - event VaultCreated( - address indexed admin, - address indexed vault, - address ownMevEscrow, - bytes params - ); + /** + * @notice Event emitted on a Vault creation + * @param admin The address of the Vault admin + * @param vault The address of the created Vault + * @param ownMevEscrow The address of the own MEV escrow contract. Zero address if shared MEV escrow is used. + * @param params The encoded parameters for initializing the Vault contract + */ + event VaultCreated(address indexed admin, address indexed vault, address ownMevEscrow, bytes params); - /** - * @notice The address of the Vault implementation contract used for proxy creation - * @return The address of the Vault implementation contract - */ - function implementation() external view returns (address); + /** + * @notice The address of the Vault implementation contract used for proxy creation + * @return The address of the Vault implementation contract + */ + function implementation() external view returns (address); - /** - * @notice The address of the own MEV escrow contract used for Vault creation - * @return The address of the MEV escrow contract - */ - function ownMevEscrow() external view returns (address); + /** + * @notice The address of the own MEV escrow contract used for Vault creation + * @return The address of the MEV escrow contract + */ + function ownMevEscrow() external view returns (address); - /** - * @notice The address of the Vault admin used for Vault creation - * @return The address of the Vault admin - */ - function vaultAdmin() external view returns (address); + /** + * @notice The address of the Vault admin used for Vault creation + * @return The address of the Vault admin + */ + function vaultAdmin() external view returns (address); - /** - * @notice Create Vault. Must transfer security deposit together with a call. - * @param params The encoded parameters for initializing the Vault contract - * @param isOwnMevEscrow Whether to deploy own escrow contract or connect to a smoothing pool for priority fees and MEV rewards - * @return vault The address of the created Vault - */ - function createVault(bytes calldata params, bool isOwnMevEscrow) external returns (address vault); + /** + * @notice Create Vault. Must transfer security deposit together with a call. + * @param params The encoded parameters for initializing the Vault contract + * @param isOwnMevEscrow Whether to deploy own escrow contract or connect to a smoothing pool for priority fees and MEV rewards + * @return vault The address of the created Vault + */ + function createVault(bytes calldata params, bool isOwnMevEscrow) external returns (address vault); } diff --git a/contracts/interfaces/IKeeper.sol b/contracts/interfaces/IKeeper.sol index 125f4e44..89dd09cd 100644 --- a/contracts/interfaces/IKeeper.sol +++ b/contracts/interfaces/IKeeper.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {IKeeperOracles} from './IKeeperOracles.sol'; -import {IKeeperValidators} from './IKeeperValidators.sol'; -import {IKeeperRewards} from './IKeeperRewards.sol'; +import {IKeeperOracles} from "./IKeeperOracles.sol"; +import {IKeeperValidators} from "./IKeeperValidators.sol"; +import {IKeeperRewards} from "./IKeeperRewards.sol"; /** * @title IKeeper @@ -12,9 +12,9 @@ import {IKeeperRewards} from './IKeeperRewards.sol'; * @notice Defines the interface for the Keeper contract */ interface IKeeper is IKeeperOracles, IKeeperRewards, IKeeperValidators { - /** - * @notice Initializes the Keeper contract. Can only be called once. - * @param _owner The address of the owner - */ - function initialize(address _owner) external; + /** + * @notice Initializes the Keeper contract. Can only be called once. + * @param _owner The address of the owner + */ + function initialize(address _owner) external; } diff --git a/contracts/interfaces/IKeeperOracles.sol b/contracts/interfaces/IKeeperOracles.sol index 51915c00..4a865282 100644 --- a/contracts/interfaces/IKeeperOracles.sol +++ b/contracts/interfaces/IKeeperOracles.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; +import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol"; /** * @title IKeeperOracles @@ -10,52 +10,52 @@ import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; * @notice Defines the interface for the KeeperOracles contract */ interface IKeeperOracles is IERC5267 { - /** - * @notice Event emitted on the oracle addition - * @param oracle The address of the added oracle - */ - event OracleAdded(address indexed oracle); - - /** - * @notice Event emitted on the oracle removal - * @param oracle The address of the removed oracle - */ - event OracleRemoved(address indexed oracle); - - /** - * @notice Event emitted on oracles config update - * @param configIpfsHash The IPFS hash of the new config - */ - event ConfigUpdated(string configIpfsHash); - - /** - * @notice Function for verifying whether oracle is registered or not - * @param oracle The address of the oracle to check - * @return `true` for the registered oracle, `false` otherwise - */ - function isOracle(address oracle) external view returns (bool); - - /** - * @notice Total Oracles - * @return The total number of oracles registered - */ - function totalOracles() external view returns (uint256); - - /** - * @notice Function for adding oracle to the set - * @param oracle The address of the oracle to add - */ - function addOracle(address oracle) external; - - /** - * @notice Function for removing oracle from the set - * @param oracle The address of the oracle to remove - */ - function removeOracle(address oracle) external; - - /** - * @notice Function for updating the config IPFS hash - * @param configIpfsHash The new config IPFS hash - */ - function updateConfig(string calldata configIpfsHash) external; + /** + * @notice Event emitted on the oracle addition + * @param oracle The address of the added oracle + */ + event OracleAdded(address indexed oracle); + + /** + * @notice Event emitted on the oracle removal + * @param oracle The address of the removed oracle + */ + event OracleRemoved(address indexed oracle); + + /** + * @notice Event emitted on oracles config update + * @param configIpfsHash The IPFS hash of the new config + */ + event ConfigUpdated(string configIpfsHash); + + /** + * @notice Function for verifying whether oracle is registered or not + * @param oracle The address of the oracle to check + * @return `true` for the registered oracle, `false` otherwise + */ + function isOracle(address oracle) external view returns (bool); + + /** + * @notice Total Oracles + * @return The total number of oracles registered + */ + function totalOracles() external view returns (uint256); + + /** + * @notice Function for adding oracle to the set + * @param oracle The address of the oracle to add + */ + function addOracle(address oracle) external; + + /** + * @notice Function for removing oracle from the set + * @param oracle The address of the oracle to remove + */ + function removeOracle(address oracle) external; + + /** + * @notice Function for updating the config IPFS hash + * @param configIpfsHash The new config IPFS hash + */ + function updateConfig(string calldata configIpfsHash) external; } diff --git a/contracts/interfaces/IKeeperRewards.sol b/contracts/interfaces/IKeeperRewards.sol index 57cc3b58..489434fe 100644 --- a/contracts/interfaces/IKeeperRewards.sol +++ b/contracts/interfaces/IKeeperRewards.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IKeeperOracles} from './IKeeperOracles.sol'; +import {IKeeperOracles} from "./IKeeperOracles.sol"; /** * @title IKeeperRewards @@ -10,193 +10,190 @@ import {IKeeperOracles} from './IKeeperOracles.sol'; * @notice Defines the interface for the Keeper contract rewards */ interface IKeeperRewards is IKeeperOracles { - /** - * @notice Event emitted on rewards update - * @param caller The address of the function caller - * @param rewardsRoot The new rewards merkle tree root - * @param avgRewardPerSecond The new average reward per second - * @param updateTimestamp The update timestamp used for rewards calculation - * @param nonce The nonce used for verifying signatures - * @param rewardsIpfsHash The new rewards IPFS hash - */ - event RewardsUpdated( - address indexed caller, - bytes32 indexed rewardsRoot, - uint256 avgRewardPerSecond, - uint64 updateTimestamp, - uint64 nonce, - string rewardsIpfsHash - ); - - /** - * @notice Event emitted on Vault harvest - * @param vault The address of the Vault - * @param rewardsRoot The rewards merkle tree root - * @param totalAssetsDelta The Vault total assets delta since last sync. Can be negative in case of penalty/slashing. - * @param unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. - */ - event Harvested( - address indexed vault, - bytes32 indexed rewardsRoot, - int256 totalAssetsDelta, - uint256 unlockedMevDelta - ); - - /** - * @notice Event emitted on rewards min oracles number update - * @param oracles The new minimum number of oracles required to update rewards - */ - event RewardsMinOraclesUpdated(uint256 oracles); - - /** - * @notice A struct containing the last synced Vault's cumulative reward - * @param assets The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing. - * @param nonce The nonce of the last sync - */ - struct Reward { - int192 assets; - uint64 nonce; - } - - /** - * @notice A struct containing the last unlocked Vault's cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. - * @param assets The shared MEV Vault's cumulative execution reward that can be withdrawn - * @param nonce The nonce of the last sync - */ - struct UnlockedMevReward { - uint192 assets; - uint64 nonce; - } - - /** - * @notice A struct containing parameters for rewards update - * @param rewardsRoot The new rewards merkle root - * @param avgRewardPerSecond The new average reward per second - * @param updateTimestamp The update timestamp used for rewards calculation - * @param rewardsIpfsHash The new IPFS hash with all the Vaults' rewards for the new root - * @param signatures The concatenation of the Oracles' signatures - */ - struct RewardsUpdateParams { - bytes32 rewardsRoot; - uint256 avgRewardPerSecond; - uint64 updateTimestamp; - string rewardsIpfsHash; - bytes signatures; - } - - /** - * @notice A struct containing parameters for harvesting rewards. Can only be called by Vault. - * @param rewardsRoot The rewards merkle root - * @param reward The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing. - * @param unlockedMevReward The Vault cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. - * @param proof The proof to verify that Vault's reward is correct - */ - struct HarvestParams { - bytes32 rewardsRoot; - int160 reward; - uint160 unlockedMevReward; - bytes32[] proof; - } - - /** - * @notice Previous Rewards Root - * @return The previous merkle tree root of the rewards accumulated by the Vaults - */ - function prevRewardsRoot() external view returns (bytes32); - - /** - * @notice Rewards Root - * @return The latest merkle tree root of the rewards accumulated by the Vaults - */ - function rewardsRoot() external view returns (bytes32); - - /** - * @notice Rewards Nonce - * @return The nonce used for updating rewards merkle tree root - */ - function rewardsNonce() external view returns (uint64); - - /** - * @notice The last rewards update - * @return The timestamp of the last rewards update - */ - function lastRewardsTimestamp() external view returns (uint64); - - /** - * @notice The minimum number of oracles required to update rewards - * @return The minimum number of oracles - */ - function rewardsMinOracles() external view returns (uint256); - - /** - * @notice The rewards delay - * @return The delay in seconds between rewards updates - */ - function rewardsDelay() external view returns (uint256); - - /** - * @notice Get last synced Vault cumulative reward - * @param vault The address of the Vault - * @return assets The last synced reward assets - * @return nonce The last synced reward nonce - */ - function rewards(address vault) external view returns (int192 assets, uint64 nonce); - - /** - * @notice Get last unlocked shared MEV Vault cumulative reward - * @param vault The address of the Vault - * @return assets The last synced reward assets - * @return nonce The last synced reward nonce - */ - function unlockedMevRewards(address vault) external view returns (uint192 assets, uint64 nonce); - - /** - * @notice Checks whether Vault must be harvested - * @param vault The address of the Vault - * @return `true` if the Vault requires harvesting, `false` otherwise - */ - function isHarvestRequired(address vault) external view returns (bool); - - /** - * @notice Checks whether the Vault can be harvested - * @param vault The address of the Vault - * @return `true` if Vault can be harvested, `false` otherwise - */ - function canHarvest(address vault) external view returns (bool); - - /** - * @notice Checks whether rewards can be updated - * @return `true` if rewards can be updated, `false` otherwise - */ - function canUpdateRewards() external view returns (bool); - - /** - * @notice Checks whether the Vault has registered validators - * @param vault The address of the Vault - * @return `true` if Vault is collateralized, `false` otherwise - */ - function isCollateralized(address vault) external view returns (bool); - - /** - * @notice Update rewards data - * @param params The struct containing rewards update parameters - */ - function updateRewards(RewardsUpdateParams calldata params) external; - - /** - * @notice Harvest rewards. Can be called only by Vault. - * @param params The struct containing rewards harvesting parameters - * @return totalAssetsDelta The total reward/penalty accumulated by the Vault since the last sync - * @return unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. - * @return harvested `true` when the rewards were harvested, `false` otherwise - */ - function harvest( - HarvestParams calldata params - ) external returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested); - - /** - * @notice Set min number of oracles for confirming rewards update. Can only be called by the owner. - * @param _rewardsMinOracles The new min number of oracles for confirming rewards update - */ - function setRewardsMinOracles(uint256 _rewardsMinOracles) external; + /** + * @notice Event emitted on rewards update + * @param caller The address of the function caller + * @param rewardsRoot The new rewards merkle tree root + * @param avgRewardPerSecond The new average reward per second + * @param updateTimestamp The update timestamp used for rewards calculation + * @param nonce The nonce used for verifying signatures + * @param rewardsIpfsHash The new rewards IPFS hash + */ + event RewardsUpdated( + address indexed caller, + bytes32 indexed rewardsRoot, + uint256 avgRewardPerSecond, + uint64 updateTimestamp, + uint64 nonce, + string rewardsIpfsHash + ); + + /** + * @notice Event emitted on Vault harvest + * @param vault The address of the Vault + * @param rewardsRoot The rewards merkle tree root + * @param totalAssetsDelta The Vault total assets delta since last sync. Can be negative in case of penalty/slashing. + * @param unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. + */ + event Harvested( + address indexed vault, bytes32 indexed rewardsRoot, int256 totalAssetsDelta, uint256 unlockedMevDelta + ); + + /** + * @notice Event emitted on rewards min oracles number update + * @param oracles The new minimum number of oracles required to update rewards + */ + event RewardsMinOraclesUpdated(uint256 oracles); + + /** + * @notice A struct containing the last synced Vault's cumulative reward + * @param assets The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing. + * @param nonce The nonce of the last sync + */ + struct Reward { + int192 assets; + uint64 nonce; + } + + /** + * @notice A struct containing the last unlocked Vault's cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. + * @param assets The shared MEV Vault's cumulative execution reward that can be withdrawn + * @param nonce The nonce of the last sync + */ + struct UnlockedMevReward { + uint192 assets; + uint64 nonce; + } + + /** + * @notice A struct containing parameters for rewards update + * @param rewardsRoot The new rewards merkle root + * @param avgRewardPerSecond The new average reward per second + * @param updateTimestamp The update timestamp used for rewards calculation + * @param rewardsIpfsHash The new IPFS hash with all the Vaults' rewards for the new root + * @param signatures The concatenation of the Oracles' signatures + */ + struct RewardsUpdateParams { + bytes32 rewardsRoot; + uint256 avgRewardPerSecond; + uint64 updateTimestamp; + string rewardsIpfsHash; + bytes signatures; + } + + /** + * @notice A struct containing parameters for harvesting rewards. Can only be called by Vault. + * @param rewardsRoot The rewards merkle root + * @param reward The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing. + * @param unlockedMevReward The Vault cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. + * @param proof The proof to verify that Vault's reward is correct + */ + struct HarvestParams { + bytes32 rewardsRoot; + int160 reward; + uint160 unlockedMevReward; + bytes32[] proof; + } + + /** + * @notice Previous Rewards Root + * @return The previous merkle tree root of the rewards accumulated by the Vaults + */ + function prevRewardsRoot() external view returns (bytes32); + + /** + * @notice Rewards Root + * @return The latest merkle tree root of the rewards accumulated by the Vaults + */ + function rewardsRoot() external view returns (bytes32); + + /** + * @notice Rewards Nonce + * @return The nonce used for updating rewards merkle tree root + */ + function rewardsNonce() external view returns (uint64); + + /** + * @notice The last rewards update + * @return The timestamp of the last rewards update + */ + function lastRewardsTimestamp() external view returns (uint64); + + /** + * @notice The minimum number of oracles required to update rewards + * @return The minimum number of oracles + */ + function rewardsMinOracles() external view returns (uint256); + + /** + * @notice The rewards delay + * @return The delay in seconds between rewards updates + */ + function rewardsDelay() external view returns (uint256); + + /** + * @notice Get last synced Vault cumulative reward + * @param vault The address of the Vault + * @return assets The last synced reward assets + * @return nonce The last synced reward nonce + */ + function rewards(address vault) external view returns (int192 assets, uint64 nonce); + + /** + * @notice Get last unlocked shared MEV Vault cumulative reward + * @param vault The address of the Vault + * @return assets The last synced reward assets + * @return nonce The last synced reward nonce + */ + function unlockedMevRewards(address vault) external view returns (uint192 assets, uint64 nonce); + + /** + * @notice Checks whether Vault must be harvested + * @param vault The address of the Vault + * @return `true` if the Vault requires harvesting, `false` otherwise + */ + function isHarvestRequired(address vault) external view returns (bool); + + /** + * @notice Checks whether the Vault can be harvested + * @param vault The address of the Vault + * @return `true` if Vault can be harvested, `false` otherwise + */ + function canHarvest(address vault) external view returns (bool); + + /** + * @notice Checks whether rewards can be updated + * @return `true` if rewards can be updated, `false` otherwise + */ + function canUpdateRewards() external view returns (bool); + + /** + * @notice Checks whether the Vault has registered validators + * @param vault The address of the Vault + * @return `true` if Vault is collateralized, `false` otherwise + */ + function isCollateralized(address vault) external view returns (bool); + + /** + * @notice Update rewards data + * @param params The struct containing rewards update parameters + */ + function updateRewards(RewardsUpdateParams calldata params) external; + + /** + * @notice Harvest rewards. Can be called only by Vault. + * @param params The struct containing rewards harvesting parameters + * @return totalAssetsDelta The total reward/penalty accumulated by the Vault since the last sync + * @return unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults. + * @return harvested `true` when the rewards were harvested, `false` otherwise + */ + function harvest(HarvestParams calldata params) + external + returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested); + + /** + * @notice Set min number of oracles for confirming rewards update. Can only be called by the owner. + * @param _rewardsMinOracles The new min number of oracles for confirming rewards update + */ + function setRewardsMinOracles(uint256 _rewardsMinOracles) external; } diff --git a/contracts/interfaces/IKeeperValidators.sol b/contracts/interfaces/IKeeperValidators.sol index ee93fcf3..862eb28b 100644 --- a/contracts/interfaces/IKeeperValidators.sol +++ b/contracts/interfaces/IKeeperValidators.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IKeeperRewards} from './IKeeperRewards.sol'; -import {IKeeperOracles} from './IKeeperOracles.sol'; +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IKeeperOracles} from "./IKeeperOracles.sol"; /** * @title IKeeperValidators @@ -11,85 +11,82 @@ import {IKeeperOracles} from './IKeeperOracles.sol'; * @notice Defines the interface for the Keeper validators */ interface IKeeperValidators is IKeeperOracles, IKeeperRewards { - /** - * @notice Event emitted on validators approval - * @param vault The address of the Vault - * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures - */ - event ValidatorsApproval(address indexed vault, string exitSignaturesIpfsHash); + /** + * @notice Event emitted on validators approval + * @param vault The address of the Vault + * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures + */ + event ValidatorsApproval(address indexed vault, string exitSignaturesIpfsHash); - /** - * @notice Event emitted on exit signatures update - * @param caller The address of the function caller - * @param vault The address of the Vault - * @param nonce The nonce used for verifying Oracles' signatures - * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures - */ - event ExitSignaturesUpdated( - address indexed caller, - address indexed vault, - uint256 nonce, - string exitSignaturesIpfsHash - ); + /** + * @notice Event emitted on exit signatures update + * @param caller The address of the function caller + * @param vault The address of the Vault + * @param nonce The nonce used for verifying Oracles' signatures + * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures + */ + event ExitSignaturesUpdated( + address indexed caller, address indexed vault, uint256 nonce, string exitSignaturesIpfsHash + ); - /** - * @notice Event emitted on validators min oracles number update - * @param oracles The new minimum number of oracles required to approve validators - */ - event ValidatorsMinOraclesUpdated(uint256 oracles); + /** + * @notice Event emitted on validators min oracles number update + * @param oracles The new minimum number of oracles required to approve validators + */ + event ValidatorsMinOraclesUpdated(uint256 oracles); - /** - * @notice Get nonce for the next vault exit signatures update - * @param vault The address of the Vault to get the nonce for - * @return The nonce of the Vault for updating signatures - */ - function exitSignaturesNonces(address vault) external view returns (uint256); + /** + * @notice Get nonce for the next vault exit signatures update + * @param vault The address of the Vault to get the nonce for + * @return The nonce of the Vault for updating signatures + */ + function exitSignaturesNonces(address vault) external view returns (uint256); - /** - * @notice Struct for approving registration of one or more validators - * @param validatorsRegistryRoot The deposit data root used to verify that oracles approved validators - * @param deadline The deadline for submitting the approval - * @param validators The concatenation of the validators' public key, signature and deposit data root - * @param signatures The concatenation of Oracles' signatures - * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures - */ - struct ApprovalParams { - bytes32 validatorsRegistryRoot; - uint256 deadline; - bytes validators; - bytes signatures; - string exitSignaturesIpfsHash; - } + /** + * @notice Struct for approving registration of one or more validators + * @param validatorsRegistryRoot The deposit data root used to verify that oracles approved validators + * @param deadline The deadline for submitting the approval + * @param validators The concatenation of the validators' public key, signature and deposit data root + * @param signatures The concatenation of Oracles' signatures + * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures + */ + struct ApprovalParams { + bytes32 validatorsRegistryRoot; + uint256 deadline; + bytes validators; + bytes signatures; + string exitSignaturesIpfsHash; + } - /** - * @notice The minimum number of oracles required to update validators - * @return The minimum number of oracles - */ - function validatorsMinOracles() external view returns (uint256); + /** + * @notice The minimum number of oracles required to update validators + * @return The minimum number of oracles + */ + function validatorsMinOracles() external view returns (uint256); - /** - * @notice Function for approving validators registration - * @param params The parameters for approving validators registration - */ - function approveValidators(ApprovalParams calldata params) external; + /** + * @notice Function for approving validators registration + * @param params The parameters for approving validators registration + */ + function approveValidators(ApprovalParams calldata params) external; - /** - * @notice Function for updating exit signatures for every hard fork - * @param vault The address of the Vault to update signatures for - * @param deadline The deadline for submitting signatures update - * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures - * @param oraclesSignatures The concatenation of Oracles' signatures - */ - function updateExitSignatures( - address vault, - uint256 deadline, - string calldata exitSignaturesIpfsHash, - bytes calldata oraclesSignatures - ) external; + /** + * @notice Function for updating exit signatures for every hard fork + * @param vault The address of the Vault to update signatures for + * @param deadline The deadline for submitting signatures update + * @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures + * @param oraclesSignatures The concatenation of Oracles' signatures + */ + function updateExitSignatures( + address vault, + uint256 deadline, + string calldata exitSignaturesIpfsHash, + bytes calldata oraclesSignatures + ) external; - /** - * @notice Function for updating validators min oracles number - * @param _validatorsMinOracles The new minimum number of oracles required to approve validators - */ - function setValidatorsMinOracles(uint256 _validatorsMinOracles) external; + /** + * @notice Function for updating validators min oracles number + * @param _validatorsMinOracles The new minimum number of oracles required to approve validators + */ + function setValidatorsMinOracles(uint256 _validatorsMinOracles) external; } diff --git a/contracts/interfaces/IMerkleDistributor.sol b/contracts/interfaces/IMerkleDistributor.sol index 76e5636b..77000b90 100644 --- a/contracts/interfaces/IMerkleDistributor.sol +++ b/contracts/interfaces/IMerkleDistributor.sol @@ -8,29 +8,25 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the MerkleDistributor contract */ interface IMerkleDistributor { - /** - * @notice Distribute tokens one time - * @param token The address of the token - * @param amount The amount of tokens to distribute - * @param rewardsIpfsHash The IPFS hash of the rewards - * @param extraData The extra data for the distribution - */ - function distributeOneTime( - address token, - uint256 amount, - string calldata rewardsIpfsHash, - bytes calldata extraData - ) external; + /** + * @notice Distribute tokens one time + * @param token The address of the token + * @param amount The amount of tokens to distribute + * @param rewardsIpfsHash The IPFS hash of the rewards + * @param extraData The extra data for the distribution + */ + function distributeOneTime(address token, uint256 amount, string calldata rewardsIpfsHash, bytes calldata extraData) + external; - /** - * @notice Add or remove a distributor. Can only be called by the owner. - * @param distributor The address of the distributor - * @param isEnabled The status of the distributor, true for adding distributor, false for removing distributor - */ - function setDistributor(address distributor, bool isEnabled) external; + /** + * @notice Add or remove a distributor. Can only be called by the owner. + * @param distributor The address of the distributor + * @param isEnabled The status of the distributor, true for adding distributor, false for removing distributor + */ + function setDistributor(address distributor, bool isEnabled) external; - /** - * @dev Returns the address of the current owner. - */ - function owner() external view returns (address); + /** + * @dev Returns the address of the current owner. + */ + function owner() external view returns (address); } diff --git a/contracts/interfaces/IMulticall.sol b/contracts/interfaces/IMulticall.sol index 0c2f755e..3701c7b1 100644 --- a/contracts/interfaces/IMulticall.sol +++ b/contracts/interfaces/IMulticall.sol @@ -9,10 +9,10 @@ pragma solidity ^0.8.22; * @notice Enables calling multiple methods in a single call to the contract */ interface IMulticall { - /** - * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed - * @param data The encoded function data for each of the calls to make to this contract - * @return results The results from each of the calls passed in via data - */ - function multicall(bytes[] calldata data) external returns (bytes[] memory results); + /** + * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + * @param data The encoded function data for each of the calls to make to this contract + * @return results The results from each of the calls passed in via data + */ + function multicall(bytes[] calldata data) external returns (bytes[] memory results); } diff --git a/contracts/interfaces/IOsToken.sol b/contracts/interfaces/IOsToken.sol index 10a3ccf7..d389ad63 100644 --- a/contracts/interfaces/IOsToken.sol +++ b/contracts/interfaces/IOsToken.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol'; -import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; -import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol"; /** * @title IOsToken @@ -13,38 +13,38 @@ import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol'; * @notice Defines the interface for the OsToken contract */ interface IOsToken is IERC20, IERC20Metadata, IERC20Permit, IERC5267 { - /** - * @notice Emitted when a controller is updated - * @param controller The address of the controller - * @param registered Whether the controller is registered or not - */ - event ControllerUpdated(address indexed controller, bool registered); + /** + * @notice Emitted when a controller is updated + * @param controller The address of the controller + * @param registered Whether the controller is registered or not + */ + event ControllerUpdated(address indexed controller, bool registered); - /** - * @notice Returns whether controller is registered or not - * @param controller The address of the controller - * @return Whether the controller is registered or not - */ - function controllers(address controller) external view returns (bool); + /** + * @notice Returns whether controller is registered or not + * @param controller The address of the controller + * @return Whether the controller is registered or not + */ + function controllers(address controller) external view returns (bool); - /** - * @notice Mint OsToken. Can only be called by the controller. - * @param account The address of the account to mint OsToken for - * @param value The amount of OsToken to mint - */ - function mint(address account, uint256 value) external; + /** + * @notice Mint OsToken. Can only be called by the controller. + * @param account The address of the account to mint OsToken for + * @param value The amount of OsToken to mint + */ + function mint(address account, uint256 value) external; - /** - * @notice Burn OsToken. Can only be called by the controller. - * @param account The address of the account to burn OsToken for - * @param value The amount of OsToken to burn - */ - function burn(address account, uint256 value) external; + /** + * @notice Burn OsToken. Can only be called by the controller. + * @param account The address of the account to burn OsToken for + * @param value The amount of OsToken to burn + */ + function burn(address account, uint256 value) external; - /** - * @notice Enable or disable the controller. Can only be called by the contract owner. - * @param controller The address of the controller - * @param registered Whether the controller is registered or not - */ - function setController(address controller, bool registered) external; + /** + * @notice Enable or disable the controller. Can only be called by the contract owner. + * @param controller The address of the controller + * @param registered Whether the controller is registered or not + */ + function setController(address controller, bool registered) external; } diff --git a/contracts/interfaces/IOsTokenConfig.sol b/contracts/interfaces/IOsTokenConfig.sol index 46741578..b8426bec 100644 --- a/contracts/interfaces/IOsTokenConfig.sol +++ b/contracts/interfaces/IOsTokenConfig.sol @@ -8,61 +8,56 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the OsTokenConfig contract */ interface IOsTokenConfig { - /** - * @notice Emitted when OsToken minting and liquidating configuration values are updated - * @param vault The address of the vault to update the config for. Will be zero address if it is a default config. - * @param liqBonusPercent The new liquidation bonus percent value - * @param liqThresholdPercent The new liquidation threshold percent value - * @param ltvPercent The new loan-to-value (LTV) percent value - */ - event OsTokenConfigUpdated( - address vault, - uint128 liqBonusPercent, - uint64 liqThresholdPercent, - uint64 ltvPercent - ); - - /** - * @notice Emitted when the OsToken redeemer address is updated - * @param newRedeemer The address of the new redeemer - */ - event RedeemerUpdated(address newRedeemer); - - /** - * @notice The OsToken minting and liquidating configuration values - * @param liqThresholdPercent The liquidation threshold percent used to calculate health factor for OsToken position - * @param liqBonusPercent The minimal bonus percent that liquidator earns on OsToken position liquidation - * @param ltvPercent The percent used to calculate how much user can mint OsToken shares - */ - struct Config { - uint128 liqBonusPercent; - uint64 liqThresholdPercent; - uint64 ltvPercent; - } - - /** - * @notice The address of the OsToken redeemer - * @return The address of the redeemer - */ - function redeemer() external view returns (address); - - /** - * @notice Returns the OsToken minting and liquidating configuration values for the vault - * @param vault The address of the vault to get the config for - * @return config The OsToken config for the vault - */ - function getConfig(address vault) external view returns (Config memory config); - - /** - * @notice Sets the OsToken redeemer address. Can only be called by the owner. - * @param newRedeemer The address of the new redeemer - */ - function setRedeemer(address newRedeemer) external; - - /** - * @notice Updates the OsToken minting and liquidating configuration values. Can only be called by the owner. - * @param vault The address of the vault. Set to zero address to update the default config. - * @param config The new OsToken configuration - */ - function updateConfig(address vault, Config memory config) external; + /** + * @notice Emitted when OsToken minting and liquidating configuration values are updated + * @param vault The address of the vault to update the config for. Will be zero address if it is a default config. + * @param liqBonusPercent The new liquidation bonus percent value + * @param liqThresholdPercent The new liquidation threshold percent value + * @param ltvPercent The new loan-to-value (LTV) percent value + */ + event OsTokenConfigUpdated(address vault, uint128 liqBonusPercent, uint64 liqThresholdPercent, uint64 ltvPercent); + + /** + * @notice Emitted when the OsToken redeemer address is updated + * @param newRedeemer The address of the new redeemer + */ + event RedeemerUpdated(address newRedeemer); + + /** + * @notice The OsToken minting and liquidating configuration values + * @param liqThresholdPercent The liquidation threshold percent used to calculate health factor for OsToken position + * @param liqBonusPercent The minimal bonus percent that liquidator earns on OsToken position liquidation + * @param ltvPercent The percent used to calculate how much user can mint OsToken shares + */ + struct Config { + uint128 liqBonusPercent; + uint64 liqThresholdPercent; + uint64 ltvPercent; + } + + /** + * @notice The address of the OsToken redeemer + * @return The address of the redeemer + */ + function redeemer() external view returns (address); + + /** + * @notice Returns the OsToken minting and liquidating configuration values for the vault + * @param vault The address of the vault to get the config for + * @return config The OsToken config for the vault + */ + function getConfig(address vault) external view returns (Config memory config); + + /** + * @notice Sets the OsToken redeemer address. Can only be called by the owner. + * @param newRedeemer The address of the new redeemer + */ + function setRedeemer(address newRedeemer) external; + + /** + * @notice Updates the OsToken minting and liquidating configuration values. Can only be called by the owner. + * @param vault The address of the vault. Set to zero address to update the default config. + * @param config The new OsToken configuration + */ + function updateConfig(address vault, Config memory config) external; } diff --git a/contracts/interfaces/IOsTokenFlashLoanRecipient.sol b/contracts/interfaces/IOsTokenFlashLoanRecipient.sol index 120e80e0..9ef6d650 100644 --- a/contracts/interfaces/IOsTokenFlashLoanRecipient.sol +++ b/contracts/interfaces/IOsTokenFlashLoanRecipient.sol @@ -8,10 +8,10 @@ pragma solidity ^0.8.22; * @notice Interface for OsTokenFlashLoanRecipient contract */ interface IOsTokenFlashLoanRecipient { - /** - * @notice Receive flash loan hook - * @param osTokenShares The osToken flash loan amount - * @param userData Arbitrary data passed to the hook - */ - function receiveFlashLoan(uint256 osTokenShares, bytes memory userData) external; + /** + * @notice Receive flash loan hook + * @param osTokenShares The osToken flash loan amount + * @param userData Arbitrary data passed to the hook + */ + function receiveFlashLoan(uint256 osTokenShares, bytes memory userData) external; } diff --git a/contracts/interfaces/IOsTokenFlashLoans.sol b/contracts/interfaces/IOsTokenFlashLoans.sol index a7e7d53d..eb33d6f0 100644 --- a/contracts/interfaces/IOsTokenFlashLoans.sol +++ b/contracts/interfaces/IOsTokenFlashLoans.sol @@ -8,17 +8,17 @@ pragma solidity ^0.8.22; * @notice Interface for OsTokenFlashLoans contract */ interface IOsTokenFlashLoans { - /** - * @notice Event emitted on flash loan - * @param caller The address of the caller - * @param amount The flashLoan osToken shares amount - */ - event OsTokenFlashLoan(address indexed caller, uint256 amount); + /** + * @notice Event emitted on flash loan + * @param caller The address of the caller + * @param amount The flashLoan osToken shares amount + */ + event OsTokenFlashLoan(address indexed caller, uint256 amount); - /** - * @notice Flash loan OsToken shares - * @param osTokenShares The flashLoan osToken shares amount - * @param userData Arbitrary data passed to the `IOsTokenFlashLoanRecipient.receiveFlashLoan` function - */ - function flashLoan(uint256 osTokenShares, bytes memory userData) external; + /** + * @notice Flash loan OsToken shares + * @param osTokenShares The flashLoan osToken shares amount + * @param userData Arbitrary data passed to the `IOsTokenFlashLoanRecipient.receiveFlashLoan` function + */ + function flashLoan(uint256 osTokenShares, bytes memory userData) external; } diff --git a/contracts/interfaces/IOsTokenVaultController.sol b/contracts/interfaces/IOsTokenVaultController.sol index 5f63d28e..be80021a 100644 --- a/contracts/interfaces/IOsTokenVaultController.sol +++ b/contracts/interfaces/IOsTokenVaultController.sol @@ -8,172 +8,172 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the OsTokenVaultController contract */ interface IOsTokenVaultController { - /** - * @notice Event emitted on minting shares - * @param vault The address of the Vault - * @param receiver The address that received the shares - * @param assets The number of assets collateralized - * @param shares The number of tokens the owner received - */ - event Mint(address indexed vault, address indexed receiver, uint256 assets, uint256 shares); - - /** - * @notice Event emitted on burning shares - * @param vault The address of the Vault - * @param owner The address that owns the shares - * @param assets The total number of assets withdrawn - * @param shares The total number of shares burned - */ - event Burn(address indexed vault, address indexed owner, uint256 assets, uint256 shares); - - /** - * @notice Event emitted on state update - * @param profitAccrued The profit accrued since the last update - * @param treasuryShares The number of shares minted for the treasury - * @param treasuryAssets The number of assets minted for the treasury - */ - event StateUpdated(uint256 profitAccrued, uint256 treasuryShares, uint256 treasuryAssets); - - /** - * @notice Event emitted on capacity update - * @param capacity The amount after which the OsToken stops accepting deposits - */ - event CapacityUpdated(uint256 capacity); - - /** - * @notice Event emitted on treasury address update - * @param treasury The new treasury address - */ - event TreasuryUpdated(address indexed treasury); - - /** - * @notice Event emitted on fee percent update - * @param feePercent The new fee percent - */ - event FeePercentUpdated(uint16 feePercent); - - /** - * @notice Event emitted on average reward per second update - * @param avgRewardPerSecond The new average reward per second - */ - event AvgRewardPerSecondUpdated(uint256 avgRewardPerSecond); - - /** - * @notice Event emitted on keeper address update - * @param keeper The new keeper address - */ - event KeeperUpdated(address keeper); - - /** - * @notice The OsToken capacity - * @return The amount after which the OsToken stops accepting deposits - */ - function capacity() external view returns (uint256); - - /** - * @notice The DAO treasury address that receives OsToken fees - * @return The address of the treasury - */ - function treasury() external view returns (address); - - /** - * @notice The fee percent (multiplied by 100) - * @return The fee percent applied by the OsToken on the rewards - */ - function feePercent() external view returns (uint64); - - /** - * @notice The address that can update avgRewardPerSecond - * @return The address of the keeper contract - */ - function keeper() external view returns (address); - - /** - * @notice The average reward per second used to mint OsToken rewards - * @return The average reward per second earned by the Vaults - */ - function avgRewardPerSecond() external view returns (uint256); - - /** - * @notice The fee per share used for calculating the fee for every position - * @return The cumulative fee per share - */ - function cumulativeFeePerShare() external view returns (uint256); - - /** - * @notice The total number of shares controlled by the OsToken - * @return The total number of shares - */ - function totalShares() external view returns (uint256); - - /** - * @notice Total assets controlled by the OsToken - * @return The total amount of the underlying asset that is "managed" by OsToken - */ - function totalAssets() external view returns (uint256); - - /** - * @notice Converts assets to shares - * @param assets The amount of assets to convert to shares - * @return shares The amount of OsToken shares obtained when exchanging with the amount of assets provided - */ - function convertToShares(uint256 assets) external view returns (uint256 shares); - - /** - * @notice Converts shares to assets - * @param shares The amount of shares to convert to assets - * @return assets The amount of assets obtained when exchanging with the amount of OsToken shares provided - */ - function convertToAssets(uint256 shares) external view returns (uint256 assets); - - /** - * @notice Updates rewards and treasury fee checkpoint for the OsToken - */ - function updateState() external; - - /** - * @notice Mint OsToken shares. Can only be called by the registered vault. - * @param receiver The address that will receive the shares - * @param shares The amount of shares to mint - * @return assets The amount of assets minted - */ - function mintShares(address receiver, uint256 shares) external returns (uint256 assets); - - /** - * @notice Burn shares for withdrawn assets. Can only be called by the registered vault. - * @param owner The address that owns the shares - * @param shares The amount of shares to burn - * @return assets The amount of assets withdrawn - */ - function burnShares(address owner, uint256 shares) external returns (uint256 assets); - - /** - * @notice Update treasury address. Can only be called by the owner. - * @param _treasury The new treasury address - */ - function setTreasury(address _treasury) external; - - /** - * @notice Update capacity. Can only be called by the owner. - * @param _capacity The amount after which the OsToken stops accepting deposits - */ - function setCapacity(uint256 _capacity) external; - - /** - * @notice Update fee percent. Can only be called by the owner. Cannot be larger than 10 000 (100%). - * @param _feePercent The new fee percent - */ - function setFeePercent(uint16 _feePercent) external; - - /** - * @notice Update keeper address. Can only be called by the owner. - * @param _keeper The new keeper address - */ - function setKeeper(address _keeper) external; - - /** - * @notice Updates average reward per second. Can only be called by the keeper. - * @param _avgRewardPerSecond The new average reward per second - */ - function setAvgRewardPerSecond(uint256 _avgRewardPerSecond) external; + /** + * @notice Event emitted on minting shares + * @param vault The address of the Vault + * @param receiver The address that received the shares + * @param assets The number of assets collateralized + * @param shares The number of tokens the owner received + */ + event Mint(address indexed vault, address indexed receiver, uint256 assets, uint256 shares); + + /** + * @notice Event emitted on burning shares + * @param vault The address of the Vault + * @param owner The address that owns the shares + * @param assets The total number of assets withdrawn + * @param shares The total number of shares burned + */ + event Burn(address indexed vault, address indexed owner, uint256 assets, uint256 shares); + + /** + * @notice Event emitted on state update + * @param profitAccrued The profit accrued since the last update + * @param treasuryShares The number of shares minted for the treasury + * @param treasuryAssets The number of assets minted for the treasury + */ + event StateUpdated(uint256 profitAccrued, uint256 treasuryShares, uint256 treasuryAssets); + + /** + * @notice Event emitted on capacity update + * @param capacity The amount after which the OsToken stops accepting deposits + */ + event CapacityUpdated(uint256 capacity); + + /** + * @notice Event emitted on treasury address update + * @param treasury The new treasury address + */ + event TreasuryUpdated(address indexed treasury); + + /** + * @notice Event emitted on fee percent update + * @param feePercent The new fee percent + */ + event FeePercentUpdated(uint16 feePercent); + + /** + * @notice Event emitted on average reward per second update + * @param avgRewardPerSecond The new average reward per second + */ + event AvgRewardPerSecondUpdated(uint256 avgRewardPerSecond); + + /** + * @notice Event emitted on keeper address update + * @param keeper The new keeper address + */ + event KeeperUpdated(address keeper); + + /** + * @notice The OsToken capacity + * @return The amount after which the OsToken stops accepting deposits + */ + function capacity() external view returns (uint256); + + /** + * @notice The DAO treasury address that receives OsToken fees + * @return The address of the treasury + */ + function treasury() external view returns (address); + + /** + * @notice The fee percent (multiplied by 100) + * @return The fee percent applied by the OsToken on the rewards + */ + function feePercent() external view returns (uint64); + + /** + * @notice The address that can update avgRewardPerSecond + * @return The address of the keeper contract + */ + function keeper() external view returns (address); + + /** + * @notice The average reward per second used to mint OsToken rewards + * @return The average reward per second earned by the Vaults + */ + function avgRewardPerSecond() external view returns (uint256); + + /** + * @notice The fee per share used for calculating the fee for every position + * @return The cumulative fee per share + */ + function cumulativeFeePerShare() external view returns (uint256); + + /** + * @notice The total number of shares controlled by the OsToken + * @return The total number of shares + */ + function totalShares() external view returns (uint256); + + /** + * @notice Total assets controlled by the OsToken + * @return The total amount of the underlying asset that is "managed" by OsToken + */ + function totalAssets() external view returns (uint256); + + /** + * @notice Converts assets to shares + * @param assets The amount of assets to convert to shares + * @return shares The amount of OsToken shares obtained when exchanging with the amount of assets provided + */ + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /** + * @notice Converts shares to assets + * @param shares The amount of shares to convert to assets + * @return assets The amount of assets obtained when exchanging with the amount of OsToken shares provided + */ + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /** + * @notice Updates rewards and treasury fee checkpoint for the OsToken + */ + function updateState() external; + + /** + * @notice Mint OsToken shares. Can only be called by the registered vault. + * @param receiver The address that will receive the shares + * @param shares The amount of shares to mint + * @return assets The amount of assets minted + */ + function mintShares(address receiver, uint256 shares) external returns (uint256 assets); + + /** + * @notice Burn shares for withdrawn assets. Can only be called by the registered vault. + * @param owner The address that owns the shares + * @param shares The amount of shares to burn + * @return assets The amount of assets withdrawn + */ + function burnShares(address owner, uint256 shares) external returns (uint256 assets); + + /** + * @notice Update treasury address. Can only be called by the owner. + * @param _treasury The new treasury address + */ + function setTreasury(address _treasury) external; + + /** + * @notice Update capacity. Can only be called by the owner. + * @param _capacity The amount after which the OsToken stops accepting deposits + */ + function setCapacity(uint256 _capacity) external; + + /** + * @notice Update fee percent. Can only be called by the owner. Cannot be larger than 10 000 (100%). + * @param _feePercent The new fee percent + */ + function setFeePercent(uint16 _feePercent) external; + + /** + * @notice Update keeper address. Can only be called by the owner. + * @param _keeper The new keeper address + */ + function setKeeper(address _keeper) external; + + /** + * @notice Updates average reward per second. Can only be called by the keeper. + * @param _avgRewardPerSecond The new average reward per second + */ + function setAvgRewardPerSecond(uint256 _avgRewardPerSecond) external; } diff --git a/contracts/interfaces/IOsTokenVaultEscrow.sol b/contracts/interfaces/IOsTokenVaultEscrow.sol index f6056a8e..459b9b9d 100644 --- a/contracts/interfaces/IOsTokenVaultEscrow.sol +++ b/contracts/interfaces/IOsTokenVaultEscrow.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IMulticall} from './IMulticall.sol'; +import {IMulticall} from "./IMulticall.sol"; /** * @title IOsTokenVaultEscrow @@ -10,225 +10,201 @@ import {IMulticall} from './IMulticall.sol'; * @notice Interface for OsTokenVaultEscrow contract */ interface IOsTokenVaultEscrow is IMulticall { - /** - * @notice Struct to store the escrow position details - * @param owner The address of the assets owner - * @param exitedAssets The amount of assets exited and ready to be claimed - * @param osTokenShares The amount of osToken shares - * @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee - */ - struct Position { - address owner; - uint96 exitedAssets; - uint128 osTokenShares; - uint128 cumulativeFeePerShare; - } - - /** - * @notice Event emitted on position creation - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param owner The address of the assets owner - * @param osTokenShares The amount of osToken shares - * @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee - */ - event PositionCreated( - address indexed vault, - uint256 indexed exitPositionTicket, - address owner, - uint256 osTokenShares, - uint256 cumulativeFeePerShare - ); - - /** - * @notice Event emitted on assets exit processing - * @param vault The address of the vault - * @param caller The address of the caller - * @param exitPositionTicket The exit position ticket - * @param exitedAssets The amount of exited assets claimed - */ - event ExitedAssetsProcessed( - address indexed vault, - address indexed caller, - uint256 indexed exitPositionTicket, - uint256 exitedAssets - ); - - /** - * @notice Event emitted on osToken liquidation - * @param caller The address of the function caller - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param receiver The address of the receiver of the liquidated assets - * @param osTokenShares The amount of osToken shares to liquidate - * @param receivedAssets The amount of assets received - */ - event OsTokenLiquidated( - address indexed caller, - address indexed vault, - uint256 indexed exitPositionTicket, - address receiver, - uint256 osTokenShares, - uint256 receivedAssets - ); - - /** - * @notice Event emitted on osToken redemption - * @param caller The address of the function caller - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param receiver The address of the receiver of the redeemed assets - * @param osTokenShares The amount of osToken shares to redeem - * @param receivedAssets The amount of assets received - */ - event OsTokenRedeemed( - address indexed caller, - address indexed vault, - uint256 indexed exitPositionTicket, - address receiver, - uint256 osTokenShares, - uint256 receivedAssets - ); - - /** - * @notice Event emitted on exited assets claim - * @param receiver The address of the receiver of the exited assets - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param osTokenShares The amount of osToken shares burned - * @param assets The amount of assets claimed - */ - event ExitedAssetsClaimed( - address indexed receiver, - address indexed vault, - uint256 indexed exitPositionTicket, - uint256 osTokenShares, - uint256 assets - ); - - /** - * @notice Event emitted on liquidation configuration update - * @param liqThresholdPercent The liquidation threshold percent - * @param liqBonusPercent The liquidation bonus percent - */ - event LiqConfigUpdated(uint64 liqThresholdPercent, uint256 liqBonusPercent); - - /** - * @notice Event emitted on authenticator update - * @param newAuthenticator The address of the new authenticator - */ - event AuthenticatorUpdated(address newAuthenticator); - - /** - * @notice The liquidation threshold percent - * @return The liquidation threshold percent starting from which the osToken shares can be liquidated - */ - function liqThresholdPercent() external view returns (uint64); - - /** - * @notice The liquidation bonus percent - * @return The liquidation bonus percent paid for liquidating the osToken shares - */ - function liqBonusPercent() external view returns (uint256); - - /** - * @notice The address of the authenticator - * @return The address of the authenticator contract - */ - function authenticator() external view returns (address); - - /** - * @notice Get the position details - * @param vault The address of the vault - * @param positionTicket The exit position ticket - * @return owner The address of the assets owner - * @return exitedAssets The amount of assets exited and ready to be claimed - * @return osTokenShares The amount of osToken shares - */ - function getPosition( - address vault, - uint256 positionTicket - ) external view returns (address, uint256, uint256); - - /** - * @notice Registers the new escrow position - * @param owner The address of the exited assets owner - * @param exitPositionTicket The exit position ticket - * @param osTokenShares The amount of osToken shares - * @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee - */ - function register( - address owner, - uint256 exitPositionTicket, - uint256 osTokenShares, - uint256 cumulativeFeePerShare - ) external; - - /** - * @notice Claims exited assets from the vault to the escrow - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param timestamp The timestamp of the exit - * @param exitQueueIndex The index of the exit in the queue - */ - function processExitedAssets( - address vault, - uint256 exitPositionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external; - - /** - * @notice Claims the exited assets from the escrow to the owner. Can only be called by the position owner. - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param osTokenShares The amount of osToken shares to burn - * @return claimedAssets The amount of assets claimed - */ - function claimExitedAssets( - address vault, - uint256 exitPositionTicket, - uint256 osTokenShares - ) external returns (uint256 claimedAssets); - - /** - * @notice Liquidates the osToken shares - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param osTokenShares The amount of osToken shares to liquidate - * @param receiver The address of the receiver of the liquidated assets - */ - function liquidateOsToken( - address vault, - uint256 exitPositionTicket, - uint256 osTokenShares, - address receiver - ) external; - - /** - * @notice Redeems the osToken shares. Can only be called by the osToken redeemer. - * @param vault The address of the vault - * @param exitPositionTicket The exit position ticket - * @param osTokenShares The amount of osToken shares to redeem - * @param receiver The address of the receiver of the redeemed assets - */ - function redeemOsToken( - address vault, - uint256 exitPositionTicket, - uint256 osTokenShares, - address receiver - ) external; - - /** - * @notice Updates the authenticator. Can only be called by the owner. - * @param newAuthenticator The address of the new authenticator - */ - function setAuthenticator(address newAuthenticator) external; - - /** - * @notice Updates the liquidation configuration. Can only be called by the owner. - * @param _liqThresholdPercent The liquidation threshold percent - * @param _liqBonusPercent The liquidation bonus percent - */ - function updateLiqConfig(uint64 _liqThresholdPercent, uint256 _liqBonusPercent) external; + /** + * @notice Struct to store the escrow position details + * @param owner The address of the assets owner + * @param exitedAssets The amount of assets exited and ready to be claimed + * @param osTokenShares The amount of osToken shares + * @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee + */ + struct Position { + address owner; + uint96 exitedAssets; + uint128 osTokenShares; + uint128 cumulativeFeePerShare; + } + + /** + * @notice Event emitted on position creation + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param owner The address of the assets owner + * @param osTokenShares The amount of osToken shares + * @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee + */ + event PositionCreated( + address indexed vault, + uint256 indexed exitPositionTicket, + address owner, + uint256 osTokenShares, + uint256 cumulativeFeePerShare + ); + + /** + * @notice Event emitted on assets exit processing + * @param vault The address of the vault + * @param caller The address of the caller + * @param exitPositionTicket The exit position ticket + * @param exitedAssets The amount of exited assets claimed + */ + event ExitedAssetsProcessed( + address indexed vault, address indexed caller, uint256 indexed exitPositionTicket, uint256 exitedAssets + ); + + /** + * @notice Event emitted on osToken liquidation + * @param caller The address of the function caller + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param receiver The address of the receiver of the liquidated assets + * @param osTokenShares The amount of osToken shares to liquidate + * @param receivedAssets The amount of assets received + */ + event OsTokenLiquidated( + address indexed caller, + address indexed vault, + uint256 indexed exitPositionTicket, + address receiver, + uint256 osTokenShares, + uint256 receivedAssets + ); + + /** + * @notice Event emitted on osToken redemption + * @param caller The address of the function caller + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param receiver The address of the receiver of the redeemed assets + * @param osTokenShares The amount of osToken shares to redeem + * @param receivedAssets The amount of assets received + */ + event OsTokenRedeemed( + address indexed caller, + address indexed vault, + uint256 indexed exitPositionTicket, + address receiver, + uint256 osTokenShares, + uint256 receivedAssets + ); + + /** + * @notice Event emitted on exited assets claim + * @param receiver The address of the receiver of the exited assets + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param osTokenShares The amount of osToken shares burned + * @param assets The amount of assets claimed + */ + event ExitedAssetsClaimed( + address indexed receiver, + address indexed vault, + uint256 indexed exitPositionTicket, + uint256 osTokenShares, + uint256 assets + ); + + /** + * @notice Event emitted on liquidation configuration update + * @param liqThresholdPercent The liquidation threshold percent + * @param liqBonusPercent The liquidation bonus percent + */ + event LiqConfigUpdated(uint64 liqThresholdPercent, uint256 liqBonusPercent); + + /** + * @notice Event emitted on authenticator update + * @param newAuthenticator The address of the new authenticator + */ + event AuthenticatorUpdated(address newAuthenticator); + + /** + * @notice The liquidation threshold percent + * @return The liquidation threshold percent starting from which the osToken shares can be liquidated + */ + function liqThresholdPercent() external view returns (uint64); + + /** + * @notice The liquidation bonus percent + * @return The liquidation bonus percent paid for liquidating the osToken shares + */ + function liqBonusPercent() external view returns (uint256); + + /** + * @notice The address of the authenticator + * @return The address of the authenticator contract + */ + function authenticator() external view returns (address); + + /** + * @notice Get the position details + * @param vault The address of the vault + * @param positionTicket The exit position ticket + * @return owner The address of the assets owner + * @return exitedAssets The amount of assets exited and ready to be claimed + * @return osTokenShares The amount of osToken shares + */ + function getPosition(address vault, uint256 positionTicket) external view returns (address, uint256, uint256); + + /** + * @notice Registers the new escrow position + * @param owner The address of the exited assets owner + * @param exitPositionTicket The exit position ticket + * @param osTokenShares The amount of osToken shares + * @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee + */ + function register(address owner, uint256 exitPositionTicket, uint256 osTokenShares, uint256 cumulativeFeePerShare) + external; + + /** + * @notice Claims exited assets from the vault to the escrow + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param timestamp The timestamp of the exit + * @param exitQueueIndex The index of the exit in the queue + */ + function processExitedAssets(address vault, uint256 exitPositionTicket, uint256 timestamp, uint256 exitQueueIndex) + external; + + /** + * @notice Claims the exited assets from the escrow to the owner. Can only be called by the position owner. + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param osTokenShares The amount of osToken shares to burn + * @return claimedAssets The amount of assets claimed + */ + function claimExitedAssets(address vault, uint256 exitPositionTicket, uint256 osTokenShares) + external + returns (uint256 claimedAssets); + + /** + * @notice Liquidates the osToken shares + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param osTokenShares The amount of osToken shares to liquidate + * @param receiver The address of the receiver of the liquidated assets + */ + function liquidateOsToken(address vault, uint256 exitPositionTicket, uint256 osTokenShares, address receiver) + external; + + /** + * @notice Redeems the osToken shares. Can only be called by the osToken redeemer. + * @param vault The address of the vault + * @param exitPositionTicket The exit position ticket + * @param osTokenShares The amount of osToken shares to redeem + * @param receiver The address of the receiver of the redeemed assets + */ + function redeemOsToken(address vault, uint256 exitPositionTicket, uint256 osTokenShares, address receiver) + external; + + /** + * @notice Updates the authenticator. Can only be called by the owner. + * @param newAuthenticator The address of the new authenticator + */ + function setAuthenticator(address newAuthenticator) external; + + /** + * @notice Updates the liquidation configuration. Can only be called by the owner. + * @param _liqThresholdPercent The liquidation threshold percent + * @param _liqBonusPercent The liquidation bonus percent + */ + function updateLiqConfig(uint64 _liqThresholdPercent, uint256 _liqBonusPercent) external; } diff --git a/contracts/interfaces/IOsTokenVaultEscrowAuth.sol b/contracts/interfaces/IOsTokenVaultEscrowAuth.sol index 0fb80a95..5695ac00 100644 --- a/contracts/interfaces/IOsTokenVaultEscrowAuth.sol +++ b/contracts/interfaces/IOsTokenVaultEscrowAuth.sol @@ -8,18 +8,16 @@ pragma solidity ^0.8.22; * @notice Interface for OsTokenVaultEscrowAuth contract */ interface IOsTokenVaultEscrowAuth { - /** - * @notice Check if the caller can register the exit position - * @param vault The address of the vault - * @param owner The address of the assets owner - * @param exitPositionTicket The exit position ticket - * @param osTokenShares The amount of osToken shares to burn - * @return True if the caller can register the exit position - */ - function canRegister( - address vault, - address owner, - uint256 exitPositionTicket, - uint256 osTokenShares - ) external view returns (bool); + /** + * @notice Check if the caller can register the exit position + * @param vault The address of the vault + * @param owner The address of the assets owner + * @param exitPositionTicket The exit position ticket + * @param osTokenShares The amount of osToken shares to burn + * @return True if the caller can register the exit position + */ + function canRegister(address vault, address owner, uint256 exitPositionTicket, uint256 osTokenShares) + external + view + returns (bool); } diff --git a/contracts/interfaces/IOwnMevEscrow.sol b/contracts/interfaces/IOwnMevEscrow.sol index cff76861..f0d3041f 100644 --- a/contracts/interfaces/IOwnMevEscrow.sol +++ b/contracts/interfaces/IOwnMevEscrow.sol @@ -8,30 +8,30 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the OwnMevEscrow contract */ interface IOwnMevEscrow { - /** - * @notice Event emitted on received MEV - * @param assets The amount of MEV assets received - */ - event MevReceived(uint256 assets); + /** + * @notice Event emitted on received MEV + * @param assets The amount of MEV assets received + */ + event MevReceived(uint256 assets); - /** - * @notice Event emitted on harvest - * @param assets The amount of assets withdrawn - */ - event Harvested(uint256 assets); + /** + * @notice Event emitted on harvest + * @param assets The amount of assets withdrawn + */ + event Harvested(uint256 assets); - /** - * @notice Vault address - * @return The address of the vault that owns the escrow - */ - function vault() external view returns (address payable); + /** + * @notice Vault address + * @return The address of the vault that owns the escrow + */ + function vault() external view returns (address payable); - /** - * @notice Withdraws MEV accumulated in the escrow. Can be called only by the Vault. - * @dev IMPORTANT: because control is transferred to the Vault, care must be - * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: - * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern - * @return assets The amount of assets withdrawn - */ - function harvest() external returns (uint256 assets); + /** + * @notice Withdraws MEV accumulated in the escrow. Can be called only by the Vault. + * @dev IMPORTANT: because control is transferred to the Vault, care must be + * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: + * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern + * @return assets The amount of assets withdrawn + */ + function harvest() external returns (uint256 assets); } diff --git a/contracts/interfaces/IRewardEthToken.sol b/contracts/interfaces/IRewardEthToken.sol index 20007ac5..31acc669 100644 --- a/contracts/interfaces/IRewardEthToken.sol +++ b/contracts/interfaces/IRewardEthToken.sol @@ -9,25 +9,25 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the RewardEthToken contract */ interface IRewardEthToken { - /** - * @dev Function for getting the total assets. - */ - function totalAssets() external view returns (uint256); + /** + * @dev Function for getting the total assets. + */ + function totalAssets() external view returns (uint256); - /** - * @dev Function for retrieving the total rewards amount. - */ - function totalRewards() external view returns (uint128); + /** + * @dev Function for retrieving the total rewards amount. + */ + function totalRewards() external view returns (uint128); - /** - * @dev Function for getting the total penalty. - */ - function totalPenalty() external view returns (uint256); + /** + * @dev Function for getting the total penalty. + */ + function totalPenalty() external view returns (uint256); - /** - * @dev Function for updating validators total rewards. - * Can only be called by Vault contract. - * @param rewardsDelta - the total rewards earned or penalties received. - */ - function updateTotalRewards(int256 rewardsDelta) external; + /** + * @dev Function for updating validators total rewards. + * Can only be called by Vault contract. + * @param rewardsDelta - the total rewards earned or penalties received. + */ + function updateTotalRewards(int256 rewardsDelta) external; } diff --git a/contracts/interfaces/IRewardGnoToken.sol b/contracts/interfaces/IRewardGnoToken.sol index e2aaba2d..892bd3f6 100644 --- a/contracts/interfaces/IRewardGnoToken.sol +++ b/contracts/interfaces/IRewardGnoToken.sol @@ -9,25 +9,25 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the RewardGnoToken contract */ interface IRewardGnoToken { - /** - * @dev Function for getting the total assets. - */ - function totalAssets() external view returns (uint256); + /** + * @dev Function for getting the total assets. + */ + function totalAssets() external view returns (uint256); - /** - * @dev Function for retrieving the total rewards amount. - */ - function totalRewards() external view returns (uint128); + /** + * @dev Function for retrieving the total rewards amount. + */ + function totalRewards() external view returns (uint128); - /** - * @dev Function for getting the total penalty. - */ - function totalPenalty() external view returns (uint256); + /** + * @dev Function for getting the total penalty. + */ + function totalPenalty() external view returns (uint256); - /** - * @dev Function for updating validators total rewards. - * Can only be called by Vault contract. - * @param rewardsDelta - the total rewards earned or penalties received. - */ - function updateTotalRewards(int256 rewardsDelta) external; + /** + * @dev Function for updating validators total rewards. + * Can only be called by Vault contract. + * @param rewardsDelta - the total rewards earned or penalties received. + */ + function updateTotalRewards(int256 rewardsDelta) external; } diff --git a/contracts/interfaces/IRewardSplitter.sol b/contracts/interfaces/IRewardSplitter.sol index e5c646b8..e2a38d04 100644 --- a/contracts/interfaces/IRewardSplitter.sol +++ b/contracts/interfaces/IRewardSplitter.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IMulticall} from './IMulticall.sol'; -import {IKeeperRewards} from './IKeeperRewards.sol'; +import {IMulticall} from "./IMulticall.sol"; +import {IKeeperRewards} from "./IKeeperRewards.sol"; /** * @title IRewardSplitter @@ -11,204 +11,190 @@ import {IKeeperRewards} from './IKeeperRewards.sol'; * @notice Defines the interface for the RewardSplitter contract */ interface IRewardSplitter is IMulticall { - // Custom errors - error NotHarvested(); - error InvalidAccount(); - error InvalidAmount(); - - /** - * @notice Structure for storing information about share holder - * @param shares The amount of shares the account has - * @param rewardPerShare The last synced reward per share - */ - struct ShareHolder { - uint128 shares; - uint128 rewardPerShare; - } - - /** - * @notice Event emitted when the claim on behalf flag is updated - * @param caller The address of the account that called the function - * @param enabled The flag indicating whether the claim on behalf is enabled - */ - event ClaimOnBehalfUpdated(address caller, bool enabled); - - /** - * @notice Event emitted when the number of shares is increased for an account - * @param account The address of the account for which the shares were increased - * @param amount The amount of shares that were added - */ - event SharesIncreased(address indexed account, uint256 amount); - - /** - * @notice Event emitted when the number of shares is decreased for an account - * @param account The address of the account for which the shares were decreased - * @param amount The amount of shares that were deducted - */ - event SharesDecreased(address indexed account, uint256 amount); - - /** - * @notice Event emitted when the rewards are synced from the vault. - * @param totalRewards The new total amount of rewards - * @param rewardPerShare The new reward per share - */ - event RewardsSynced(uint256 totalRewards, uint256 rewardPerShare); - - /** - * @notice Event emitted when the rewards are withdrawn from the splitter - * @param account The address of the account for which the rewards were withdrawn - * @param amount The amount of rewards that were withdrawn - */ - event RewardsWithdrawn(address indexed account, uint256 amount); - - /** - * @notice Event emitted when the rewards are claimed on behalf - * @param onBehalf The address of the account on behalf of which the rewards were claimed - * @param positionTicket The position ticket in the exit queue - * @param amount The amount of rewards that were claimed - */ - event ExitQueueEnteredOnBehalf(address indexed onBehalf, uint256 positionTicket, uint256 amount); - - /** - * @notice Event emitted when the exited assets are claimed on behalf - * @param onBehalf The address of the account on behalf of which the assets were claimed - * @param positionTicket The position ticket in the exit queue - * @param amount The amount of assets that were claimed - */ - event ExitedAssetsClaimedOnBehalf( - address indexed onBehalf, - uint256 positionTicket, - uint256 amount - ); - - /** - * @notice The vault to which the RewardSplitter is connected - * @return The address of the vault - */ - function vault() external view returns (address); - - /** - * @notice The total number of shares in the splitter - * @return The total number of shares - */ - function totalShares() external view returns (uint256); - - /** - * @notice Returns the address of shareholder on behalf of which the rewards are claimed - * @param exitPosition The position in the exit queue - * @return onBehalf The address of shareholder - */ - function exitPositions(uint256 exitPosition) external view returns (address onBehalf); - - /** - * @notice Returns whether the claim on behalf is enabled - * @return `true` if the claim on behalf is enabled, `false` otherwise - */ - function isClaimOnBehalfEnabled() external view returns (bool); - - /** - * @notice The total amount of unclaimed rewards in the splitter - * @return The total amount of rewards - */ - function totalRewards() external view returns (uint128); - - /** - * @notice Initializes the RewardSplitter contract - * @param _vault The address of the vault to which the RewardSplitter will be connected - */ - function initialize(address _vault) external; - - /** - * @notice Sets the flag indicating whether the claim on behalf is enabled. - * @param enabled The flag indicating whether the claim on behalf is enabled - * Can only be called by the vault admin. - */ - function setClaimOnBehalf(bool enabled) external; - - /** - * @notice Retrieves the amount of splitter shares for the given account. - * The shares are used to calculate the amount of rewards the account is entitled to. - * @param account The address of the account to get shares for - */ - function sharesOf(address account) external view returns (uint256); - - /** - * @notice Retrieves the amount of rewards the account is entitled to. - * The rewards are calculated based on the amount of shares the account has. - * Note, rewards must be synced using the `syncRewards` function. - * @param account The address of the account to get rewards for - */ - function rewardsOf(address account) external view returns (uint256); - - /** - * @notice Checks whether new rewards can be synced from the vault. - * @return True if new rewards can be synced, false otherwise - */ - function canSyncRewards() external view returns (bool); - - /** - * @notice Increases the amount of shares for the given account. Can only be called by the owner. - * @param account The address of the account to increase shares for - * @param amount The amount of shares to add - */ - function increaseShares(address account, uint128 amount) external; - - /** - * @notice Decreases the amount of shares for the given account. Can only be called by the owner. - * @param account The address of the account to decrease shares for - * @param amount The amount of shares to deduct - */ - function decreaseShares(address account, uint128 amount) external; - - /** - * @notice Updates the vault state. Can be used in multicall to update state, sync rewards and withdraw them. - * @param harvestParams The harvest params to use for updating the vault state - */ - function updateVaultState(IKeeperRewards.HarvestParams calldata harvestParams) external; - - /** - * @notice Transfers the vault tokens to the given account. Can only be called for the vault with ERC-20 token. - * @param rewards The amount of vault tokens to transfer - * @param receiver The address of the account to transfer tokens to - */ - function claimVaultTokens(uint256 rewards, address receiver) external; - - /** - * @notice Sends the rewards to the exit queue - * @param rewards The amount of rewards to send to the exit queue - * @param receiver The address that will claim exited assets - * @return positionTicket The position ticket of the exit queue - */ - function enterExitQueue( - uint256 rewards, - address receiver - ) external returns (uint256 positionTicket); - - /** - * @notice Enters the exit queue on behalf of the shareholder. Can only be called if claim on behalf is enabled. - * @param rewards The amount of rewards to send to the exit queue - * @param onBehalf The address of the account on behalf of which the rewards are sent to the exit queue - * @return positionTicket The position ticket of the exit queue - */ - function enterExitQueueOnBehalf( - uint256 rewards, - address onBehalf - ) external returns (uint256 positionTicket); - - /** - * @notice Claims the exited assets from the vault. - * @param positionTicket The position ticket in the exit queue - * @param timestamp The timestamp when the shares entered the exit queue - * @param exitQueueIndex The exit queue index of the exit request - */ - function claimExitedAssetsOnBehalf( - uint256 positionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external; - - /** - * @notice Syncs the rewards from the vault to the splitter. The vault state must be up-to-date. - */ - function syncRewards() external; + // Custom errors + error NotHarvested(); + error InvalidAccount(); + error InvalidAmount(); + + /** + * @notice Structure for storing information about share holder + * @param shares The amount of shares the account has + * @param rewardPerShare The last synced reward per share + */ + struct ShareHolder { + uint128 shares; + uint128 rewardPerShare; + } + + /** + * @notice Event emitted when the claim on behalf flag is updated + * @param caller The address of the account that called the function + * @param enabled The flag indicating whether the claim on behalf is enabled + */ + event ClaimOnBehalfUpdated(address caller, bool enabled); + + /** + * @notice Event emitted when the number of shares is increased for an account + * @param account The address of the account for which the shares were increased + * @param amount The amount of shares that were added + */ + event SharesIncreased(address indexed account, uint256 amount); + + /** + * @notice Event emitted when the number of shares is decreased for an account + * @param account The address of the account for which the shares were decreased + * @param amount The amount of shares that were deducted + */ + event SharesDecreased(address indexed account, uint256 amount); + + /** + * @notice Event emitted when the rewards are synced from the vault. + * @param totalRewards The new total amount of rewards + * @param rewardPerShare The new reward per share + */ + event RewardsSynced(uint256 totalRewards, uint256 rewardPerShare); + + /** + * @notice Event emitted when the rewards are withdrawn from the splitter + * @param account The address of the account for which the rewards were withdrawn + * @param amount The amount of rewards that were withdrawn + */ + event RewardsWithdrawn(address indexed account, uint256 amount); + + /** + * @notice Event emitted when the rewards are claimed on behalf + * @param onBehalf The address of the account on behalf of which the rewards were claimed + * @param positionTicket The position ticket in the exit queue + * @param amount The amount of rewards that were claimed + */ + event ExitQueueEnteredOnBehalf(address indexed onBehalf, uint256 positionTicket, uint256 amount); + + /** + * @notice Event emitted when the exited assets are claimed on behalf + * @param onBehalf The address of the account on behalf of which the assets were claimed + * @param positionTicket The position ticket in the exit queue + * @param amount The amount of assets that were claimed + */ + event ExitedAssetsClaimedOnBehalf(address indexed onBehalf, uint256 positionTicket, uint256 amount); + + /** + * @notice The vault to which the RewardSplitter is connected + * @return The address of the vault + */ + function vault() external view returns (address); + + /** + * @notice The total number of shares in the splitter + * @return The total number of shares + */ + function totalShares() external view returns (uint256); + + /** + * @notice Returns the address of shareholder on behalf of which the rewards are claimed + * @param exitPosition The position in the exit queue + * @return onBehalf The address of shareholder + */ + function exitPositions(uint256 exitPosition) external view returns (address onBehalf); + + /** + * @notice Returns whether the claim on behalf is enabled + * @return `true` if the claim on behalf is enabled, `false` otherwise + */ + function isClaimOnBehalfEnabled() external view returns (bool); + + /** + * @notice The total amount of unclaimed rewards in the splitter + * @return The total amount of rewards + */ + function totalRewards() external view returns (uint128); + + /** + * @notice Initializes the RewardSplitter contract + * @param _vault The address of the vault to which the RewardSplitter will be connected + */ + function initialize(address _vault) external; + + /** + * @notice Sets the flag indicating whether the claim on behalf is enabled. + * @param enabled The flag indicating whether the claim on behalf is enabled + * Can only be called by the vault admin. + */ + function setClaimOnBehalf(bool enabled) external; + + /** + * @notice Retrieves the amount of splitter shares for the given account. + * The shares are used to calculate the amount of rewards the account is entitled to. + * @param account The address of the account to get shares for + */ + function sharesOf(address account) external view returns (uint256); + + /** + * @notice Retrieves the amount of rewards the account is entitled to. + * The rewards are calculated based on the amount of shares the account has. + * Note, rewards must be synced using the `syncRewards` function. + * @param account The address of the account to get rewards for + */ + function rewardsOf(address account) external view returns (uint256); + + /** + * @notice Checks whether new rewards can be synced from the vault. + * @return True if new rewards can be synced, false otherwise + */ + function canSyncRewards() external view returns (bool); + + /** + * @notice Increases the amount of shares for the given account. Can only be called by the owner. + * @param account The address of the account to increase shares for + * @param amount The amount of shares to add + */ + function increaseShares(address account, uint128 amount) external; + + /** + * @notice Decreases the amount of shares for the given account. Can only be called by the owner. + * @param account The address of the account to decrease shares for + * @param amount The amount of shares to deduct + */ + function decreaseShares(address account, uint128 amount) external; + + /** + * @notice Updates the vault state. Can be used in multicall to update state, sync rewards and withdraw them. + * @param harvestParams The harvest params to use for updating the vault state + */ + function updateVaultState(IKeeperRewards.HarvestParams calldata harvestParams) external; + + /** + * @notice Transfers the vault tokens to the given account. Can only be called for the vault with ERC-20 token. + * @param rewards The amount of vault tokens to transfer + * @param receiver The address of the account to transfer tokens to + */ + function claimVaultTokens(uint256 rewards, address receiver) external; + + /** + * @notice Sends the rewards to the exit queue + * @param rewards The amount of rewards to send to the exit queue + * @param receiver The address that will claim exited assets + * @return positionTicket The position ticket of the exit queue + */ + function enterExitQueue(uint256 rewards, address receiver) external returns (uint256 positionTicket); + + /** + * @notice Enters the exit queue on behalf of the shareholder. Can only be called if claim on behalf is enabled. + * @param rewards The amount of rewards to send to the exit queue + * @param onBehalf The address of the account on behalf of which the rewards are sent to the exit queue + * @return positionTicket The position ticket of the exit queue + */ + function enterExitQueueOnBehalf(uint256 rewards, address onBehalf) external returns (uint256 positionTicket); + + /** + * @notice Claims the exited assets from the vault. + * @param positionTicket The position ticket in the exit queue + * @param timestamp The timestamp when the shares entered the exit queue + * @param exitQueueIndex The exit queue index of the exit request + */ + function claimExitedAssetsOnBehalf(uint256 positionTicket, uint256 timestamp, uint256 exitQueueIndex) external; + + /** + * @notice Syncs the rewards from the vault to the splitter. The vault state must be up-to-date. + */ + function syncRewards() external; } diff --git a/contracts/interfaces/IRewardSplitterFactory.sol b/contracts/interfaces/IRewardSplitterFactory.sol index 19b1f511..b67be0f3 100644 --- a/contracts/interfaces/IRewardSplitterFactory.sol +++ b/contracts/interfaces/IRewardSplitterFactory.sol @@ -8,24 +8,24 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the RewardSplitterFactory contract */ interface IRewardSplitterFactory { - /** - * @notice Event emitted on a RewardSplitter creation - * @param owner The address of the RewardSplitter owner - * @param vault The address of the connected vault - * @param rewardSplitter The address of the created RewardSplitter - */ - event RewardSplitterCreated(address owner, address vault, address rewardSplitter); + /** + * @notice Event emitted on a RewardSplitter creation + * @param owner The address of the RewardSplitter owner + * @param vault The address of the connected vault + * @param rewardSplitter The address of the created RewardSplitter + */ + event RewardSplitterCreated(address owner, address vault, address rewardSplitter); - /** - * @notice The address of the RewardSplitter implementation contract used for proxy creation - * @return The address of the RewardSplitter proxy contract - */ - function implementation() external view returns (address); + /** + * @notice The address of the RewardSplitter implementation contract used for proxy creation + * @return The address of the RewardSplitter proxy contract + */ + function implementation() external view returns (address); - /** - * @notice Creates RewardSplitter contract proxy - * @param vault The address of the vault to which the RewardSplitter will be connected - * @return rewardSplitter The address of the created RewardSplitter contract - */ - function createRewardSplitter(address vault) external returns (address rewardSplitter); + /** + * @notice Creates RewardSplitter contract proxy + * @param vault The address of the vault to which the RewardSplitter will be connected + * @return rewardSplitter The address of the created RewardSplitter contract + */ + function createRewardSplitter(address vault) external returns (address rewardSplitter); } diff --git a/contracts/interfaces/ISavingsXDaiAdapter.sol b/contracts/interfaces/ISavingsXDaiAdapter.sol index 2c4e47ff..a27ef94c 100644 --- a/contracts/interfaces/ISavingsXDaiAdapter.sol +++ b/contracts/interfaces/ISavingsXDaiAdapter.sol @@ -8,10 +8,10 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the SavingsXDaiAdapter */ interface ISavingsXDaiAdapter { - /** - * @notice Convert xDAI to sDAI - * @param receiver The address of the receiver - * @return The amount of sDAI received - */ - function depositXDAI(address receiver) external payable returns (uint256); + /** + * @notice Convert xDAI to sDAI + * @param receiver The address of the receiver + * @return The amount of sDAI received + */ + function depositXDAI(address receiver) external payable returns (uint256); } diff --git a/contracts/interfaces/ISharedMevEscrow.sol b/contracts/interfaces/ISharedMevEscrow.sol index 9b136817..c178b27d 100644 --- a/contracts/interfaces/ISharedMevEscrow.sol +++ b/contracts/interfaces/ISharedMevEscrow.sol @@ -8,25 +8,25 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the SharedMevEscrow contract */ interface ISharedMevEscrow { - /** - * @notice Event emitted on received MEV - * @param assets The amount of MEV assets received - */ - event MevReceived(uint256 assets); + /** + * @notice Event emitted on received MEV + * @param assets The amount of MEV assets received + */ + event MevReceived(uint256 assets); - /** - * @notice Event emitted on harvest - * @param caller The function caller - * @param assets The amount of assets withdrawn - */ - event Harvested(address indexed caller, uint256 assets); + /** + * @notice Event emitted on harvest + * @param caller The function caller + * @param assets The amount of assets withdrawn + */ + event Harvested(address indexed caller, uint256 assets); - /** - * @notice Withdraws MEV accumulated in the escrow. Can be called only by the Vault. - * @dev IMPORTANT: because control is transferred to the Vault, care must be - * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: - * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern - * @param assets The amount of assets to withdraw - */ - function harvest(uint256 assets) external; + /** + * @notice Withdraws MEV accumulated in the escrow. Can be called only by the Vault. + * @dev IMPORTANT: because control is transferred to the Vault, care must be + * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: + * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern + * @param assets The amount of assets to withdraw + */ + function harvest(uint256 assets) external; } diff --git a/contracts/interfaces/IValidatorsChecker.sol b/contracts/interfaces/IValidatorsChecker.sol index 5585fdc2..83b6e18d 100644 --- a/contracts/interfaces/IValidatorsChecker.sol +++ b/contracts/interfaces/IValidatorsChecker.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; -import {IMulticall} from './IMulticall.sol'; +import {IKeeperRewards} from "../interfaces/IKeeperRewards.sol"; +import {IMulticall} from "./IMulticall.sol"; /** * @title IValidatorsChecker @@ -11,89 +11,86 @@ import {IMulticall} from './IMulticall.sol'; * @notice Defines the interface for ValidatorsChecker */ interface IValidatorsChecker is IMulticall { - enum Status { - SUCCEEDED, - INVALID_VALIDATORS_REGISTRY_ROOT, - INVALID_VAULT, - INSUFFICIENT_ASSETS, - INVALID_SIGNATURE, - INVALID_VALIDATORS_MANAGER, - INVALID_VALIDATORS_COUNT, - INVALID_VALIDATORS_LENGTH, - INVALID_PROOF - } + enum Status { + SUCCEEDED, + INVALID_VALIDATORS_REGISTRY_ROOT, + INVALID_VAULT, + INSUFFICIENT_ASSETS, + INVALID_SIGNATURE, + INVALID_VALIDATORS_MANAGER, + INVALID_VALIDATORS_COUNT, + INVALID_VALIDATORS_LENGTH, + INVALID_PROOF + } - /** - * @dev Struct for checking deposit data root - * @param vault The address of the vault - * @param validatorsRegistryRoot The validators registry root - * @param validators The concatenation of the validators' public key, deposit signature, deposit root - * @param proof The proof of the deposit data root - * @param proofFlags The flags of the proof - * @param proofIndexes The indexes of the proof - */ - struct DepositDataRootCheckParams { - address vault; - bytes32 validatorsRegistryRoot; - bytes validators; - bytes32[] proof; - bool[] proofFlags; - uint256[] proofIndexes; - } + /** + * @dev Struct for checking deposit data root + * @param vault The address of the vault + * @param validatorsRegistryRoot The validators registry root + * @param validators The concatenation of the validators' public key, deposit signature, deposit root + * @param proof The proof of the deposit data root + * @param proofFlags The flags of the proof + * @param proofIndexes The indexes of the proof + */ + struct DepositDataRootCheckParams { + address vault; + bytes32 validatorsRegistryRoot; + bytes validators; + bytes32[] proof; + bool[] proofFlags; + uint256[] proofIndexes; + } - /** - * @notice Function for updating vault state - * @param vault The address of the vault - * @param harvestParams The parameters for harvesting - */ - function updateVaultState( - address vault, - IKeeperRewards.HarvestParams calldata harvestParams - ) external; + /** + * @notice Function for updating vault state + * @param vault The address of the vault + * @param harvestParams The parameters for harvesting + */ + function updateVaultState(address vault, IKeeperRewards.HarvestParams calldata harvestParams) external; - /** - * @notice Function for getting the exit queue cumulative tickets - * @param vault The address of the vault - * @return The exit queue cumulative tickets - */ - function getExitQueueCumulativeTickets(address vault) external view returns (uint256); + /** + * @notice Function for getting the exit queue cumulative tickets + * @param vault The address of the vault + * @return The exit queue cumulative tickets + */ + function getExitQueueCumulativeTickets(address vault) external view returns (uint256); - /** - * @notice Function for getting the exit queue missing assets - * @param vault The address of the vault - * @param withdrawingAssets The amount of assets currently being withdrawn from validators - * @param targetCumulativeTickets The target cumulative tickets - * @return missingAssets The exit queue missing assets - */ - function getExitQueueMissingAssets( - address vault, - uint256 withdrawingAssets, - uint256 targetCumulativeTickets - ) external view returns (uint256 missingAssets); + /** + * @notice Function for getting the exit queue missing assets + * @param vault The address of the vault + * @param withdrawingAssets The amount of assets currently being withdrawn from validators + * @param targetCumulativeTickets The target cumulative tickets + * @return missingAssets The exit queue missing assets + */ + function getExitQueueMissingAssets(address vault, uint256 withdrawingAssets, uint256 targetCumulativeTickets) + external + view + returns (uint256 missingAssets); - /** - * @notice Function for checking validators manager signature - * @param vault The address of the vault - * @param validatorsRegistryRoot The validators registry root - * @param validators The concatenation of the validators' public key, deposit signature, deposit root - * @param signature The validators manager signature - * @return blockNumber Current block number - * @return status The status of the verification - */ - function checkValidatorsManagerSignature( - address vault, - bytes32 validatorsRegistryRoot, - bytes calldata validators, - bytes calldata signature - ) external view returns (uint256 blockNumber, Status status); + /** + * @notice Function for checking validators manager signature + * @param vault The address of the vault + * @param validatorsRegistryRoot The validators registry root + * @param validators The concatenation of the validators' public key, deposit signature, deposit root + * @param signature The validators manager signature + * @return blockNumber Current block number + * @return status The status of the verification + */ + function checkValidatorsManagerSignature( + address vault, + bytes32 validatorsRegistryRoot, + bytes calldata validators, + bytes calldata signature + ) external view returns (uint256 blockNumber, Status status); - /** - * @notice Function for checking deposit data root - * @param params The parameters for checking deposit data root - * @return blockNumber Current block number - * @return status The status of the verification - */ - function checkDepositDataRoot( - DepositDataRootCheckParams calldata params - ) external view returns (uint256 blockNumber, Status status); + /** + * @notice Function for checking deposit data root + * @param params The parameters for checking deposit data root + * @return blockNumber Current block number + * @return status The status of the verification + */ + function checkDepositDataRoot(DepositDataRootCheckParams calldata params) + external + view + returns (uint256 blockNumber, Status status); } diff --git a/contracts/interfaces/IValidatorsRegistry.sol b/contracts/interfaces/IValidatorsRegistry.sol index 8b79bcb3..73fe5b36 100644 --- a/contracts/interfaces/IValidatorsRegistry.sol +++ b/contracts/interfaces/IValidatorsRegistry.sol @@ -8,16 +8,10 @@ pragma solidity ^0.8.22; * @notice The validators deposit contract common interface */ interface IValidatorsRegistry { - /// @notice A processed deposit event. - event DepositEvent( - bytes pubkey, - bytes withdrawal_credentials, - bytes amount, - bytes signature, - bytes index - ); + /// @notice A processed deposit event. + event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index); - /// @notice Query the current deposit root hash. - /// @return The deposit root hash. - function get_deposit_root() external view returns (bytes32); + /// @notice Query the current deposit root hash. + /// @return The deposit root hash. + function get_deposit_root() external view returns (bytes32); } diff --git a/contracts/interfaces/IVaultAdmin.sol b/contracts/interfaces/IVaultAdmin.sol index d69be714..728b819c 100644 --- a/contracts/interfaces/IVaultAdmin.sol +++ b/contracts/interfaces/IVaultAdmin.sol @@ -8,35 +8,35 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the VaultAdmin contract */ interface IVaultAdmin { - /** - * @notice Event emitted on metadata ipfs hash update - * @param caller The address of the function caller - * @param metadataIpfsHash The new metadata IPFS hash - */ - event MetadataUpdated(address indexed caller, string metadataIpfsHash); + /** + * @notice Event emitted on metadata ipfs hash update + * @param caller The address of the function caller + * @param metadataIpfsHash The new metadata IPFS hash + */ + event MetadataUpdated(address indexed caller, string metadataIpfsHash); - /** - * @notice Event emitted on admin update - * @param caller The address of the function caller - * @param newAdmin The new admin address - */ - event AdminUpdated(address indexed caller, address newAdmin); + /** + * @notice Event emitted on admin update + * @param caller The address of the function caller + * @param newAdmin The new admin address + */ + event AdminUpdated(address indexed caller, address newAdmin); - /** - * @notice The Vault admin - * @return The address of the Vault admin - */ - function admin() external view returns (address); + /** + * @notice The Vault admin + * @return The address of the Vault admin + */ + function admin() external view returns (address); - /** - * @notice Function for updating the metadata IPFS hash. Can only be called by Vault admin. - * @param metadataIpfsHash The new metadata IPFS hash - */ - function setMetadata(string calldata metadataIpfsHash) external; + /** + * @notice Function for updating the metadata IPFS hash. Can only be called by Vault admin. + * @param metadataIpfsHash The new metadata IPFS hash + */ + function setMetadata(string calldata metadataIpfsHash) external; - /** - * @notice Function for updating the admin address. Can only be called by Vault current admin. - * @param newAdmin The new admin address - */ - function setAdmin(address newAdmin) external; + /** + * @notice Function for updating the admin address. Can only be called by Vault current admin. + * @param newAdmin The new admin address + */ + function setAdmin(address newAdmin) external; } diff --git a/contracts/interfaces/IVaultBlocklist.sol b/contracts/interfaces/IVaultBlocklist.sol index 00ba18ad..6e051b26 100644 --- a/contracts/interfaces/IVaultBlocklist.sol +++ b/contracts/interfaces/IVaultBlocklist.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IVaultAdmin} from './IVaultAdmin.sol'; +import {IVaultAdmin} from "./IVaultAdmin.sol"; /** * @title IVaultBlocklist @@ -10,44 +10,44 @@ import {IVaultAdmin} from './IVaultAdmin.sol'; * @notice Defines the interface for the VaultBlocklist contract */ interface IVaultBlocklist is IVaultAdmin { - /** - * @notice Event emitted on blocklist update - * @param caller The address of the function caller - * @param account The address of the account updated - * @param isBlocked Whether account is blocked or not - */ - event BlocklistUpdated(address indexed caller, address indexed account, bool isBlocked); - - /** - * @notice Event emitted when blocklist manager address is updated - * @param caller The address of the function caller - * @param blocklistManager The address of the new blocklist manager - */ - event BlocklistManagerUpdated(address indexed caller, address indexed blocklistManager); - - /** - * @notice Blocklist manager address - * @return The address of the blocklist manager - */ - function blocklistManager() external view returns (address); - - /** - * @notice Checks whether account is blocked or not - * @param account The account to check - * @return `true` for the blocked account, `false` otherwise - */ - function blockedAccounts(address account) external view returns (bool); - - /** - * @notice Add or remove account from the blocklist. Can only be called by the blocklist manager. - * @param account The account to add or remove to the blocklist - * @param isBlocked Whether account should be blocked or not - */ - function updateBlocklist(address account, bool isBlocked) external; - - /** - * @notice Used to update the blocklist manager. Can only be called by the Vault admin. - * @param _blocklistManager The address of the new blocklist manager - */ - function setBlocklistManager(address _blocklistManager) external; + /** + * @notice Event emitted on blocklist update + * @param caller The address of the function caller + * @param account The address of the account updated + * @param isBlocked Whether account is blocked or not + */ + event BlocklistUpdated(address indexed caller, address indexed account, bool isBlocked); + + /** + * @notice Event emitted when blocklist manager address is updated + * @param caller The address of the function caller + * @param blocklistManager The address of the new blocklist manager + */ + event BlocklistManagerUpdated(address indexed caller, address indexed blocklistManager); + + /** + * @notice Blocklist manager address + * @return The address of the blocklist manager + */ + function blocklistManager() external view returns (address); + + /** + * @notice Checks whether account is blocked or not + * @param account The account to check + * @return `true` for the blocked account, `false` otherwise + */ + function blockedAccounts(address account) external view returns (bool); + + /** + * @notice Add or remove account from the blocklist. Can only be called by the blocklist manager. + * @param account The account to add or remove to the blocklist + * @param isBlocked Whether account should be blocked or not + */ + function updateBlocklist(address account, bool isBlocked) external; + + /** + * @notice Used to update the blocklist manager. Can only be called by the Vault admin. + * @param _blocklistManager The address of the new blocklist manager + */ + function setBlocklistManager(address _blocklistManager) external; } diff --git a/contracts/interfaces/IVaultEnterExit.sol b/contracts/interfaces/IVaultEnterExit.sol index d688a5fd..3c7f9f0c 100644 --- a/contracts/interfaces/IVaultEnterExit.sol +++ b/contracts/interfaces/IVaultEnterExit.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IVaultState} from './IVaultState.sol'; +import {IVaultState} from "./IVaultState.sol"; /** * @title IVaultEnterExit @@ -10,121 +10,94 @@ import {IVaultState} from './IVaultState.sol'; * @notice Defines the interface for the VaultEnterExit contract */ interface IVaultEnterExit is IVaultState { - /** - * @notice Event emitted on deposit - * @param caller The address that called the deposit function - * @param receiver The address that received the shares - * @param assets The number of assets deposited by the caller - * @param shares The number of shares received - * @param referrer The address of the referrer - */ - event Deposited( - address indexed caller, - address indexed receiver, - uint256 assets, - uint256 shares, - address referrer - ); + /** + * @notice Event emitted on deposit + * @param caller The address that called the deposit function + * @param receiver The address that received the shares + * @param assets The number of assets deposited by the caller + * @param shares The number of shares received + * @param referrer The address of the referrer + */ + event Deposited(address indexed caller, address indexed receiver, uint256 assets, uint256 shares, address referrer); - /** - * @notice Event emitted on redeem - * @param owner The address that owns the shares - * @param receiver The address that received withdrawn assets - * @param assets The total number of withdrawn assets - * @param shares The total number of withdrawn shares - */ - event Redeemed(address indexed owner, address indexed receiver, uint256 assets, uint256 shares); + /** + * @notice Event emitted on redeem + * @param owner The address that owns the shares + * @param receiver The address that received withdrawn assets + * @param assets The total number of withdrawn assets + * @param shares The total number of withdrawn shares + */ + event Redeemed(address indexed owner, address indexed receiver, uint256 assets, uint256 shares); - /** - * @notice Event emitted on shares added to the exit queue - * @param owner The address that owns the shares - * @param receiver The address that will receive withdrawn assets - * @param positionTicket The exit queue ticket that was assigned to the position - * @param shares The number of shares that queued for the exit - */ - event ExitQueueEntered( - address indexed owner, - address indexed receiver, - uint256 positionTicket, - uint256 shares - ); + /** + * @notice Event emitted on shares added to the exit queue + * @param owner The address that owns the shares + * @param receiver The address that will receive withdrawn assets + * @param positionTicket The exit queue ticket that was assigned to the position + * @param shares The number of shares that queued for the exit + */ + event ExitQueueEntered(address indexed owner, address indexed receiver, uint256 positionTicket, uint256 shares); - /** - * @notice Event emitted on shares added to the V2 exit queue (deprecated) - * @param owner The address that owns the shares - * @param receiver The address that will receive withdrawn assets - * @param positionTicket The exit queue ticket that was assigned to the position - * @param shares The number of shares that queued for the exit - * @param assets The number of assets that queued for the exit - */ - event V2ExitQueueEntered( - address indexed owner, - address indexed receiver, - uint256 positionTicket, - uint256 shares, - uint256 assets - ); + /** + * @notice Event emitted on shares added to the V2 exit queue (deprecated) + * @param owner The address that owns the shares + * @param receiver The address that will receive withdrawn assets + * @param positionTicket The exit queue ticket that was assigned to the position + * @param shares The number of shares that queued for the exit + * @param assets The number of assets that queued for the exit + */ + event V2ExitQueueEntered( + address indexed owner, address indexed receiver, uint256 positionTicket, uint256 shares, uint256 assets + ); - /** - * @notice Event emitted on claim of the exited assets - * @param receiver The address that has received withdrawn assets - * @param prevPositionTicket The exit queue ticket received after the `enterExitQueue` call - * @param newPositionTicket The new exit queue ticket in case not all the shares were withdrawn. Otherwise 0. - * @param withdrawnAssets The total number of assets withdrawn - */ - event ExitedAssetsClaimed( - address indexed receiver, - uint256 prevPositionTicket, - uint256 newPositionTicket, - uint256 withdrawnAssets - ); + /** + * @notice Event emitted on claim of the exited assets + * @param receiver The address that has received withdrawn assets + * @param prevPositionTicket The exit queue ticket received after the `enterExitQueue` call + * @param newPositionTicket The new exit queue ticket in case not all the shares were withdrawn. Otherwise 0. + * @param withdrawnAssets The total number of assets withdrawn + */ + event ExitedAssetsClaimed( + address indexed receiver, uint256 prevPositionTicket, uint256 newPositionTicket, uint256 withdrawnAssets + ); - /** - * @notice Locks shares to the exit queue. The shares continue earning rewards until they will be burned by the Vault. - * @param shares The number of shares to lock - * @param receiver The address that will receive assets upon withdrawal - * @return positionTicket The position ticket of the exit queue. Returns uint256 max if no ticket created. - */ - function enterExitQueue( - uint256 shares, - address receiver - ) external returns (uint256 positionTicket); + /** + * @notice Locks shares to the exit queue. The shares continue earning rewards until they will be burned by the Vault. + * @param shares The number of shares to lock + * @param receiver The address that will receive assets upon withdrawal + * @return positionTicket The position ticket of the exit queue. Returns uint256 max if no ticket created. + */ + function enterExitQueue(uint256 shares, address receiver) external returns (uint256 positionTicket); - /** - * @notice Get the exit queue index to claim exited assets from - * @param positionTicket The exit queue position ticket to get the index for - * @return The exit queue index that should be used to claim exited assets. - * Returns -1 in case such index does not exist. - */ - function getExitQueueIndex(uint256 positionTicket) external view returns (int256); + /** + * @notice Get the exit queue index to claim exited assets from + * @param positionTicket The exit queue position ticket to get the index for + * @return The exit queue index that should be used to claim exited assets. + * Returns -1 in case such index does not exist. + */ + function getExitQueueIndex(uint256 positionTicket) external view returns (int256); - /** - * @notice Calculates the number of shares and assets that can be claimed from the exit queue. - * @param receiver The address that will receive assets upon withdrawal - * @param positionTicket The exit queue ticket received after the `enterExitQueue` call - * @param timestamp The timestamp when the shares entered the exit queue - * @param exitQueueIndex The exit queue index at which the shares were burned. It can be looked up by calling `getExitQueueIndex`. - * @return leftTickets The number of tickets left in the queue - * @return exitedTickets The number of tickets that have already exited - * @return exitedAssets The number of assets that can be claimed - */ - function calculateExitedAssets( - address receiver, - uint256 positionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external view returns (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets); + /** + * @notice Calculates the number of shares and assets that can be claimed from the exit queue. + * @param receiver The address that will receive assets upon withdrawal + * @param positionTicket The exit queue ticket received after the `enterExitQueue` call + * @param timestamp The timestamp when the shares entered the exit queue + * @param exitQueueIndex The exit queue index at which the shares were burned. It can be looked up by calling `getExitQueueIndex`. + * @return leftTickets The number of tickets left in the queue + * @return exitedTickets The number of tickets that have already exited + * @return exitedAssets The number of assets that can be claimed + */ + function calculateExitedAssets(address receiver, uint256 positionTicket, uint256 timestamp, uint256 exitQueueIndex) + external + view + returns (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets); - /** - * @notice Claims assets that were withdrawn by the Vault. It can be called only after the `enterExitQueue` call by the `receiver`. - * @param positionTicket The exit queue ticket received after the `enterExitQueue` call - * @param timestamp The timestamp when the assets entered the exit queue - * @param exitQueueIndex The exit queue index at which the shares were burned. - * It can be looked up by calling `getExitQueueIndex`. - */ - function claimExitedAssets( - uint256 positionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external; + /** + * @notice Claims assets that were withdrawn by the Vault. It can be called only after the `enterExitQueue` call by the `receiver`. + * @param positionTicket The exit queue ticket received after the `enterExitQueue` call + * @param timestamp The timestamp when the assets entered the exit queue + * @param exitQueueIndex The exit queue index at which the shares were burned. + * It can be looked up by calling `getExitQueueIndex`. + */ + function claimExitedAssets(uint256 positionTicket, uint256 timestamp, uint256 exitQueueIndex) external; } diff --git a/contracts/interfaces/IVaultEthStaking.sol b/contracts/interfaces/IVaultEthStaking.sol index 07361e45..21a4b402 100644 --- a/contracts/interfaces/IVaultEthStaking.sol +++ b/contracts/interfaces/IVaultEthStaking.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {IVaultState} from './IVaultState.sol'; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; -import {IKeeperRewards} from './IKeeperRewards.sol'; -import {IVaultMev} from './IVaultMev.sol'; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IVaultMev} from "./IVaultMev.sol"; /** * @title IVaultEthStaking @@ -14,29 +14,29 @@ import {IVaultMev} from './IVaultMev.sol'; * @notice Defines the interface for the VaultEthStaking contract */ interface IVaultEthStaking is IVaultState, IVaultValidators, IVaultEnterExit, IVaultMev { - /** - * @notice Deposit ETH to the Vault - * @param receiver The address that will receive Vault's shares - * @param referrer The address of the referrer. Set to zero address if not used. - * @return shares The number of shares minted - */ - function deposit(address receiver, address referrer) external payable returns (uint256 shares); + /** + * @notice Deposit ETH to the Vault + * @param receiver The address that will receive Vault's shares + * @param referrer The address of the referrer. Set to zero address if not used. + * @return shares The number of shares minted + */ + function deposit(address receiver, address referrer) external payable returns (uint256 shares); - /** - * @notice Used by MEV escrow to transfer ETH. - */ - function receiveFromMevEscrow() external payable; + /** + * @notice Used by MEV escrow to transfer ETH. + */ + function receiveFromMevEscrow() external payable; - /** - * @notice Updates Vault state and deposits ETH to the Vault - * @param receiver The address that will receive Vault's shares - * @param referrer The address of the referrer. Set to zero address if not used. - * @param harvestParams The parameters for harvesting Keeper rewards - * @return shares The number of shares minted - */ - function updateStateAndDeposit( - address receiver, - address referrer, - IKeeperRewards.HarvestParams calldata harvestParams - ) external payable returns (uint256 shares); + /** + * @notice Updates Vault state and deposits ETH to the Vault + * @param receiver The address that will receive Vault's shares + * @param referrer The address of the referrer. Set to zero address if not used. + * @param harvestParams The parameters for harvesting Keeper rewards + * @return shares The number of shares minted + */ + function updateStateAndDeposit( + address receiver, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable returns (uint256 shares); } diff --git a/contracts/interfaces/IVaultFee.sol b/contracts/interfaces/IVaultFee.sol index 13db45c6..aa182197 100644 --- a/contracts/interfaces/IVaultFee.sol +++ b/contracts/interfaces/IVaultFee.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IVaultAdmin} from './IVaultAdmin.sol'; +import {IVaultAdmin} from "./IVaultAdmin.sol"; /** * @title IVaultFee @@ -10,41 +10,41 @@ import {IVaultAdmin} from './IVaultAdmin.sol'; * @notice Defines the interface for the VaultFee contract */ interface IVaultFee is IVaultAdmin { - /** - * @notice Event emitted on fee recipient update - * @param caller The address of the function caller - * @param feeRecipient The address of the new fee recipient - */ - event FeeRecipientUpdated(address indexed caller, address indexed feeRecipient); - - /** - * @notice Event emitted on fee percent update - * @param caller The address of the function caller - * @param feePercent The new fee percent - */ - event FeePercentUpdated(address indexed caller, uint16 feePercent); - - /** - * @notice The Vault's fee recipient - * @return The address of the Vault's fee recipient - */ - function feeRecipient() external view returns (address); - - /** - * @notice The Vault's fee percent in BPS - * @return The fee percent applied by the Vault on the rewards - */ - function feePercent() external view returns (uint16); - - /** - * @notice Function for updating the fee recipient address. Can only be called by the admin. - * @param _feeRecipient The address of the new fee recipient - */ - function setFeeRecipient(address _feeRecipient) external; - - /** - * @notice Function for updating the fee percent. Can only be called by the admin. - * @param _feePercent The new fee percent - */ - function setFeePercent(uint16 _feePercent) external; + /** + * @notice Event emitted on fee recipient update + * @param caller The address of the function caller + * @param feeRecipient The address of the new fee recipient + */ + event FeeRecipientUpdated(address indexed caller, address indexed feeRecipient); + + /** + * @notice Event emitted on fee percent update + * @param caller The address of the function caller + * @param feePercent The new fee percent + */ + event FeePercentUpdated(address indexed caller, uint16 feePercent); + + /** + * @notice The Vault's fee recipient + * @return The address of the Vault's fee recipient + */ + function feeRecipient() external view returns (address); + + /** + * @notice The Vault's fee percent in BPS + * @return The fee percent applied by the Vault on the rewards + */ + function feePercent() external view returns (uint16); + + /** + * @notice Function for updating the fee recipient address. Can only be called by the admin. + * @param _feeRecipient The address of the new fee recipient + */ + function setFeeRecipient(address _feeRecipient) external; + + /** + * @notice Function for updating the fee percent. Can only be called by the admin. + * @param _feePercent The new fee percent + */ + function setFeePercent(uint16 _feePercent) external; } diff --git a/contracts/interfaces/IVaultGnoStaking.sol b/contracts/interfaces/IVaultGnoStaking.sol index e0dcfb5f..e0f27409 100644 --- a/contracts/interfaces/IVaultGnoStaking.sol +++ b/contracts/interfaces/IVaultGnoStaking.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultValidators} from './IVaultValidators.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; +import {IVaultValidators} from "./IVaultValidators.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; /** * @title IVaultGnoStaking @@ -11,23 +11,19 @@ import {IVaultEnterExit} from './IVaultEnterExit.sol'; * @notice Defines the interface for the VaultGnoStaking contract */ interface IVaultGnoStaking is IVaultValidators, IVaultEnterExit { - /** - * @notice Emitted when xDAI is swapped to GNO (deprecated) - * @param amount The amount of xDAI swapped - * @param assets The amount of GNO received - */ - event XdaiSwapped(uint256 amount, uint256 assets); + /** + * @notice Emitted when xDAI is swapped to GNO (deprecated) + * @param amount The amount of xDAI swapped + * @param assets The amount of GNO received + */ + event XdaiSwapped(uint256 amount, uint256 assets); - /** - * @notice Deposit GNO to the Vault - * @param assets The amount of GNO to deposit - * @param receiver The address that will receive Vault's shares - * @param referrer The address of the referrer. Set to zero address if not used. - * @return shares The number of shares minted - */ - function deposit( - uint256 assets, - address receiver, - address referrer - ) external returns (uint256 shares); + /** + * @notice Deposit GNO to the Vault + * @param assets The amount of GNO to deposit + * @param receiver The address that will receive Vault's shares + * @param referrer The address of the referrer. Set to zero address if not used. + * @return shares The number of shares minted + */ + function deposit(uint256 assets, address receiver, address referrer) external returns (uint256 shares); } diff --git a/contracts/interfaces/IVaultMev.sol b/contracts/interfaces/IVaultMev.sol index 6125f871..5263d0ee 100644 --- a/contracts/interfaces/IVaultMev.sol +++ b/contracts/interfaces/IVaultMev.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IVaultState} from './IVaultState.sol'; +import {IVaultState} from "./IVaultState.sol"; /** * @title IVaultMev @@ -10,9 +10,9 @@ import {IVaultState} from './IVaultState.sol'; * @notice Common interface for the VaultMev contracts */ interface IVaultMev is IVaultState { - /** - * @notice The contract that accumulates MEV rewards - * @return The MEV escrow contract address - */ - function mevEscrow() external view returns (address); + /** + * @notice The contract that accumulates MEV rewards + * @return The MEV escrow contract address + */ + function mevEscrow() external view returns (address); } diff --git a/contracts/interfaces/IVaultOsToken.sol b/contracts/interfaces/IVaultOsToken.sol index 8a35526c..2d892469 100644 --- a/contracts/interfaces/IVaultOsToken.sol +++ b/contracts/interfaces/IVaultOsToken.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IVaultState} from './IVaultState.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; /** * @title IVaultOsToken @@ -11,126 +11,114 @@ import {IVaultEnterExit} from './IVaultEnterExit.sol'; * @notice Defines the interface for the VaultOsToken contract */ interface IVaultOsToken is IVaultState, IVaultEnterExit { - /** - * @notice Event emitted on minting osToken - * @param caller The address of the function caller - * @param receiver The address of the osToken receiver - * @param assets The amount of minted assets - * @param shares The amount of minted shares - * @param referrer The address of the referrer - */ - event OsTokenMinted( - address indexed caller, - address receiver, - uint256 assets, - uint256 shares, - address referrer - ); + /** + * @notice Event emitted on minting osToken + * @param caller The address of the function caller + * @param receiver The address of the osToken receiver + * @param assets The amount of minted assets + * @param shares The amount of minted shares + * @param referrer The address of the referrer + */ + event OsTokenMinted(address indexed caller, address receiver, uint256 assets, uint256 shares, address referrer); - /** - * @notice Event emitted on burning OsToken - * @param caller The address of the function caller - * @param assets The amount of burned assets - * @param shares The amount of burned shares - */ - event OsTokenBurned(address indexed caller, uint256 assets, uint256 shares); + /** + * @notice Event emitted on burning OsToken + * @param caller The address of the function caller + * @param assets The amount of burned assets + * @param shares The amount of burned shares + */ + event OsTokenBurned(address indexed caller, uint256 assets, uint256 shares); - /** - * @notice Event emitted on osToken position liquidation - * @param caller The address of the function caller - * @param user The address of the user liquidated - * @param receiver The address of the receiver of the liquidated assets - * @param osTokenShares The amount of osToken shares to liquidate - * @param shares The amount of vault shares burned - * @param receivedAssets The amount of assets received - */ - event OsTokenLiquidated( - address indexed caller, - address indexed user, - address receiver, - uint256 osTokenShares, - uint256 shares, - uint256 receivedAssets - ); + /** + * @notice Event emitted on osToken position liquidation + * @param caller The address of the function caller + * @param user The address of the user liquidated + * @param receiver The address of the receiver of the liquidated assets + * @param osTokenShares The amount of osToken shares to liquidate + * @param shares The amount of vault shares burned + * @param receivedAssets The amount of assets received + */ + event OsTokenLiquidated( + address indexed caller, + address indexed user, + address receiver, + uint256 osTokenShares, + uint256 shares, + uint256 receivedAssets + ); - /** - * @notice Event emitted on osToken position redemption - * @param caller The address of the function caller - * @param user The address of the position owner to redeem from - * @param receiver The address of the receiver of the redeemed assets - * @param osTokenShares The amount of osToken shares to redeem - * @param shares The amount of vault shares burned - * @param assets The amount of assets received - */ - event OsTokenRedeemed( - address indexed caller, - address indexed user, - address receiver, - uint256 osTokenShares, - uint256 shares, - uint256 assets - ); + /** + * @notice Event emitted on osToken position redemption + * @param caller The address of the function caller + * @param user The address of the position owner to redeem from + * @param receiver The address of the receiver of the redeemed assets + * @param osTokenShares The amount of osToken shares to redeem + * @param shares The amount of vault shares burned + * @param assets The amount of assets received + */ + event OsTokenRedeemed( + address indexed caller, + address indexed user, + address receiver, + uint256 osTokenShares, + uint256 shares, + uint256 assets + ); - /** - * @notice Struct of osToken position - * @param shares The total number of minted osToken shares. Will increase based on the treasury fee. - * @param cumulativeFeePerShare The cumulative fee per share - */ - struct OsTokenPosition { - uint128 shares; - uint128 cumulativeFeePerShare; - } + /** + * @notice Struct of osToken position + * @param shares The total number of minted osToken shares. Will increase based on the treasury fee. + * @param cumulativeFeePerShare The cumulative fee per share + */ + struct OsTokenPosition { + uint128 shares; + uint128 cumulativeFeePerShare; + } - /** - * @notice Get total amount of minted osToken shares - * @param user The address of the user - * @return shares The number of minted osToken shares - */ - function osTokenPositions(address user) external view returns (uint128 shares); + /** + * @notice Get total amount of minted osToken shares + * @param user The address of the user + * @return shares The number of minted osToken shares + */ + function osTokenPositions(address user) external view returns (uint128 shares); - /** - * @notice Mints OsToken shares - * @param receiver The address that will receive the minted OsToken shares - * @param osTokenShares The number of OsToken shares to mint to the receiver. To mint the maximum amount of shares, use 2^256 - 1. - * @param referrer The address of the referrer - * @return assets The number of assets minted to the receiver - */ - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) external returns (uint256 assets); + /** + * @notice Mints OsToken shares + * @param receiver The address that will receive the minted OsToken shares + * @param osTokenShares The number of OsToken shares to mint to the receiver. To mint the maximum amount of shares, use 2^256 - 1. + * @param referrer The address of the referrer + * @return assets The number of assets minted to the receiver + */ + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) external returns (uint256 assets); - /** - * @notice Burns osToken shares - * @param osTokenShares The number of shares to burn - * @return assets The number of assets burned - */ - function burnOsToken(uint128 osTokenShares) external returns (uint256 assets); + /** + * @notice Burns osToken shares + * @param osTokenShares The number of shares to burn + * @return assets The number of assets burned + */ + function burnOsToken(uint128 osTokenShares) external returns (uint256 assets); - /** - * @notice Liquidates a user position and returns the number of received assets. - * Can only be called when health factor is below 1 by the liquidator. - * @param osTokenShares The number of shares to cover - * @param owner The address of the position owner to liquidate - * @param receiver The address of the receiver of the liquidated assets - */ - function liquidateOsToken(uint256 osTokenShares, address owner, address receiver) external; + /** + * @notice Liquidates a user position and returns the number of received assets. + * Can only be called when health factor is below 1 by the liquidator. + * @param osTokenShares The number of shares to cover + * @param owner The address of the position owner to liquidate + * @param receiver The address of the receiver of the liquidated assets + */ + function liquidateOsToken(uint256 osTokenShares, address owner, address receiver) external; - /** - * @notice Redeems osToken shares for assets. Can only be called when health factor is above redeemFromHealthFactor by the redeemer. - * @param osTokenShares The number of osToken shares to redeem - * @param owner The address of the position owner to redeem from - * @param receiver The address of the receiver of the redeemed assets - */ - function redeemOsToken(uint256 osTokenShares, address owner, address receiver) external; + /** + * @notice Redeems osToken shares for assets. Can only be called when health factor is above redeemFromHealthFactor by the redeemer. + * @param osTokenShares The number of osToken shares to redeem + * @param owner The address of the position owner to redeem from + * @param receiver The address of the receiver of the redeemed assets + */ + function redeemOsToken(uint256 osTokenShares, address owner, address receiver) external; - /** - * @notice Transfers minted osToken shares to the OsTokenVaultEscrow contract, enters the exit queue for staked assets - * @param osTokenShares The number of osToken shares to transfer - * @return positionTicket The exit position ticket - */ - function transferOsTokenPositionToEscrow( - uint256 osTokenShares - ) external returns (uint256 positionTicket); + /** + * @notice Transfers minted osToken shares to the OsTokenVaultEscrow contract, enters the exit queue for staked assets + * @param osTokenShares The number of osToken shares to transfer + * @return positionTicket The exit position ticket + */ + function transferOsTokenPositionToEscrow(uint256 osTokenShares) external returns (uint256 positionTicket); } diff --git a/contracts/interfaces/IVaultState.sol b/contracts/interfaces/IVaultState.sol index 91cd6383..a9ff7578 100644 --- a/contracts/interfaces/IVaultState.sol +++ b/contracts/interfaces/IVaultState.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IKeeperRewards} from './IKeeperRewards.sol'; -import {IVaultFee} from './IVaultFee.sol'; +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IVaultFee} from "./IVaultFee.sol"; /** * @title IVaultState @@ -11,100 +11,100 @@ import {IVaultFee} from './IVaultFee.sol'; * @notice Defines the interface for the VaultState contract */ interface IVaultState is IVaultFee { - /** - * @notice Event emitted on checkpoint creation - * @param shares The number of burned shares - * @param assets The amount of exited assets - */ - event CheckpointCreated(uint256 shares, uint256 assets); + /** + * @notice Event emitted on checkpoint creation + * @param shares The number of burned shares + * @param assets The amount of exited assets + */ + event CheckpointCreated(uint256 shares, uint256 assets); - /** - * @notice Event emitted on minting fee recipient shares - * @param receiver The address of the fee recipient - * @param shares The number of minted shares - * @param assets The amount of minted assets - */ - event FeeSharesMinted(address receiver, uint256 shares, uint256 assets); + /** + * @notice Event emitted on minting fee recipient shares + * @param receiver The address of the fee recipient + * @param shares The number of minted shares + * @param assets The amount of minted assets + */ + event FeeSharesMinted(address receiver, uint256 shares, uint256 assets); - /** - * @notice Event emitted when exiting assets are penalized (deprecated) - * @param penalty The total penalty amount - */ - event ExitingAssetsPenalized(uint256 penalty); + /** + * @notice Event emitted when exiting assets are penalized (deprecated) + * @param penalty The total penalty amount + */ + event ExitingAssetsPenalized(uint256 penalty); - /** - * @notice Total assets in the Vault - * @return The total amount of the underlying asset that is "managed" by Vault - */ - function totalAssets() external view returns (uint256); + /** + * @notice Total assets in the Vault + * @return The total amount of the underlying asset that is "managed" by Vault + */ + function totalAssets() external view returns (uint256); - /** - * @notice Function for retrieving total shares - * @return The amount of shares in existence - */ - function totalShares() external view returns (uint256); + /** + * @notice Function for retrieving total shares + * @return The amount of shares in existence + */ + function totalShares() external view returns (uint256); - /** - * @notice The Vault's capacity - * @return The amount after which the Vault stops accepting deposits - */ - function capacity() external view returns (uint256); + /** + * @notice The Vault's capacity + * @return The amount after which the Vault stops accepting deposits + */ + function capacity() external view returns (uint256); - /** - * @notice Total assets available in the Vault. They can be staked or withdrawn. - * @return The total amount of withdrawable assets - */ - function withdrawableAssets() external view returns (uint256); + /** + * @notice Total assets available in the Vault. They can be staked or withdrawn. + * @return The total amount of withdrawable assets + */ + function withdrawableAssets() external view returns (uint256); - /** - * @notice Get exit queue data - * @return queuedShares The number of shares in the exit queue - * @return unclaimedAssets The amount of unclaimed assets in the exit queue - * @return totalExitingTickets The total number of exiting tickets - * @return totalExitingAssets The total amount of exiting assets - * @return totalTickets The total number of tickets in the exit queue - */ - function getExitQueueData() - external - view - returns ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ); + /** + * @notice Get exit queue data + * @return queuedShares The number of shares in the exit queue + * @return unclaimedAssets The amount of unclaimed assets in the exit queue + * @return totalExitingTickets The total number of exiting tickets + * @return totalExitingAssets The total amount of exiting assets + * @return totalTickets The total number of tickets in the exit queue + */ + function getExitQueueData() + external + view + returns ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ); - /** - * @notice Returns the number of shares held by an account - * @param account The account for which to look up the number of shares it has, i.e. its balance - * @return The number of shares held by the account - */ - function getShares(address account) external view returns (uint256); + /** + * @notice Returns the number of shares held by an account + * @param account The account for which to look up the number of shares it has, i.e. its balance + * @return The number of shares held by the account + */ + function getShares(address account) external view returns (uint256); - /** - * @notice Converts assets to shares - * @param assets The amount of assets to convert to shares - * @return shares The amount of shares that the Vault would exchange for the amount of assets provided - */ - function convertToShares(uint256 assets) external view returns (uint256 shares); + /** + * @notice Converts assets to shares + * @param assets The amount of assets to convert to shares + * @return shares The amount of shares that the Vault would exchange for the amount of assets provided + */ + function convertToShares(uint256 assets) external view returns (uint256 shares); - /** - * @notice Converts shares to assets - * @param shares The amount of shares to convert to assets - * @return assets The amount of assets that the Vault would exchange for the amount of shares provided - */ - function convertToAssets(uint256 shares) external view returns (uint256 assets); + /** + * @notice Converts shares to assets + * @param shares The amount of shares to convert to assets + * @return assets The amount of assets that the Vault would exchange for the amount of shares provided + */ + function convertToAssets(uint256 shares) external view returns (uint256 assets); - /** - * @notice Check whether state update is required - * @return `true` if state update is required, `false` otherwise - */ - function isStateUpdateRequired() external view returns (bool); + /** + * @notice Check whether state update is required + * @return `true` if state update is required, `false` otherwise + */ + function isStateUpdateRequired() external view returns (bool); - /** - * @notice Updates the total amount of assets in the Vault and its exit queue - * @param harvestParams The parameters for harvesting Keeper rewards - */ - function updateState(IKeeperRewards.HarvestParams calldata harvestParams) external; + /** + * @notice Updates the total amount of assets in the Vault and its exit queue + * @param harvestParams The parameters for harvesting Keeper rewards + */ + function updateState(IKeeperRewards.HarvestParams calldata harvestParams) external; } diff --git a/contracts/interfaces/IVaultToken.sol b/contracts/interfaces/IVaultToken.sol index c3617746..8eb3737c 100644 --- a/contracts/interfaces/IVaultToken.sol +++ b/contracts/interfaces/IVaultToken.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol'; -import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; -import {IVaultState} from './IVaultState.sol'; -import {IVaultEnterExit} from './IVaultEnterExit.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; /** * @title IVaultToken diff --git a/contracts/interfaces/IVaultValidators.sol b/contracts/interfaces/IVaultValidators.sol index bdac149e..156d6c84 100644 --- a/contracts/interfaces/IVaultValidators.sol +++ b/contracts/interfaces/IVaultValidators.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {IKeeperValidators} from './IKeeperValidators.sol'; -import {IVaultAdmin} from './IVaultAdmin.sol'; -import {IVaultState} from './IVaultState.sol'; +import {IKeeperValidators} from "./IKeeperValidators.sol"; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultState} from "./IVaultState.sol"; /** * @title IVaultValidators @@ -12,127 +12,123 @@ import {IVaultState} from './IVaultState.sol'; * @notice Defines the interface for VaultValidators contract */ interface IVaultValidators is IVaultAdmin, IVaultState { - /** - * @notice Event emitted on V1 validator registration - * @param publicKey The public key of the validator that was registered - */ - event ValidatorRegistered(bytes publicKey); - - /** - * @notice Event emitted on V2 validator registration - * @param publicKey The public key of the validator that was registered - * @param amount The amount of assets that was registered - */ - event V2ValidatorRegistered(bytes publicKey, uint256 amount); - - /** - * @notice Event emitted on validator withdrawal - * @param publicKey The public key of the validator that was withdrawn - * @param amount The amount of assets that was withdrawn - * @param feePaid The amount of fee that was paid - */ - event ValidatorWithdrawalSubmitted(bytes publicKey, uint256 amount, uint256 feePaid); - - /** - * @notice Event emitted on validator balance top-up - * @param publicKey The public key of the validator that was funded - * @param amount The amount of assets that was funded - */ - event ValidatorFunded(bytes publicKey, uint256 amount); - - /** - * @notice Event emitted on validators consolidation - * @param fromPublicKey The public key of the validator that was consolidated - * @param toPublicKey The public key of the validator that was consolidated to - * @param feePaid The amount of fee that was paid - */ - event ValidatorConsolidationSubmitted(bytes fromPublicKey, bytes toPublicKey, uint256 feePaid); - - /** - * @notice Event emitted on keys manager address update (deprecated) - * @param caller The address of the function caller - * @param keysManager The address of the new keys manager - */ - event KeysManagerUpdated(address indexed caller, address indexed keysManager); - - /** - * @notice Event emitted on validators merkle tree root update (deprecated) - * @param caller The address of the function caller - * @param validatorsRoot The new validators merkle tree root - */ - event ValidatorsRootUpdated(address indexed caller, bytes32 indexed validatorsRoot); - - /** - * @notice Event emitted on validators manager address update - * @param caller The address of the function caller - * @param validatorsManager The address of the new validators manager - */ - event ValidatorsManagerUpdated(address indexed caller, address indexed validatorsManager); - - /** - * @notice The Vault validators manager address - * @return The address that can register validators - */ - function validatorsManager() external view returns (address); - - /** - * @notice The nonce for the validators manager used for signing - * @return The nonce for the validators manager - */ - function validatorsManagerNonce() external view returns (uint256); - - /** - * @notice Function for checking if the validator is tracked V2 validator - * @param publicKeyHash The keccak256 hash of the public key of the validator - * @return Whether the validator is tracked V2 validator - */ - function v2Validators(bytes32 publicKeyHash) external view returns (bool); - - /** - * @notice Function for funding single or multiple existing validators - * @param validators The concatenated validators data - * @param validatorsManagerSignature The optional signature from the validators manager - */ - function fundValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) external; - - /** - * @notice Function for withdrawing single or multiple validators - * @param validators The concatenated validators data - * @param validatorsManagerSignature The optional signature from the validators manager - */ - function withdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) external payable; - - /** - * @notice Function for consolidating single or multiple validators - * @param validators The concatenated validators data - * @param validatorsManagerSignature The optional signature from the validators manager - * @param oracleSignatures The optional signatures from the oracles - */ - function consolidateValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature, - bytes calldata oracleSignatures - ) external payable; - - /** - * @notice Function for registering single or multiple validators - * @param keeperParams The parameters for getting approval from Keeper oracles - * @param validatorsManagerSignature The optional signature from the validators manager - */ - function registerValidators( - IKeeperValidators.ApprovalParams calldata keeperParams, - bytes calldata validatorsManagerSignature - ) external; - - /** - * @notice Function for updating the validators manager. Can only be called by the admin. Default is the DepositDataRegistry contract. - * @param _validatorsManager The new validators manager address - */ - function setValidatorsManager(address _validatorsManager) external; + /** + * @notice Event emitted on V1 validator registration + * @param publicKey The public key of the validator that was registered + */ + event ValidatorRegistered(bytes publicKey); + + /** + * @notice Event emitted on V2 validator registration + * @param publicKey The public key of the validator that was registered + * @param amount The amount of assets that was registered + */ + event V2ValidatorRegistered(bytes publicKey, uint256 amount); + + /** + * @notice Event emitted on validator withdrawal + * @param publicKey The public key of the validator that was withdrawn + * @param amount The amount of assets that was withdrawn + * @param feePaid The amount of fee that was paid + */ + event ValidatorWithdrawalSubmitted(bytes publicKey, uint256 amount, uint256 feePaid); + + /** + * @notice Event emitted on validator balance top-up + * @param publicKey The public key of the validator that was funded + * @param amount The amount of assets that was funded + */ + event ValidatorFunded(bytes publicKey, uint256 amount); + + /** + * @notice Event emitted on validators consolidation + * @param fromPublicKey The public key of the validator that was consolidated + * @param toPublicKey The public key of the validator that was consolidated to + * @param feePaid The amount of fee that was paid + */ + event ValidatorConsolidationSubmitted(bytes fromPublicKey, bytes toPublicKey, uint256 feePaid); + + /** + * @notice Event emitted on keys manager address update (deprecated) + * @param caller The address of the function caller + * @param keysManager The address of the new keys manager + */ + event KeysManagerUpdated(address indexed caller, address indexed keysManager); + + /** + * @notice Event emitted on validators merkle tree root update (deprecated) + * @param caller The address of the function caller + * @param validatorsRoot The new validators merkle tree root + */ + event ValidatorsRootUpdated(address indexed caller, bytes32 indexed validatorsRoot); + + /** + * @notice Event emitted on validators manager address update + * @param caller The address of the function caller + * @param validatorsManager The address of the new validators manager + */ + event ValidatorsManagerUpdated(address indexed caller, address indexed validatorsManager); + + /** + * @notice The Vault validators manager address + * @return The address that can register validators + */ + function validatorsManager() external view returns (address); + + /** + * @notice The nonce for the validators manager used for signing + * @return The nonce for the validators manager + */ + function validatorsManagerNonce() external view returns (uint256); + + /** + * @notice Function for checking if the validator is tracked V2 validator + * @param publicKeyHash The keccak256 hash of the public key of the validator + * @return Whether the validator is tracked V2 validator + */ + function v2Validators(bytes32 publicKeyHash) external view returns (bool); + + /** + * @notice Function for funding single or multiple existing validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + */ + function fundValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) external; + + /** + * @notice Function for withdrawing single or multiple validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + */ + function withdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + external + payable; + + /** + * @notice Function for consolidating single or multiple validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + * @param oracleSignatures The optional signatures from the oracles + */ + function consolidateValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature, + bytes calldata oracleSignatures + ) external payable; + + /** + * @notice Function for registering single or multiple validators + * @param keeperParams The parameters for getting approval from Keeper oracles + * @param validatorsManagerSignature The optional signature from the validators manager + */ + function registerValidators( + IKeeperValidators.ApprovalParams calldata keeperParams, + bytes calldata validatorsManagerSignature + ) external; + + /** + * @notice Function for updating the validators manager. Can only be called by the admin. Default is the DepositDataRegistry contract. + * @param _validatorsManager The new validators manager address + */ + function setValidatorsManager(address _validatorsManager) external; } diff --git a/contracts/interfaces/IVaultVersion.sol b/contracts/interfaces/IVaultVersion.sol index 6eb8b504..b2680365 100644 --- a/contracts/interfaces/IVaultVersion.sol +++ b/contracts/interfaces/IVaultVersion.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IERC1822Proxiable} from '@openzeppelin/contracts/interfaces/draft-IERC1822.sol'; -import {IVaultAdmin} from './IVaultAdmin.sol'; +import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; +import {IVaultAdmin} from "./IVaultAdmin.sol"; /** * @title IVaultVersion @@ -11,21 +11,21 @@ import {IVaultAdmin} from './IVaultAdmin.sol'; * @notice Defines the interface for VaultVersion contract */ interface IVaultVersion is IERC1822Proxiable, IVaultAdmin { - /** - * @notice Vault Unique Identifier - * @return The unique identifier of the Vault - */ - function vaultId() external pure returns (bytes32); + /** + * @notice Vault Unique Identifier + * @return The unique identifier of the Vault + */ + function vaultId() external pure returns (bytes32); - /** - * @notice Version - * @return The version of the Vault implementation contract - */ - function version() external pure returns (uint8); + /** + * @notice Version + * @return The version of the Vault implementation contract + */ + function version() external pure returns (uint8); - /** - * @notice Implementation - * @return The address of the Vault implementation contract - */ - function implementation() external view returns (address); + /** + * @notice Implementation + * @return The address of the Vault implementation contract + */ + function implementation() external view returns (address); } diff --git a/contracts/interfaces/IVaultWhitelist.sol b/contracts/interfaces/IVaultWhitelist.sol index 0543e5d3..e6f19adb 100644 --- a/contracts/interfaces/IVaultWhitelist.sol +++ b/contracts/interfaces/IVaultWhitelist.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {IVaultAdmin} from './IVaultAdmin.sol'; +import {IVaultAdmin} from "./IVaultAdmin.sol"; /** * @title IVaultWhitelist @@ -10,44 +10,44 @@ import {IVaultAdmin} from './IVaultAdmin.sol'; * @notice Defines the interface for the VaultWhitelist contract */ interface IVaultWhitelist is IVaultAdmin { - /** - * @notice Event emitted on whitelist update - * @param caller The address of the function caller - * @param account The address of the account updated - * @param approved Whether account is approved or not - */ - event WhitelistUpdated(address indexed caller, address indexed account, bool approved); - - /** - * @notice Event emitted when whitelister address is updated - * @param caller The address of the function caller - * @param whitelister The address of the new whitelister - */ - event WhitelisterUpdated(address indexed caller, address indexed whitelister); - - /** - * @notice Whitelister address - * @return The address of the whitelister - */ - function whitelister() external view returns (address); - - /** - * @notice Checks whether account is whitelisted or not - * @param account The account to check - * @return `true` for the whitelisted account, `false` otherwise - */ - function whitelistedAccounts(address account) external view returns (bool); - - /** - * @notice Add or remove account from the whitelist. Can only be called by the whitelister. - * @param account The account to add or remove from the whitelist - * @param approved Whether account should be whitelisted or not - */ - function updateWhitelist(address account, bool approved) external; - - /** - * @notice Used to update the whitelister. Can only be called by the Vault admin. - * @param _whitelister The address of the new whitelister - */ - function setWhitelister(address _whitelister) external; + /** + * @notice Event emitted on whitelist update + * @param caller The address of the function caller + * @param account The address of the account updated + * @param approved Whether account is approved or not + */ + event WhitelistUpdated(address indexed caller, address indexed account, bool approved); + + /** + * @notice Event emitted when whitelister address is updated + * @param caller The address of the function caller + * @param whitelister The address of the new whitelister + */ + event WhitelisterUpdated(address indexed caller, address indexed whitelister); + + /** + * @notice Whitelister address + * @return The address of the whitelister + */ + function whitelister() external view returns (address); + + /** + * @notice Checks whether account is whitelisted or not + * @param account The account to check + * @return `true` for the whitelisted account, `false` otherwise + */ + function whitelistedAccounts(address account) external view returns (bool); + + /** + * @notice Add or remove account from the whitelist. Can only be called by the whitelister. + * @param account The account to add or remove from the whitelist + * @param approved Whether account should be whitelisted or not + */ + function updateWhitelist(address account, bool approved) external; + + /** + * @notice Used to update the whitelister. Can only be called by the Vault admin. + * @param _whitelister The address of the new whitelister + */ + function setWhitelister(address _whitelister) external; } diff --git a/contracts/interfaces/IVaultsRegistry.sol b/contracts/interfaces/IVaultsRegistry.sol index d145da3b..3571a021 100644 --- a/contracts/interfaces/IVaultsRegistry.sol +++ b/contracts/interfaces/IVaultsRegistry.sol @@ -8,91 +8,91 @@ pragma solidity ^0.8.22; * @notice Defines the interface for the VaultsRegistry */ interface IVaultsRegistry { - /** - * @notice Event emitted on a Vault addition - * @param caller The address that has added the Vault - * @param vault The address of the added Vault - */ - event VaultAdded(address indexed caller, address indexed vault); + /** + * @notice Event emitted on a Vault addition + * @param caller The address that has added the Vault + * @param vault The address of the added Vault + */ + event VaultAdded(address indexed caller, address indexed vault); - /** - * @notice Event emitted on adding Vault implementation contract - * @param impl The address of the new implementation contract - */ - event VaultImplAdded(address indexed impl); + /** + * @notice Event emitted on adding Vault implementation contract + * @param impl The address of the new implementation contract + */ + event VaultImplAdded(address indexed impl); - /** - * @notice Event emitted on removing Vault implementation contract - * @param impl The address of the removed implementation contract - */ - event VaultImplRemoved(address indexed impl); + /** + * @notice Event emitted on removing Vault implementation contract + * @param impl The address of the removed implementation contract + */ + event VaultImplRemoved(address indexed impl); - /** - * @notice Event emitted on whitelisting the factory - * @param factory The address of the whitelisted factory - */ - event FactoryAdded(address indexed factory); + /** + * @notice Event emitted on whitelisting the factory + * @param factory The address of the whitelisted factory + */ + event FactoryAdded(address indexed factory); - /** - * @notice Event emitted on removing the factory from the whitelist - * @param factory The address of the factory removed from the whitelist - */ - event FactoryRemoved(address indexed factory); + /** + * @notice Event emitted on removing the factory from the whitelist + * @param factory The address of the factory removed from the whitelist + */ + event FactoryRemoved(address indexed factory); - /** - * @notice Registered Vaults - * @param vault The address of the vault to check whether it is registered - * @return `true` for the registered Vault, `false` otherwise - */ - function vaults(address vault) external view returns (bool); + /** + * @notice Registered Vaults + * @param vault The address of the vault to check whether it is registered + * @return `true` for the registered Vault, `false` otherwise + */ + function vaults(address vault) external view returns (bool); - /** - * @notice Registered Vault implementations - * @param impl The address of the vault implementation - * @return `true` for the registered implementation, `false` otherwise - */ - function vaultImpls(address impl) external view returns (bool); + /** + * @notice Registered Vault implementations + * @param impl The address of the vault implementation + * @return `true` for the registered implementation, `false` otherwise + */ + function vaultImpls(address impl) external view returns (bool); - /** - * @notice Registered Factories - * @param factory The address of the factory to check whether it is whitelisted - * @return `true` for the whitelisted Factory, `false` otherwise - */ - function factories(address factory) external view returns (bool); + /** + * @notice Registered Factories + * @param factory The address of the factory to check whether it is whitelisted + * @return `true` for the whitelisted Factory, `false` otherwise + */ + function factories(address factory) external view returns (bool); - /** - * @notice Function for adding Vault to the registry. Can only be called by the whitelisted Factory. - * @param vault The address of the Vault to add - */ - function addVault(address vault) external; + /** + * @notice Function for adding Vault to the registry. Can only be called by the whitelisted Factory. + * @param vault The address of the Vault to add + */ + function addVault(address vault) external; - /** - * @notice Function for adding Vault implementation contract - * @param newImpl The address of the new implementation contract - */ - function addVaultImpl(address newImpl) external; + /** + * @notice Function for adding Vault implementation contract + * @param newImpl The address of the new implementation contract + */ + function addVaultImpl(address newImpl) external; - /** - * @notice Function for removing Vault implementation contract - * @param impl The address of the removed implementation contract - */ - function removeVaultImpl(address impl) external; + /** + * @notice Function for removing Vault implementation contract + * @param impl The address of the removed implementation contract + */ + function removeVaultImpl(address impl) external; - /** - * @notice Function for adding the factory to the whitelist - * @param factory The address of the factory to add to the whitelist - */ - function addFactory(address factory) external; + /** + * @notice Function for adding the factory to the whitelist + * @param factory The address of the factory to add to the whitelist + */ + function addFactory(address factory) external; - /** - * @notice Function for removing the factory from the whitelist - * @param factory The address of the factory to remove from the whitelist - */ - function removeFactory(address factory) external; + /** + * @notice Function for removing the factory from the whitelist + * @param factory The address of the factory to remove from the whitelist + */ + function removeFactory(address factory) external; - /** - * @notice Function for initializing the registry. Can only be called once during the deployment. - * @param _owner The address of the owner of the contract - */ - function initialize(address _owner) external; + /** + * @notice Function for initializing the registry. Can only be called once during the deployment. + * @param _owner The address of the owner of the contract + */ + function initialize(address _owner) external; } diff --git a/contracts/keeper/Keeper.sol b/contracts/keeper/Keeper.sol index 732c8625..f9d0c833 100644 --- a/contracts/keeper/Keeper.sol +++ b/contracts/keeper/Keeper.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; -import {IKeeper} from '../interfaces/IKeeper.sol'; -import {KeeperValidators} from './KeeperValidators.sol'; -import {KeeperRewards} from './KeeperRewards.sol'; -import {KeeperOracles} from './KeeperOracles.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {IValidatorsRegistry} from "../interfaces/IValidatorsRegistry.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {IOsTokenVaultController} from "../interfaces/IOsTokenVaultController.sol"; +import {IKeeper} from "../interfaces/IKeeper.sol"; +import {KeeperValidators} from "./KeeperValidators.sol"; +import {KeeperRewards} from "./KeeperRewards.sol"; +import {KeeperOracles} from "./KeeperOracles.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title Keeper @@ -17,43 +17,37 @@ import {Errors} from '../libraries/Errors.sol'; * @notice Defines the functionality for updating Vaults' rewards and approving validators registrations */ contract Keeper is KeeperOracles, KeeperRewards, KeeperValidators, IKeeper { - bool private _initialized; + bool private _initialized; - /** - * @dev Constructor - * @param sharedMevEscrow The address of the shared MEV escrow contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param _rewardsDelay The delay in seconds between rewards updates - * @param maxAvgRewardPerSecond The maximum possible average reward per second - * @param validatorsRegistry The address of the beacon chain validators registry contract - */ - constructor( - address sharedMevEscrow, - IVaultsRegistry vaultsRegistry, - IOsTokenVaultController osTokenVaultController, - uint256 _rewardsDelay, - uint256 maxAvgRewardPerSecond, - IValidatorsRegistry validatorsRegistry - ) - KeeperOracles() - KeeperRewards( - sharedMevEscrow, - vaultsRegistry, - osTokenVaultController, - _rewardsDelay, - maxAvgRewardPerSecond + /** + * @dev Constructor + * @param sharedMevEscrow The address of the shared MEV escrow contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param _rewardsDelay The delay in seconds between rewards updates + * @param maxAvgRewardPerSecond The maximum possible average reward per second + * @param validatorsRegistry The address of the beacon chain validators registry contract + */ + constructor( + address sharedMevEscrow, + IVaultsRegistry vaultsRegistry, + IOsTokenVaultController osTokenVaultController, + uint256 _rewardsDelay, + uint256 maxAvgRewardPerSecond, + IValidatorsRegistry validatorsRegistry ) - KeeperValidators(validatorsRegistry) - {} + KeeperOracles() + KeeperRewards(sharedMevEscrow, vaultsRegistry, osTokenVaultController, _rewardsDelay, maxAvgRewardPerSecond) + KeeperValidators(validatorsRegistry) + {} - /// @inheritdoc IKeeper - function initialize(address _owner) external override onlyOwner { - if (_owner == address(0)) revert Errors.ZeroAddress(); - if (_initialized) revert Errors.AccessDenied(); + /// @inheritdoc IKeeper + function initialize(address _owner) external override onlyOwner { + if (_owner == address(0)) revert Errors.ZeroAddress(); + if (_initialized) revert Errors.AccessDenied(); - // transfer ownership - _transferOwnership(_owner); - _initialized = true; - } + // transfer ownership + _transferOwnership(_owner); + _initialized = true; + } } diff --git a/contracts/keeper/KeeperOracles.sol b/contracts/keeper/KeeperOracles.sol index 83ec40fc..05e6f73f 100644 --- a/contracts/keeper/KeeperOracles.sol +++ b/contracts/keeper/KeeperOracles.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; -import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {IKeeperOracles} from '../interfaces/IKeeperOracles.sol'; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {IKeeperOracles} from "../interfaces/IKeeperOracles.sol"; /** * @title KeeperOracles @@ -14,100 +14,97 @@ import {IKeeperOracles} from '../interfaces/IKeeperOracles.sol'; * @notice Defines the functionality for verifying signatures of the whitelisted off-chain oracles */ abstract contract KeeperOracles is Ownable2Step, EIP712, IKeeperOracles { - uint256 internal constant _signatureLength = 65; - uint256 private constant _maxOracles = 30; + uint256 internal constant _signatureLength = 65; + uint256 private constant _maxOracles = 30; - /// @inheritdoc IKeeperOracles - mapping(address => bool) public override isOracle; + /// @inheritdoc IKeeperOracles + mapping(address => bool) public override isOracle; - /// @inheritdoc IKeeperOracles - uint256 public override totalOracles; + /// @inheritdoc IKeeperOracles + uint256 public override totalOracles; - /** - * @dev Constructor - */ - constructor() Ownable(msg.sender) EIP712('KeeperOracles', '1') {} + /** + * @dev Constructor + */ + constructor() Ownable(msg.sender) EIP712("KeeperOracles", "1") {} - /// @inheritdoc IKeeperOracles - function addOracle(address oracle) external override onlyOwner { - if (isOracle[oracle]) revert Errors.AlreadyAdded(); + /// @inheritdoc IKeeperOracles + function addOracle(address oracle) external override onlyOwner { + if (isOracle[oracle]) revert Errors.AlreadyAdded(); - // SLOAD to memory - uint256 _totalOracles = totalOracles; - unchecked { - // capped with _maxOracles - _totalOracles += 1; + // SLOAD to memory + uint256 _totalOracles = totalOracles; + unchecked { + // capped with _maxOracles + _totalOracles += 1; + } + if (_totalOracles > _maxOracles) revert Errors.MaxOraclesExceeded(); + + // update state + isOracle[oracle] = true; + totalOracles = _totalOracles; + + emit OracleAdded(oracle); } - if (_totalOracles > _maxOracles) revert Errors.MaxOraclesExceeded(); - // update state - isOracle[oracle] = true; - totalOracles = _totalOracles; + /// @inheritdoc IKeeperOracles + function removeOracle(address oracle) external override onlyOwner { + if (!isOracle[oracle]) revert Errors.AlreadyRemoved(); - emit OracleAdded(oracle); - } + // SLOAD to memory + uint256 _totalOracles; + unchecked { + // cannot underflow + _totalOracles = totalOracles - 1; + } - /// @inheritdoc IKeeperOracles - function removeOracle(address oracle) external override onlyOwner { - if (!isOracle[oracle]) revert Errors.AlreadyRemoved(); + isOracle[oracle] = false; + totalOracles = _totalOracles; - // SLOAD to memory - uint256 _totalOracles; - unchecked { - // cannot underflow - _totalOracles = totalOracles - 1; + emit OracleRemoved(oracle); } - isOracle[oracle] = false; - totalOracles = _totalOracles; - - emit OracleRemoved(oracle); - } - - /// @inheritdoc IKeeperOracles - function updateConfig(string calldata configIpfsHash) external override onlyOwner { - emit ConfigUpdated(configIpfsHash); - } - - /** - * @notice Internal function for verifying oracles' signatures - * @param requiredSignatures The number of signatures required for the verification to pass - * @param message The message that was signed - * @param signatures The concatenation of the oracles' signatures - */ - function _verifySignatures( - uint256 requiredSignatures, - bytes32 message, - bytes calldata signatures - ) internal view { - if (requiredSignatures == 0) revert Errors.InvalidOracles(); - - // check whether enough signatures - unchecked { - // cannot realistically overflow - if (signatures.length < requiredSignatures * _signatureLength) - revert Errors.NotEnoughSignatures(); + /// @inheritdoc IKeeperOracles + function updateConfig(string calldata configIpfsHash) external override onlyOwner { + emit ConfigUpdated(configIpfsHash); } - bytes32 data = _hashTypedDataV4(message); - address lastOracle; - address currentOracle; - uint256 startIndex; - for (uint256 i = 0; i < requiredSignatures; i++) { - unchecked { - // cannot overflow as signatures.length is checked above - currentOracle = ECDSA.recover(data, signatures[startIndex:startIndex + _signatureLength]); - } - // signatures must be sorted by oracles' addresses and not repeat - if (currentOracle <= lastOracle || !isOracle[currentOracle]) revert Errors.InvalidOracle(); - - // update last oracle - lastOracle = currentOracle; - - unchecked { - // cannot realistically overflow - startIndex += _signatureLength; - } + /** + * @notice Internal function for verifying oracles' signatures + * @param requiredSignatures The number of signatures required for the verification to pass + * @param message The message that was signed + * @param signatures The concatenation of the oracles' signatures + */ + function _verifySignatures(uint256 requiredSignatures, bytes32 message, bytes calldata signatures) internal view { + if (requiredSignatures == 0) revert Errors.InvalidOracles(); + + // check whether enough signatures + unchecked { + // cannot realistically overflow + if (signatures.length < requiredSignatures * _signatureLength) { + revert Errors.NotEnoughSignatures(); + } + } + + bytes32 data = _hashTypedDataV4(message); + address lastOracle; + address currentOracle; + uint256 startIndex; + for (uint256 i = 0; i < requiredSignatures; i++) { + unchecked { + // cannot overflow as signatures.length is checked above + currentOracle = ECDSA.recover(data, signatures[startIndex:startIndex + _signatureLength]); + } + // signatures must be sorted by oracles' addresses and not repeat + if (currentOracle <= lastOracle || !isOracle[currentOracle]) revert Errors.InvalidOracle(); + + // update last oracle + lastOracle = currentOracle; + + unchecked { + // cannot realistically overflow + startIndex += _signatureLength; + } + } } - } } diff --git a/contracts/keeper/KeeperRewards.sol b/contracts/keeper/KeeperRewards.sol index 527e9302..8a15e238 100644 --- a/contracts/keeper/KeeperRewards.sol +++ b/contracts/keeper/KeeperRewards.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.22; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; -import {IVaultMev} from '../interfaces/IVaultMev.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; -import {KeeperOracles} from './KeeperOracles.sol'; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +import {IKeeperRewards} from "../interfaces/IKeeperRewards.sol"; +import {IVaultMev} from "../interfaces/IVaultMev.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {IOsTokenVaultController} from "../interfaces/IOsTokenVaultController.sol"; +import {KeeperOracles} from "./KeeperOracles.sol"; /** * @title KeeperRewards @@ -16,232 +16,228 @@ import {KeeperOracles} from './KeeperOracles.sol'; * @notice Defines the functionality for updating Vaults' and OsToken rewards */ abstract contract KeeperRewards is KeeperOracles, IKeeperRewards { - bytes32 private constant _rewardsUpdateTypeHash = - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' + bytes32 private constant _rewardsUpdateTypeHash = keccak256( + "KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)" ); - uint256 private immutable _maxAvgRewardPerSecond; + uint256 private immutable _maxAvgRewardPerSecond; - address private immutable _sharedMevEscrow; + address private immutable _sharedMevEscrow; - IOsTokenVaultController private immutable _osTokenVaultController; + IOsTokenVaultController private immutable _osTokenVaultController; - IVaultsRegistry internal immutable _vaultsRegistry; + IVaultsRegistry internal immutable _vaultsRegistry; - /// @inheritdoc IKeeperRewards - uint256 public immutable override rewardsDelay; + /// @inheritdoc IKeeperRewards + uint256 public immutable override rewardsDelay; - /// @inheritdoc IKeeperRewards - mapping(address => Reward) public override rewards; + /// @inheritdoc IKeeperRewards + mapping(address => Reward) public override rewards; - /// @inheritdoc IKeeperRewards - mapping(address => UnlockedMevReward) public override unlockedMevRewards; + /// @inheritdoc IKeeperRewards + mapping(address => UnlockedMevReward) public override unlockedMevRewards; - /// @inheritdoc IKeeperRewards - bytes32 public override prevRewardsRoot; + /// @inheritdoc IKeeperRewards + bytes32 public override prevRewardsRoot; - /// @inheritdoc IKeeperRewards - bytes32 public override rewardsRoot; + /// @inheritdoc IKeeperRewards + bytes32 public override rewardsRoot; - /// @inheritdoc IKeeperRewards - uint256 public override rewardsMinOracles; + /// @inheritdoc IKeeperRewards + uint256 public override rewardsMinOracles; - /// @inheritdoc IKeeperRewards - uint64 public override lastRewardsTimestamp; + /// @inheritdoc IKeeperRewards + uint64 public override lastRewardsTimestamp; - /// @inheritdoc IKeeperRewards - uint64 public override rewardsNonce; + /// @inheritdoc IKeeperRewards + uint64 public override rewardsNonce; - /** - * @dev Constructor - * @param sharedMevEscrow The address of the shared MEV escrow contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param _rewardsDelay The delay in seconds between rewards updates - * @param maxAvgRewardPerSecond The maximum possible average reward per second - */ - constructor( - address sharedMevEscrow, - IVaultsRegistry vaultsRegistry, - IOsTokenVaultController osTokenVaultController, - uint256 _rewardsDelay, - uint256 maxAvgRewardPerSecond - ) { - _sharedMevEscrow = sharedMevEscrow; - _vaultsRegistry = vaultsRegistry; - _osTokenVaultController = osTokenVaultController; - rewardsDelay = _rewardsDelay; - _maxAvgRewardPerSecond = maxAvgRewardPerSecond; - - // set rewardsNonce to 1 so that vaults collateralized - // before first rewards update will not have 0 nonce - rewardsNonce = 1; - } - - /// @inheritdoc IKeeperRewards - function updateRewards(RewardsUpdateParams calldata params) external override { - if (!canUpdateRewards()) revert Errors.TooEarlyUpdate(); - - if (params.avgRewardPerSecond > _maxAvgRewardPerSecond) { - revert Errors.InvalidAvgRewardPerSecond(); + /** + * @dev Constructor + * @param sharedMevEscrow The address of the shared MEV escrow contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param _rewardsDelay The delay in seconds between rewards updates + * @param maxAvgRewardPerSecond The maximum possible average reward per second + */ + constructor( + address sharedMevEscrow, + IVaultsRegistry vaultsRegistry, + IOsTokenVaultController osTokenVaultController, + uint256 _rewardsDelay, + uint256 maxAvgRewardPerSecond + ) { + _sharedMevEscrow = sharedMevEscrow; + _vaultsRegistry = vaultsRegistry; + _osTokenVaultController = osTokenVaultController; + rewardsDelay = _rewardsDelay; + _maxAvgRewardPerSecond = maxAvgRewardPerSecond; + + // set rewardsNonce to 1 so that vaults collateralized + // before first rewards update will not have 0 nonce + rewardsNonce = 1; } - // SLOAD to memory - uint64 nonce = rewardsNonce; - - // verify rewards update signatures - _verifySignatures( - rewardsMinOracles, - keccak256( - abi.encode( - _rewardsUpdateTypeHash, - params.rewardsRoot, - keccak256(bytes(params.rewardsIpfsHash)), - params.avgRewardPerSecond, - params.updateTimestamp, - nonce - ) - ), - params.signatures - ); - - // update state - prevRewardsRoot = rewardsRoot; - rewardsRoot = params.rewardsRoot; - // cannot overflow on human timescales - lastRewardsTimestamp = uint64(block.timestamp); - unchecked { - // cannot realistically overflow - rewardsNonce = nonce + 1; + /// @inheritdoc IKeeperRewards + function updateRewards(RewardsUpdateParams calldata params) external override { + if (!canUpdateRewards()) revert Errors.TooEarlyUpdate(); + + if (params.avgRewardPerSecond > _maxAvgRewardPerSecond) { + revert Errors.InvalidAvgRewardPerSecond(); + } + + // SLOAD to memory + uint64 nonce = rewardsNonce; + + // verify rewards update signatures + _verifySignatures( + rewardsMinOracles, + keccak256( + abi.encode( + _rewardsUpdateTypeHash, + params.rewardsRoot, + keccak256(bytes(params.rewardsIpfsHash)), + params.avgRewardPerSecond, + params.updateTimestamp, + nonce + ) + ), + params.signatures + ); + + // update state + prevRewardsRoot = rewardsRoot; + rewardsRoot = params.rewardsRoot; + // cannot overflow on human timescales + lastRewardsTimestamp = uint64(block.timestamp); + unchecked { + // cannot realistically overflow + rewardsNonce = nonce + 1; + } + + _osTokenVaultController.setAvgRewardPerSecond(params.avgRewardPerSecond); + + emit RewardsUpdated( + msg.sender, + params.rewardsRoot, + params.avgRewardPerSecond, + params.updateTimestamp, + nonce, + params.rewardsIpfsHash + ); } - _osTokenVaultController.setAvgRewardPerSecond(params.avgRewardPerSecond); + /// @inheritdoc IKeeperRewards + function canUpdateRewards() public view override returns (bool) { + unchecked { + // cannot overflow as lastRewardsTimestamp & rewardsDelay are uint64 + return lastRewardsTimestamp + rewardsDelay < block.timestamp; + } + } - emit RewardsUpdated( - msg.sender, - params.rewardsRoot, - params.avgRewardPerSecond, - params.updateTimestamp, - nonce, - params.rewardsIpfsHash - ); - } + /// @inheritdoc IKeeperRewards + function isHarvestRequired(address vault) external view override returns (bool) { + // vault is considered harvested in case it does not have any validators (nonce = 0) + // or it is up to 1 rewards update behind + uint256 nonce = rewards[vault].nonce; + unchecked { + // cannot overflow as nonce is uint64 + return nonce != 0 && nonce + 1 < rewardsNonce; + } + } - /// @inheritdoc IKeeperRewards - function canUpdateRewards() public view override returns (bool) { - unchecked { - // cannot overflow as lastRewardsTimestamp & rewardsDelay are uint64 - return lastRewardsTimestamp + rewardsDelay < block.timestamp; + /// @inheritdoc IKeeperRewards + function canHarvest(address vault) external view override returns (bool) { + uint256 nonce = rewards[vault].nonce; + return nonce != 0 && nonce < rewardsNonce; } - } - - /// @inheritdoc IKeeperRewards - function isHarvestRequired(address vault) external view override returns (bool) { - // vault is considered harvested in case it does not have any validators (nonce = 0) - // or it is up to 1 rewards update behind - uint256 nonce = rewards[vault].nonce; - unchecked { - // cannot overflow as nonce is uint64 - return nonce != 0 && nonce + 1 < rewardsNonce; + + /// @inheritdoc IKeeperRewards + function isCollateralized(address vault) public view override returns (bool) { + return rewards[vault].nonce != 0; } - } - - /// @inheritdoc IKeeperRewards - function canHarvest(address vault) external view override returns (bool) { - uint256 nonce = rewards[vault].nonce; - return nonce != 0 && nonce < rewardsNonce; - } - - /// @inheritdoc IKeeperRewards - function isCollateralized(address vault) public view override returns (bool) { - return rewards[vault].nonce != 0; - } - - /// @inheritdoc IKeeperRewards - function harvest( - HarvestParams calldata params - ) external override returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested) { - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); - - // SLOAD to memory - uint64 currentNonce = rewardsNonce; - - // allow harvest for the past two updates - if (params.rewardsRoot != rewardsRoot) { - if (params.rewardsRoot != prevRewardsRoot) revert Errors.InvalidRewardsRoot(); - unchecked { - // cannot underflow as after first merkle root update nonce will be "2" - currentNonce -= 1; - } + + /// @inheritdoc IKeeperRewards + function harvest(HarvestParams calldata params) + external + override + returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested) + { + if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); + + // SLOAD to memory + uint64 currentNonce = rewardsNonce; + + // allow harvest for the past two updates + if (params.rewardsRoot != rewardsRoot) { + if (params.rewardsRoot != prevRewardsRoot) revert Errors.InvalidRewardsRoot(); + unchecked { + // cannot underflow as after first merkle root update nonce will be "2" + currentNonce -= 1; + } + } + + // verify the proof + if ( + !MerkleProof.verifyCalldata( + params.proof, + params.rewardsRoot, + keccak256(bytes.concat(keccak256(abi.encode(msg.sender, params.reward, params.unlockedMevReward)))) + ) + ) { + revert Errors.InvalidProof(); + } + + // SLOAD to memory + Reward storage lastReward = rewards[msg.sender]; + // check whether Vault's nonce is smaller that the current, otherwise it's already harvested + if (lastReward.nonce >= currentNonce) return (0, 0, false); + + // calculate total assets delta + totalAssetsDelta = params.reward - lastReward.assets; + harvested = true; + + // update state + lastReward.nonce = currentNonce; + lastReward.assets = params.reward; + + // check whether Vault has unlocked execution reward + if (IVaultMev(msg.sender).mevEscrow() == _sharedMevEscrow) { + // calculate execution assets reward + unlockedMevDelta = params.unlockedMevReward - unlockedMevRewards[msg.sender].assets; + + // update state + unlockedMevRewards[msg.sender] = UnlockedMevReward({nonce: currentNonce, assets: params.unlockedMevReward}); + } + + // emit event + emit Harvested(msg.sender, params.rewardsRoot, totalAssetsDelta, unlockedMevDelta); } - // verify the proof - if ( - !MerkleProof.verifyCalldata( - params.proof, - params.rewardsRoot, - keccak256( - bytes.concat(keccak256(abi.encode(msg.sender, params.reward, params.unlockedMevReward))) - ) - ) - ) { - revert Errors.InvalidProof(); + /// @inheritdoc IKeeperRewards + function setRewardsMinOracles(uint256 _rewardsMinOracles) external override onlyOwner { + _setRewardsMinOracles(_rewardsMinOracles); } - // SLOAD to memory - Reward storage lastReward = rewards[msg.sender]; - // check whether Vault's nonce is smaller that the current, otherwise it's already harvested - if (lastReward.nonce >= currentNonce) return (0, 0, false); - - // calculate total assets delta - totalAssetsDelta = params.reward - lastReward.assets; - harvested = true; - - // update state - lastReward.nonce = currentNonce; - lastReward.assets = params.reward; - - // check whether Vault has unlocked execution reward - if (IVaultMev(msg.sender).mevEscrow() == _sharedMevEscrow) { - // calculate execution assets reward - unlockedMevDelta = params.unlockedMevReward - unlockedMevRewards[msg.sender].assets; - - // update state - unlockedMevRewards[msg.sender] = UnlockedMevReward({ - nonce: currentNonce, - assets: params.unlockedMevReward - }); + /** + * @dev Internal function for updating rewardsMinOracles + * @param _rewardsMinOracles The new value of rewardsMinOracles + */ + function _setRewardsMinOracles(uint256 _rewardsMinOracles) private { + if (_rewardsMinOracles == 0 || totalOracles < _rewardsMinOracles) { + revert Errors.InvalidOracles(); + } + rewardsMinOracles = _rewardsMinOracles; + emit RewardsMinOraclesUpdated(_rewardsMinOracles); } - // emit event - emit Harvested(msg.sender, params.rewardsRoot, totalAssetsDelta, unlockedMevDelta); - } - - /// @inheritdoc IKeeperRewards - function setRewardsMinOracles(uint256 _rewardsMinOracles) external override onlyOwner { - _setRewardsMinOracles(_rewardsMinOracles); - } - - /** - * @dev Internal function for updating rewardsMinOracles - * @param _rewardsMinOracles The new value of rewardsMinOracles - */ - function _setRewardsMinOracles(uint256 _rewardsMinOracles) private { - if (_rewardsMinOracles == 0 || totalOracles < _rewardsMinOracles) { - revert Errors.InvalidOracles(); + /** + * @dev Collateralize Vault so that it must be harvested in future reward updates + * @param vault The address of the Vault + */ + function _collateralize(address vault) internal { + // vault is already collateralized + if (rewards[vault].nonce != 0) return; + rewards[vault] = Reward({nonce: rewardsNonce, assets: 0}); } - rewardsMinOracles = _rewardsMinOracles; - emit RewardsMinOraclesUpdated(_rewardsMinOracles); - } - - /** - * @dev Collateralize Vault so that it must be harvested in future reward updates - * @param vault The address of the Vault - */ - function _collateralize(address vault) internal { - // vault is already collateralized - if (rewards[vault].nonce != 0) return; - rewards[vault] = Reward({nonce: rewardsNonce, assets: 0}); - } } diff --git a/contracts/keeper/KeeperValidators.sol b/contracts/keeper/KeeperValidators.sol index 17b16a02..d0279593 100644 --- a/contracts/keeper/KeeperValidators.sol +++ b/contracts/keeper/KeeperValidators.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; -import {IKeeperValidators} from '../interfaces/IKeeperValidators.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {KeeperOracles} from './KeeperOracles.sol'; -import {KeeperRewards} from './KeeperRewards.sol'; +import {IValidatorsRegistry} from "../interfaces/IValidatorsRegistry.sol"; +import {IKeeperValidators} from "../interfaces/IKeeperValidators.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {KeeperOracles} from "./KeeperOracles.sol"; +import {KeeperRewards} from "./KeeperRewards.sol"; /** * @title KeeperValidators @@ -14,115 +14,106 @@ import {KeeperRewards} from './KeeperRewards.sol'; * @notice Defines the functionality for approving validators' registrations and updating exit signatures */ abstract contract KeeperValidators is KeeperOracles, KeeperRewards, IKeeperValidators { - bytes32 private constant _registerValidatorsTypeHash = - keccak256( - 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' + bytes32 private constant _registerValidatorsTypeHash = keccak256( + "KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)" ); - bytes32 private constant _updateExitSigTypeHash = - keccak256( - 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' - ); - - IValidatorsRegistry private immutable _validatorsRegistry; + bytes32 private constant _updateExitSigTypeHash = + keccak256("KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)"); - /// @inheritdoc IKeeperValidators - mapping(address => uint256) public override exitSignaturesNonces; + IValidatorsRegistry private immutable _validatorsRegistry; - /// @inheritdoc IKeeperValidators - uint256 public override validatorsMinOracles; + /// @inheritdoc IKeeperValidators + mapping(address => uint256) public override exitSignaturesNonces; - /** - * @dev Constructor - * @param validatorsRegistry The address of the beacon chain validators registry contract - */ - constructor(IValidatorsRegistry validatorsRegistry) { - _validatorsRegistry = validatorsRegistry; - } + /// @inheritdoc IKeeperValidators + uint256 public override validatorsMinOracles; - /// @inheritdoc IKeeperValidators - function setValidatorsMinOracles(uint256 _validatorsMinOracles) external override onlyOwner { - _setValidatorsMinOracles(_validatorsMinOracles); - } - - /// @inheritdoc IKeeperValidators - function approveValidators(ApprovalParams calldata params) external override { - if (params.deadline < block.timestamp) revert Errors.DeadlineExpired(); + /** + * @dev Constructor + * @param validatorsRegistry The address of the beacon chain validators registry contract + */ + constructor(IValidatorsRegistry validatorsRegistry) { + _validatorsRegistry = validatorsRegistry; + } - // verify oracles approved registration for the current validators registry contract state - if (_validatorsRegistry.get_deposit_root() != params.validatorsRegistryRoot) { - revert Errors.InvalidValidatorsRegistryRoot(); + /// @inheritdoc IKeeperValidators + function setValidatorsMinOracles(uint256 _validatorsMinOracles) external override onlyOwner { + _setValidatorsMinOracles(_validatorsMinOracles); } - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); - - // verify oracles approved registration - _verifySignatures( - validatorsMinOracles, - keccak256( - abi.encode( - _registerValidatorsTypeHash, - params.validatorsRegistryRoot, - msg.sender, - keccak256(params.validators), - keccak256(bytes(params.exitSignaturesIpfsHash)), - params.deadline - ) - ), - params.signatures - ); - _collateralize(msg.sender); - - emit ValidatorsApproval(msg.sender, params.exitSignaturesIpfsHash); - } - - /// @inheritdoc IKeeperValidators - function updateExitSignatures( - address vault, - uint256 deadline, - string calldata exitSignaturesIpfsHash, - bytes calldata oraclesSignatures - ) external override { - if (!(_vaultsRegistry.vaults(vault) && isCollateralized(vault))) revert Errors.InvalidVault(); - if (deadline < block.timestamp) revert Errors.DeadlineExpired(); - - // SLOAD to memory - uint256 nonce = exitSignaturesNonces[vault]; - - // verify oracles approved signatures update - _verifySignatures( - validatorsMinOracles, - keccak256( - abi.encode( - _updateExitSigTypeHash, - vault, - keccak256(bytes(exitSignaturesIpfsHash)), - nonce, - deadline - ) - ), - oraclesSignatures - ); + /// @inheritdoc IKeeperValidators + function approveValidators(ApprovalParams calldata params) external override { + if (params.deadline < block.timestamp) revert Errors.DeadlineExpired(); + + // verify oracles approved registration for the current validators registry contract state + if (_validatorsRegistry.get_deposit_root() != params.validatorsRegistryRoot) { + revert Errors.InvalidValidatorsRegistryRoot(); + } + if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); + + // verify oracles approved registration + _verifySignatures( + validatorsMinOracles, + keccak256( + abi.encode( + _registerValidatorsTypeHash, + params.validatorsRegistryRoot, + msg.sender, + keccak256(params.validators), + keccak256(bytes(params.exitSignaturesIpfsHash)), + params.deadline + ) + ), + params.signatures + ); + + _collateralize(msg.sender); + + emit ValidatorsApproval(msg.sender, params.exitSignaturesIpfsHash); + } - // update state - unchecked { - // cannot realistically overflow - exitSignaturesNonces[vault] = nonce + 1; + /// @inheritdoc IKeeperValidators + function updateExitSignatures( + address vault, + uint256 deadline, + string calldata exitSignaturesIpfsHash, + bytes calldata oraclesSignatures + ) external override { + if (!(_vaultsRegistry.vaults(vault) && isCollateralized(vault))) revert Errors.InvalidVault(); + if (deadline < block.timestamp) revert Errors.DeadlineExpired(); + + // SLOAD to memory + uint256 nonce = exitSignaturesNonces[vault]; + + // verify oracles approved signatures update + _verifySignatures( + validatorsMinOracles, + keccak256( + abi.encode(_updateExitSigTypeHash, vault, keccak256(bytes(exitSignaturesIpfsHash)), nonce, deadline) + ), + oraclesSignatures + ); + + // update state + unchecked { + // cannot realistically overflow + exitSignaturesNonces[vault] = nonce + 1; + } + + // emit event + emit ExitSignaturesUpdated(msg.sender, vault, nonce, exitSignaturesIpfsHash); } - // emit event - emit ExitSignaturesUpdated(msg.sender, vault, nonce, exitSignaturesIpfsHash); - } - - /** - * @dev Internal function to set the minimum number of oracles required to approve validators - * @param _validatorsMinOracles The new minimum number of oracles required to approve validators - */ - function _setValidatorsMinOracles(uint256 _validatorsMinOracles) private { - if (_validatorsMinOracles == 0 || totalOracles < _validatorsMinOracles) { - revert Errors.InvalidOracles(); + /** + * @dev Internal function to set the minimum number of oracles required to approve validators + * @param _validatorsMinOracles The new minimum number of oracles required to approve validators + */ + function _setValidatorsMinOracles(uint256 _validatorsMinOracles) private { + if (_validatorsMinOracles == 0 || totalOracles < _validatorsMinOracles) { + revert Errors.InvalidOracles(); + } + validatorsMinOracles = _validatorsMinOracles; + emit ValidatorsMinOraclesUpdated(_validatorsMinOracles); } - validatorsMinOracles = _validatorsMinOracles; - emit ValidatorsMinOraclesUpdated(_validatorsMinOracles); - } } diff --git a/contracts/libraries/EIP712Utils.sol b/contracts/libraries/EIP712Utils.sol index 2454a8c1..6ac461c5 100644 --- a/contracts/libraries/EIP712Utils.sol +++ b/contracts/libraries/EIP712Utils.sol @@ -8,28 +8,22 @@ pragma solidity ^0.8.22; * @notice Includes functionality for calculating EIP712 hashes */ library EIP712Utils { - /** - * @notice Computes the hash of the EIP712 typed data - * @dev This function is used to compute the hash of the EIP712 typed data - * @param name The name of the domain - * @param verifyingContract The address of the verifying contract - * @return The hash of the EIP712 typed data - */ - function computeDomainSeparator( - string memory name, - address verifyingContract - ) external view returns (bytes32) { - return - keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes(name)), - keccak256('1'), - block.chainid, - verifyingContract - ) - ); - } + /** + * @notice Computes the hash of the EIP712 typed data + * @dev This function is used to compute the hash of the EIP712 typed data + * @param name The name of the domain + * @param verifyingContract The address of the verifying contract + * @return The hash of the EIP712 typed data + */ + function computeDomainSeparator(string memory name, address verifyingContract) external view returns (bytes32) { + return keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes(name)), + keccak256("1"), + block.chainid, + verifyingContract + ) + ); + } } diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index 0883a43b..ac8bf284 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -8,48 +8,48 @@ pragma solidity ^0.8.22; * @notice Contains all the custom errors */ library Errors { - error AccessDenied(); - error InvalidShares(); - error InvalidAssets(); - error ZeroAddress(); - error CapacityExceeded(); - error InvalidCapacity(); - error InvalidSecurityDeposit(); - error InvalidFeeRecipient(); - error InvalidFeePercent(); - error NotHarvested(); - error NotCollateralized(); - error InvalidProof(); - error LowLtv(); - error InvalidPosition(); - error InvalidHealthFactor(); - error InvalidReceivedAssets(); - error InvalidTokenMeta(); - error UpgradeFailed(); - error InvalidValidators(); - error DeadlineExpired(); - error PermitInvalidSigner(); - error InvalidValidatorsRegistryRoot(); - error InvalidVault(); - error AlreadyAdded(); - error AlreadyRemoved(); - error InvalidOracles(); - error NotEnoughSignatures(); - error InvalidOracle(); - error TooEarlyUpdate(); - error InvalidAvgRewardPerSecond(); - error InvalidRewardsRoot(); - error HarvestFailed(); - error LiquidationDisabled(); - error InvalidLiqThresholdPercent(); - error InvalidLiqBonusPercent(); - error InvalidLtvPercent(); - error InvalidCheckpointIndex(); - error InvalidCheckpointValue(); - error MaxOraclesExceeded(); - error ExitRequestNotProcessed(); - error ValueNotChanged(); - error FlashLoanFailed(); - error CannotTopUpV1Validators(); - error InvalidSignatures(); + error AccessDenied(); + error InvalidShares(); + error InvalidAssets(); + error ZeroAddress(); + error CapacityExceeded(); + error InvalidCapacity(); + error InvalidSecurityDeposit(); + error InvalidFeeRecipient(); + error InvalidFeePercent(); + error NotHarvested(); + error NotCollateralized(); + error InvalidProof(); + error LowLtv(); + error InvalidPosition(); + error InvalidHealthFactor(); + error InvalidReceivedAssets(); + error InvalidTokenMeta(); + error UpgradeFailed(); + error InvalidValidators(); + error DeadlineExpired(); + error PermitInvalidSigner(); + error InvalidValidatorsRegistryRoot(); + error InvalidVault(); + error AlreadyAdded(); + error AlreadyRemoved(); + error InvalidOracles(); + error NotEnoughSignatures(); + error InvalidOracle(); + error TooEarlyUpdate(); + error InvalidAvgRewardPerSecond(); + error InvalidRewardsRoot(); + error HarvestFailed(); + error LiquidationDisabled(); + error InvalidLiqThresholdPercent(); + error InvalidLiqBonusPercent(); + error InvalidLtvPercent(); + error InvalidCheckpointIndex(); + error InvalidCheckpointValue(); + error MaxOraclesExceeded(); + error ExitRequestNotProcessed(); + error ValueNotChanged(); + error FlashLoanFailed(); + error CannotTopUpV1Validators(); + error InvalidSignatures(); } diff --git a/contracts/libraries/ExitQueue.sol b/contracts/libraries/ExitQueue.sol index 0a55f0b6..2c585551 100644 --- a/contracts/libraries/ExitQueue.sol +++ b/contracts/libraries/ExitQueue.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Errors} from './Errors.sol'; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Errors} from "./Errors.sol"; /** * @title ExitQueue @@ -12,174 +12,166 @@ import {Errors} from './Errors.sol'; * @notice ExitQueue represent checkpoints of burned shares and exited assets */ library ExitQueue { - /** - * @notice A struct containing checkpoint data - * @param totalTickets The cumulative number of tickets (shares) exited - * @param exitedAssets The number of assets that exited in this checkpoint - */ - struct Checkpoint { - uint160 totalTickets; - uint96 exitedAssets; - } - - /** - * @notice A struct containing the history of checkpoints data - * @param checkpoints An array of checkpoints - */ - struct History { - Checkpoint[] checkpoints; - } - - /** - * @notice Get the latest checkpoint total tickets - * @param self An array containing checkpoints - * @return The current total tickets or zero if there are no checkpoints - */ - function getLatestTotalTickets(History storage self) internal view returns (uint256) { - uint256 pos = self.checkpoints.length; - unchecked { - // cannot underflow as subtraction happens in case pos > 0 - return pos == 0 ? 0 : _unsafeAccess(self.checkpoints, pos - 1).totalTickets; + /** + * @notice A struct containing checkpoint data + * @param totalTickets The cumulative number of tickets (shares) exited + * @param exitedAssets The number of assets that exited in this checkpoint + */ + struct Checkpoint { + uint160 totalTickets; + uint96 exitedAssets; } - } - - /** - * @notice Get checkpoint index for the burned shares - * @param self An array containing checkpoints - * @param positionTicket The position ticket to search the closest checkpoint for - * @return The checkpoint index or the length of checkpoints array in case there is no such - */ - function getCheckpointIndex( - History storage self, - uint256 positionTicket - ) external view returns (uint256) { - uint256 high = self.checkpoints.length; - uint256 low; - while (low < high) { - uint256 mid = Math.average(low, high); - if (_unsafeAccess(self.checkpoints, mid).totalTickets > positionTicket) { - high = mid; - } else { + + /** + * @notice A struct containing the history of checkpoints data + * @param checkpoints An array of checkpoints + */ + struct History { + Checkpoint[] checkpoints; + } + + /** + * @notice Get the latest checkpoint total tickets + * @param self An array containing checkpoints + * @return The current total tickets or zero if there are no checkpoints + */ + function getLatestTotalTickets(History storage self) internal view returns (uint256) { + uint256 pos = self.checkpoints.length; unchecked { - // cannot underflow as mid < high - low = mid + 1; + // cannot underflow as subtraction happens in case pos > 0 + return pos == 0 ? 0 : _unsafeAccess(self.checkpoints, pos - 1).totalTickets; } - } - } - return high; - } - - /** - * @notice Calculates burned shares and exited assets - * @param self An array containing checkpoints - * @param checkpointIdx The index of the checkpoint to start calculating from - * @param positionTicket The position ticket to start calculating exited assets from - * @param positionShares The number of shares to calculate assets for - * @return burnedShares The number of shares burned - * @return exitedAssets The number of assets exited - */ - function calculateExitedAssets( - History storage self, - uint256 checkpointIdx, - uint256 positionTicket, - uint256 positionShares - ) external view returns (uint256 burnedShares, uint256 exitedAssets) { - uint256 length = self.checkpoints.length; - // there are no exited assets for such checkpoint index or no shares to burn - if (checkpointIdx >= length || positionShares == 0) return (0, 0); - - // previous total tickets for calculating how much shares were burned for the period - uint256 prevTotalTickets; - unchecked { - // cannot underflow as subtraction happens in case checkpointIdx > 0 - prevTotalTickets = checkpointIdx == 0 - ? 0 - : _unsafeAccess(self.checkpoints, checkpointIdx - 1).totalTickets; } - // current total tickets for calculating assets per burned share - // can be used with _unsafeAccess as checkpointIdx < length - Checkpoint memory checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx); - uint256 currTotalTickets = checkpoint.totalTickets; - uint256 checkpointAssets = checkpoint.exitedAssets; - // check whether position ticket is in [prevTotalTickets, currTotalTickets) range - if (positionTicket < prevTotalTickets || currTotalTickets <= positionTicket) { - revert Errors.InvalidCheckpointIndex(); + /** + * @notice Get checkpoint index for the burned shares + * @param self An array containing checkpoints + * @param positionTicket The position ticket to search the closest checkpoint for + * @return The checkpoint index or the length of checkpoints array in case there is no such + */ + function getCheckpointIndex(History storage self, uint256 positionTicket) external view returns (uint256) { + uint256 high = self.checkpoints.length; + uint256 low; + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self.checkpoints, mid).totalTickets > positionTicket) { + high = mid; + } else { + unchecked { + // cannot underflow as mid < high + low = mid + 1; + } + } + } + return high; } - if (currTotalTickets > 1 && checkpointAssets == 0 && checkpointIdx + 1 < length) { - // only single checkpoint created during V2 -> V3 migration can pass this if - checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx + 1); - uint256 totalShares = checkpoint.totalTickets - currTotalTickets; - return (positionShares, Math.mulDiv(positionShares, checkpoint.exitedAssets, totalShares)); - } + /** + * @notice Calculates burned shares and exited assets + * @param self An array containing checkpoints + * @param checkpointIdx The index of the checkpoint to start calculating from + * @param positionTicket The position ticket to start calculating exited assets from + * @param positionShares The number of shares to calculate assets for + * @return burnedShares The number of shares burned + * @return exitedAssets The number of assets exited + */ + function calculateExitedAssets( + History storage self, + uint256 checkpointIdx, + uint256 positionTicket, + uint256 positionShares + ) external view returns (uint256 burnedShares, uint256 exitedAssets) { + uint256 length = self.checkpoints.length; + // there are no exited assets for such checkpoint index or no shares to burn + if (checkpointIdx >= length || positionShares == 0) return (0, 0); + + // previous total tickets for calculating how much shares were burned for the period + uint256 prevTotalTickets; + unchecked { + // cannot underflow as subtraction happens in case checkpointIdx > 0 + prevTotalTickets = checkpointIdx == 0 ? 0 : _unsafeAccess(self.checkpoints, checkpointIdx - 1).totalTickets; + } + + // current total tickets for calculating assets per burned share + // can be used with _unsafeAccess as checkpointIdx < length + Checkpoint memory checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx); + uint256 currTotalTickets = checkpoint.totalTickets; + uint256 checkpointAssets = checkpoint.exitedAssets; + // check whether position ticket is in [prevTotalTickets, currTotalTickets) range + if (positionTicket < prevTotalTickets || currTotalTickets <= positionTicket) { + revert Errors.InvalidCheckpointIndex(); + } + + if (currTotalTickets > 1 && checkpointAssets == 0 && checkpointIdx + 1 < length) { + // only single checkpoint created during V2 -> V3 migration can pass this if + checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx + 1); + uint256 totalShares = checkpoint.totalTickets - currTotalTickets; + return (positionShares, Math.mulDiv(positionShares, checkpoint.exitedAssets, totalShares)); + } - // calculate amount of available shares that will be updated while iterating over checkpoints - uint256 availableShares; - unchecked { - // cannot underflow as positionTicket < currTotalTickets - availableShares = currTotalTickets - positionTicket; + // calculate amount of available shares that will be updated while iterating over checkpoints + uint256 availableShares; + unchecked { + // cannot underflow as positionTicket < currTotalTickets + availableShares = currTotalTickets - positionTicket; + } + + // accumulate assets until the number of required shares is collected + uint256 checkpointShares; + uint256 sharesDelta; + while (true) { + unchecked { + // cannot underflow as prevTotalTickets <= positionTicket + checkpointShares = currTotalTickets - prevTotalTickets; + // cannot underflow as positionShares > burnedShares while in the loop + sharesDelta = Math.min(availableShares, positionShares - burnedShares); + + // cannot overflow as it is capped with underlying asset total supply + burnedShares += sharesDelta; + exitedAssets += Math.mulDiv(sharesDelta, checkpointAssets, checkpointShares); + + // cannot overflow as checkpoints are created max once per day + checkpointIdx++; + } + + // stop when required shares collected or reached end of checkpoints list + if (positionShares <= burnedShares || checkpointIdx >= length) { + return (burnedShares, exitedAssets); + } + + // take next checkpoint + prevTotalTickets = currTotalTickets; + // can use _unsafeAccess as checkpointIdx < length is checked above + checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx); + currTotalTickets = checkpoint.totalTickets; + checkpointAssets = checkpoint.exitedAssets; + + unchecked { + // cannot underflow as every next checkpoint total tickets is larger than previous + availableShares = currTotalTickets - prevTotalTickets; + } + } } - // accumulate assets until the number of required shares is collected - uint256 checkpointShares; - uint256 sharesDelta; - while (true) { - unchecked { - // cannot underflow as prevTotalTickets <= positionTicket - checkpointShares = currTotalTickets - prevTotalTickets; - // cannot underflow as positionShares > burnedShares while in the loop - sharesDelta = Math.min(availableShares, positionShares - burnedShares); - - // cannot overflow as it is capped with underlying asset total supply - burnedShares += sharesDelta; - exitedAssets += Math.mulDiv(sharesDelta, checkpointAssets, checkpointShares); - - // cannot overflow as checkpoints are created max once per day - checkpointIdx++; - } - - // stop when required shares collected or reached end of checkpoints list - if (positionShares <= burnedShares || checkpointIdx >= length) { - return (burnedShares, exitedAssets); - } - - // take next checkpoint - prevTotalTickets = currTotalTickets; - // can use _unsafeAccess as checkpointIdx < length is checked above - checkpoint = _unsafeAccess(self.checkpoints, checkpointIdx); - currTotalTickets = checkpoint.totalTickets; - checkpointAssets = checkpoint.exitedAssets; - - unchecked { - // cannot underflow as every next checkpoint total tickets is larger than previous - availableShares = currTotalTickets - prevTotalTickets; - } + /** + * @notice Pushes a new checkpoint onto a History + * @param self An array containing checkpoints + * @param shares The number of shares to add to the latest checkpoint + * @param assets The number of assets that were exited for this checkpoint + */ + function push(History storage self, uint256 shares, uint256 assets) internal { + if (shares == 0) revert Errors.InvalidCheckpointValue(); + Checkpoint memory checkpoint = Checkpoint({ + totalTickets: SafeCast.toUint160(getLatestTotalTickets(self) + shares), + exitedAssets: SafeCast.toUint96(assets) + }); + self.checkpoints.push(checkpoint); } - } - - /** - * @notice Pushes a new checkpoint onto a History - * @param self An array containing checkpoints - * @param shares The number of shares to add to the latest checkpoint - * @param assets The number of assets that were exited for this checkpoint - */ - function push(History storage self, uint256 shares, uint256 assets) internal { - if (shares == 0) revert Errors.InvalidCheckpointValue(); - Checkpoint memory checkpoint = Checkpoint({ - totalTickets: SafeCast.toUint160(getLatestTotalTickets(self) + shares), - exitedAssets: SafeCast.toUint96(assets) - }); - self.checkpoints.push(checkpoint); - } - - function _unsafeAccess( - Checkpoint[] storage self, - uint256 pos - ) private pure returns (Checkpoint storage result) { - assembly { - mstore(0, self.slot) - result.slot := add(keccak256(0, 0x20), pos) + + function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } } - } } diff --git a/contracts/libraries/OsTokenUtils.sol b/contracts/libraries/OsTokenUtils.sol index fa4dbe0b..8d65588e 100644 --- a/contracts/libraries/OsTokenUtils.sol +++ b/contracts/libraries/OsTokenUtils.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IOsTokenConfig} from '../interfaces/IOsTokenConfig.sol'; -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; -import {Errors} from './Errors.sol'; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {IOsTokenConfig} from "../interfaces/IOsTokenConfig.sol"; +import {IOsTokenVaultController} from "../interfaces/IOsTokenVaultController.sol"; +import {Errors} from "./Errors.sol"; /** * @title OsTokenUtils @@ -13,76 +13,71 @@ import {Errors} from './Errors.sol'; * @notice Includes functionality for handling osToken redemptions */ library OsTokenUtils { - uint256 private constant _wad = 1e18; - uint256 private constant _hfLiqThreshold = 1e18; - uint256 private constant _maxPercent = 1e18; - uint256 private constant _disabledLiqThreshold = type(uint64).max; + uint256 private constant _wad = 1e18; + uint256 private constant _hfLiqThreshold = 1e18; + uint256 private constant _maxPercent = 1e18; + uint256 private constant _disabledLiqThreshold = type(uint64).max; - /** - * @dev Struct for storing redemption data - * @param mintedAssets The amount of minted assets - * @param depositedAssets The amount of deposited assets - * @param redeemedOsTokenShares The amount of redeemed osToken shares - * @param availableAssets The amount of available assets - * @param isLiquidation Whether the redemption is a liquidation - */ - struct RedemptionData { - uint256 mintedAssets; - uint256 depositedAssets; - uint256 redeemedOsTokenShares; - uint256 availableAssets; - bool isLiquidation; - } - - /** - * @dev Calculates the amount of received assets during osToken redemption - * @param osTokenConfig The address of the osToken config contract - * @param osTokenVaultController The address of the osToken vault controller contract - * @param data The redemption data - * @return receivedAssets The amount of received assets - */ - function calculateReceivedAssets( - IOsTokenConfig osTokenConfig, - IOsTokenVaultController osTokenVaultController, - RedemptionData memory data - ) external view returns (uint256 receivedAssets) { - // SLOAD to memory - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(this)); - if (data.isLiquidation && config.liqThresholdPercent == _disabledLiqThreshold) { - revert Errors.LiquidationDisabled(); + /** + * @dev Struct for storing redemption data + * @param mintedAssets The amount of minted assets + * @param depositedAssets The amount of deposited assets + * @param redeemedOsTokenShares The amount of redeemed osToken shares + * @param availableAssets The amount of available assets + * @param isLiquidation Whether the redemption is a liquidation + */ + struct RedemptionData { + uint256 mintedAssets; + uint256 depositedAssets; + uint256 redeemedOsTokenShares; + uint256 availableAssets; + bool isLiquidation; } - // calculate received assets - if (data.isLiquidation) { - receivedAssets = Math.mulDiv( - osTokenVaultController.convertToAssets(data.redeemedOsTokenShares), - config.liqBonusPercent, - _maxPercent - ); - } else { - receivedAssets = osTokenVaultController.convertToAssets(data.redeemedOsTokenShares); - } + /** + * @dev Calculates the amount of received assets during osToken redemption + * @param osTokenConfig The address of the osToken config contract + * @param osTokenVaultController The address of the osToken vault controller contract + * @param data The redemption data + * @return receivedAssets The amount of received assets + */ + function calculateReceivedAssets( + IOsTokenConfig osTokenConfig, + IOsTokenVaultController osTokenVaultController, + RedemptionData memory data + ) external view returns (uint256 receivedAssets) { + // SLOAD to memory + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(this)); + if (data.isLiquidation && config.liqThresholdPercent == _disabledLiqThreshold) { + revert Errors.LiquidationDisabled(); + } + + // calculate received assets + if (data.isLiquidation) { + receivedAssets = Math.mulDiv( + osTokenVaultController.convertToAssets(data.redeemedOsTokenShares), config.liqBonusPercent, _maxPercent + ); + } else { + receivedAssets = osTokenVaultController.convertToAssets(data.redeemedOsTokenShares); + } - { - // check whether received assets are valid - if (receivedAssets > data.depositedAssets || receivedAssets > data.availableAssets) { - revert Errors.InvalidReceivedAssets(); - } + { + // check whether received assets are valid + if (receivedAssets > data.depositedAssets || receivedAssets > data.availableAssets) { + revert Errors.InvalidReceivedAssets(); + } - if (!data.isLiquidation) { - return receivedAssets; - } + if (!data.isLiquidation) { + return receivedAssets; + } - // check health factor violation in case of liquidation - if ( - Math.mulDiv( - data.depositedAssets * _wad, - config.liqThresholdPercent, - data.mintedAssets * _maxPercent - ) >= _hfLiqThreshold - ) { - revert Errors.InvalidHealthFactor(); - } + // check health factor violation in case of liquidation + if ( + Math.mulDiv(data.depositedAssets * _wad, config.liqThresholdPercent, data.mintedAssets * _maxPercent) + >= _hfLiqThreshold + ) { + revert Errors.InvalidHealthFactor(); + } + } } - } } diff --git a/contracts/libraries/ValidatorUtils.sol b/contracts/libraries/ValidatorUtils.sol index 90c615af..ad5c3c1d 100644 --- a/contracts/libraries/ValidatorUtils.sol +++ b/contracts/libraries/ValidatorUtils.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; -import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; -import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; -import {Errors} from './Errors.sol'; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; +import {IVaultValidators} from "../interfaces/IVaultValidators.sol"; +import {Errors} from "./Errors.sol"; /** * @title ValidatorUtils @@ -14,310 +14,293 @@ import {Errors} from './Errors.sol'; * @notice Includes functionality for managing the validators */ library ValidatorUtils { - bytes32 private constant _validatorsManagerTypeHash = - keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'); - uint256 private constant _validatorV1DepositLength = 176; - uint256 private constant _validatorV2DepositLength = 184; - uint256 private constant _validatorWithdrawalLength = 56; - uint256 private constant _validatorConsolidationLength = 96; - uint256 private constant _validatorMinEffectiveBalance = 32 ether; - uint256 private constant _validatorMaxEffectiveBalance = 2048 ether; - - /* - * @dev Struct to hold the validator registration data - * @param publicKey The public key of the validator - * @param signature The signature of the validator - * @param withdrawalCredentials The withdrawal credentials of the validator - * @param depositDataRoot The deposit data root of the validator - * @param depositAmount The deposit amount of the validator - */ - struct ValidatorDeposit { - bytes publicKey; - bytes signature; - bytes withdrawalCredentials; - bytes32 depositDataRoot; - uint256 depositAmount; - } - - /** - * @dev Function to check if the validator signature is valid - * @param nonce The nonce of the validator - * @param domainSeparator The domain separator of the validator - * @param validatorsManager The address of the validators manager - * @param validators The validators data - * @param signature The signature of the validator - * @return Whether the signature is valid - */ - function isValidManagerSignature( - bytes32 nonce, - bytes32 domainSeparator, - address validatorsManager, - bytes calldata validators, - bytes calldata signature - ) external view returns (bool) { - bytes32 messageHash = MessageHashUtils.toTypedDataHash( - domainSeparator, - keccak256(abi.encode(_validatorsManagerTypeHash, nonce, keccak256(validators))) - ); - return SignatureChecker.isValidSignatureNow(validatorsManager, messageHash, signature); - } - - /** - * @dev Function to get the validator registration data - * @param validator The validator data - * @param isV1Validator Whether the validator is a V1 validator - * @return validatorDeposit The validator registration data - */ - function getValidatorDeposit( - bytes calldata validator, - bool isV1Validator - ) internal view returns (ValidatorDeposit memory validatorDeposit) { - validatorDeposit.publicKey = validator[:48]; - validatorDeposit.signature = validator[48:144]; - validatorDeposit.depositDataRoot = bytes32(validator[144:176]); - - // get the deposit amount and withdrawal credentials prefix - bytes1 withdrawalCredsPrefix; - if (isV1Validator) { - withdrawalCredsPrefix = 0x01; - validatorDeposit.depositAmount = _validatorMinEffectiveBalance; - } else { - withdrawalCredsPrefix = 0x02; - // extract amount from data, convert gwei to wei by multiplying by 1 gwei - validatorDeposit.depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei); - } - validatorDeposit.withdrawalCredentials = abi.encodePacked( - withdrawalCredsPrefix, - bytes11(0x0), - address(this) - ); - } - - /** - * @dev Function to get the type of validators - * @param validatorsLength The length of the validators data - * @return isV1Validators Whether the validators are V1 validators - */ - function getIsV1Validators(uint256 validatorsLength) internal pure returns (bool) { - bool isV1Validators = validatorsLength % _validatorV1DepositLength == 0; - bool isV2Validators = validatorsLength % _validatorV2DepositLength == 0; - if ( - validatorsLength == 0 || - (isV1Validators && isV2Validators) || - (!isV1Validators && !isV2Validators) - ) { - revert Errors.InvalidValidators(); + bytes32 private constant _validatorsManagerTypeHash = + keccak256("VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)"); + uint256 private constant _validatorV1DepositLength = 176; + uint256 private constant _validatorV2DepositLength = 184; + uint256 private constant _validatorWithdrawalLength = 56; + uint256 private constant _validatorConsolidationLength = 96; + uint256 private constant _validatorMinEffectiveBalance = 32 ether; + uint256 private constant _validatorMaxEffectiveBalance = 2048 ether; + + /* + * @dev Struct to hold the validator registration data + * @param publicKey The public key of the validator + * @param signature The signature of the validator + * @param withdrawalCredentials The withdrawal credentials of the validator + * @param depositDataRoot The deposit data root of the validator + * @param depositAmount The deposit amount of the validator + */ + struct ValidatorDeposit { + bytes publicKey; + bytes signature; + bytes withdrawalCredentials; + bytes32 depositDataRoot; + uint256 depositAmount; } - return isV1Validators; - } - - /** - * @dev Function to get the validator registrations - * @param v2Validators The mapping of public key hashes to registration status - * @param validators The validators data - * @param isTopUp Whether the registration is a top-up - * @return validatorDeposits The array of validator registrations - */ - function getValidatorDeposits( - mapping(bytes32 publicKeyHash => bool isRegistered) storage v2Validators, - bytes calldata validators, - bool isTopUp - ) external returns (ValidatorDeposit[] memory validatorDeposits) { - // check validators length is valid - uint256 validatorsLength = validators.length; - bool isV1Validators = getIsV1Validators(validatorsLength); - - // top up is only allowed for V2 validators - if (isTopUp && isV1Validators) { - revert Errors.CannotTopUpV1Validators(); + /** + * @dev Function to check if the validator signature is valid + * @param nonce The nonce of the validator + * @param domainSeparator The domain separator of the validator + * @param validatorsManager The address of the validators manager + * @param validators The validators data + * @param signature The signature of the validator + * @return Whether the signature is valid + */ + function isValidManagerSignature( + bytes32 nonce, + bytes32 domainSeparator, + address validatorsManager, + bytes calldata validators, + bytes calldata signature + ) external view returns (bool) { + bytes32 messageHash = MessageHashUtils.toTypedDataHash( + domainSeparator, keccak256(abi.encode(_validatorsManagerTypeHash, nonce, keccak256(validators))) + ); + return SignatureChecker.isValidSignatureNow(validatorsManager, messageHash, signature); } - uint256 _validatorDepositLength = ( - isV1Validators ? _validatorV1DepositLength : _validatorV2DepositLength - ); - uint256 validatorsCount = validatorsLength / _validatorDepositLength; - - uint256 startIndex; - ValidatorDeposit memory valDeposit; - validatorDeposits = new ValidatorDeposit[](validatorsCount); - for (uint256 i = 0; i < validatorsCount; ) { - valDeposit = getValidatorDeposit( - validators[startIndex:startIndex + _validatorDepositLength], - isV1Validators - ); - - if (isTopUp) { - // check whether validator is tracked in case of the top-up - if (!v2Validators[keccak256(valDeposit.publicKey)]) { - revert Errors.InvalidValidators(); - } - // add registration data to the array - validatorDeposits[i] = valDeposit; - emit IVaultValidators.ValidatorFunded(valDeposit.publicKey, valDeposit.depositAmount); - unchecked { - // cannot realistically overflow - ++i; - startIndex += _validatorDepositLength; + /** + * @dev Function to get the validator registration data + * @param validator The validator data + * @param isV1Validator Whether the validator is a V1 validator + * @return validatorDeposit The validator registration data + */ + function getValidatorDeposit(bytes calldata validator, bool isV1Validator) + internal + view + returns (ValidatorDeposit memory validatorDeposit) + { + validatorDeposit.publicKey = validator[:48]; + validatorDeposit.signature = validator[48:144]; + validatorDeposit.depositDataRoot = bytes32(validator[144:176]); + + // get the deposit amount and withdrawal credentials prefix + bytes1 withdrawalCredsPrefix; + if (isV1Validator) { + withdrawalCredsPrefix = 0x01; + validatorDeposit.depositAmount = _validatorMinEffectiveBalance; + } else { + withdrawalCredsPrefix = 0x02; + // extract amount from data, convert gwei to wei by multiplying by 1 gwei + validatorDeposit.depositAmount = (uint256(uint64(bytes8(validator[176:184]))) * 1 gwei); } - continue; - } - - // check the registration amount - if ( - valDeposit.depositAmount > _validatorMaxEffectiveBalance || - valDeposit.depositAmount < _validatorMinEffectiveBalance - ) { - revert Errors.InvalidAssets(); - } - - // mark v2 validator public key as tracked - if (!isV1Validators) { - v2Validators[keccak256(valDeposit.publicKey)] = true; - emit IVaultValidators.V2ValidatorRegistered(valDeposit.publicKey, valDeposit.depositAmount); - } else { - emit IVaultValidators.ValidatorRegistered(valDeposit.publicKey); - } - - // add registration data to the array - validatorDeposits[i] = valDeposit; - - unchecked { - // cannot realistically overflow - ++i; - startIndex += _validatorDepositLength; - } - } - } - - /** - * @dev Function to withdraw the validators - * @param validators The validators data - * @param validatorsWithdrawals The address of the validators withdrawals contract - */ - function withdrawValidators(bytes calldata validators, address validatorsWithdrawals) external { - // check validators length is valid - uint256 validatorsCount = validators.length / _validatorWithdrawalLength; - unchecked { - if (validatorsCount == 0 || validators.length % _validatorWithdrawalLength != 0) { - revert Errors.InvalidValidators(); - } + validatorDeposit.withdrawalCredentials = abi.encodePacked(withdrawalCredsPrefix, bytes11(0x0), address(this)); } - uint256 feePaid; - uint256 withdrawnAmount; - uint256 totalFeeAssets = msg.value; - bytes calldata publicKey; - bytes calldata validator; - uint256 startIndex; - for (uint256 i = 0; i < validatorsCount; ) { - validator = validators[startIndex:startIndex + _validatorWithdrawalLength]; - publicKey = validator[:48]; - - // convert gwei to wei by multiplying by 1 gwei - withdrawnAmount = (uint256(uint64(bytes8(validator[48:56]))) * 1 gwei); - feePaid = uint256(bytes32(Address.functionStaticCall(validatorsWithdrawals, ''))); - - // submit validator withdrawal - Address.functionCallWithValue(validatorsWithdrawals, validator, feePaid); - totalFeeAssets -= feePaid; - emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, withdrawnAmount, feePaid); - - unchecked { - // cannot realistically overflow - ++i; - startIndex += _validatorWithdrawalLength; - } + /** + * @dev Function to get the type of validators + * @param validatorsLength The length of the validators data + * @return isV1Validators Whether the validators are V1 validators + */ + function getIsV1Validators(uint256 validatorsLength) internal pure returns (bool) { + bool isV1Validators = validatorsLength % _validatorV1DepositLength == 0; + bool isV2Validators = validatorsLength % _validatorV2DepositLength == 0; + if (validatorsLength == 0 || (isV1Validators && isV2Validators) || (!isV1Validators && !isV2Validators)) { + revert Errors.InvalidValidators(); + } + + return isV1Validators; } - // send the remaining assets to the caller - if (totalFeeAssets > 0) { - Address.sendValue(payable(msg.sender), totalFeeAssets); + /** + * @dev Function to get the validator registrations + * @param v2Validators The mapping of public key hashes to registration status + * @param validators The validators data + * @param isTopUp Whether the registration is a top-up + * @return validatorDeposits The array of validator registrations + */ + function getValidatorDeposits( + mapping(bytes32 publicKeyHash => bool isRegistered) storage v2Validators, + bytes calldata validators, + bool isTopUp + ) external returns (ValidatorDeposit[] memory validatorDeposits) { + // check validators length is valid + uint256 validatorsLength = validators.length; + bool isV1Validators = getIsV1Validators(validatorsLength); + + // top up is only allowed for V2 validators + if (isTopUp && isV1Validators) { + revert Errors.CannotTopUpV1Validators(); + } + + uint256 _validatorDepositLength = (isV1Validators ? _validatorV1DepositLength : _validatorV2DepositLength); + uint256 validatorsCount = validatorsLength / _validatorDepositLength; + + uint256 startIndex; + ValidatorDeposit memory valDeposit; + validatorDeposits = new ValidatorDeposit[](validatorsCount); + for (uint256 i = 0; i < validatorsCount;) { + valDeposit = + getValidatorDeposit(validators[startIndex:startIndex + _validatorDepositLength], isV1Validators); + + if (isTopUp) { + // check whether validator is tracked in case of the top-up + if (!v2Validators[keccak256(valDeposit.publicKey)]) { + revert Errors.InvalidValidators(); + } + // add registration data to the array + validatorDeposits[i] = valDeposit; + emit IVaultValidators.ValidatorFunded(valDeposit.publicKey, valDeposit.depositAmount); + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorDepositLength; + } + continue; + } + + // check the registration amount + if ( + valDeposit.depositAmount > _validatorMaxEffectiveBalance + || valDeposit.depositAmount < _validatorMinEffectiveBalance + ) { + revert Errors.InvalidAssets(); + } + + // mark v2 validator public key as tracked + if (!isV1Validators) { + v2Validators[keccak256(valDeposit.publicKey)] = true; + emit IVaultValidators.V2ValidatorRegistered(valDeposit.publicKey, valDeposit.depositAmount); + } else { + emit IVaultValidators.ValidatorRegistered(valDeposit.publicKey); + } + + // add registration data to the array + validatorDeposits[i] = valDeposit; + + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorDepositLength; + } + } } - } - - /** - * @dev Internal function for consolidating validators - * @param validator The validator data - * @param validatorsConsolidations The address of the validators consolidations contract - * @param fromPublicKey The public key of the validator that was consolidated - * @param toPublicKey The public key of the validator that was consolidated to - * @param feePaid The amount of fee that was paid - */ - function consolidateValidator( - bytes calldata validator, - address validatorsConsolidations - ) internal returns (bytes calldata fromPublicKey, bytes calldata toPublicKey, uint256 feePaid) { - fromPublicKey = validator[:48]; - toPublicKey = validator[48:96]; - feePaid = uint256(bytes32(Address.functionStaticCall(validatorsConsolidations, ''))); - - Address.functionCallWithValue(validatorsConsolidations, validator, feePaid); - } - - /** - * @dev Function to consolidate the validators - * @param v2Validators The mapping of public key hashes to registration status - * @param validators The validators data - * @param consolidationsApproved Whether the consolidations are approved - * @param validatorsConsolidations The address of the validators consolidations contract - */ - function consolidateValidators( - mapping(bytes32 publicKeyHash => bool isRegistered) storage v2Validators, - bytes calldata validators, - bool consolidationsApproved, - address validatorsConsolidations - ) external { - // Check validators length is valid - uint256 validatorsCount = validators.length / _validatorConsolidationLength; - unchecked { - if (validatorsCount == 0 || validators.length % _validatorConsolidationLength != 0) { - revert Errors.InvalidValidators(); - } + + /** + * @dev Function to withdraw the validators + * @param validators The validators data + * @param validatorsWithdrawals The address of the validators withdrawals contract + */ + function withdrawValidators(bytes calldata validators, address validatorsWithdrawals) external { + // check validators length is valid + uint256 validatorsCount = validators.length / _validatorWithdrawalLength; + unchecked { + if (validatorsCount == 0 || validators.length % _validatorWithdrawalLength != 0) { + revert Errors.InvalidValidators(); + } + } + + uint256 feePaid; + uint256 withdrawnAmount; + uint256 totalFeeAssets = msg.value; + bytes calldata publicKey; + bytes calldata validator; + uint256 startIndex; + for (uint256 i = 0; i < validatorsCount;) { + validator = validators[startIndex:startIndex + _validatorWithdrawalLength]; + publicKey = validator[:48]; + + // convert gwei to wei by multiplying by 1 gwei + withdrawnAmount = (uint256(uint64(bytes8(validator[48:56]))) * 1 gwei); + feePaid = uint256(bytes32(Address.functionStaticCall(validatorsWithdrawals, ""))); + + // submit validator withdrawal + Address.functionCallWithValue(validatorsWithdrawals, validator, feePaid); + totalFeeAssets -= feePaid; + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, withdrawnAmount, feePaid); + + unchecked { + // cannot realistically overflow + ++i; + startIndex += _validatorWithdrawalLength; + } + } + + // send the remaining assets to the caller + if (totalFeeAssets > 0) { + Address.sendValue(payable(msg.sender), totalFeeAssets); + } } - uint256 totalFeeAssets = msg.value; - - // Process each validator - bytes32 destPubKeyHash; - bytes calldata sourcePublicKey; - bytes calldata destPublicKey; - uint256 feePaid; - uint256 startIndex; - for (uint256 i = 0; i < validatorsCount; ) { - // consolidate validators - (sourcePublicKey, destPublicKey, feePaid) = consolidateValidator( - validators[startIndex:startIndex + _validatorConsolidationLength], - validatorsConsolidations - ); - - // check whether the destination public key is tracked or approved - destPubKeyHash = keccak256(destPublicKey); - if (consolidationsApproved) { - v2Validators[destPubKeyHash] = true; - } else if (!v2Validators[destPubKeyHash]) { - revert Errors.InvalidValidators(); - } - - // Update fees and emit event - unchecked { - // cannot realistically overflow - totalFeeAssets -= feePaid; - startIndex += _validatorConsolidationLength; - ++i; - } - - // emit event - emit IVaultValidators.ValidatorConsolidationSubmitted( - sourcePublicKey, - destPublicKey, - feePaid - ); + /** + * @dev Internal function for consolidating validators + * @param validator The validator data + * @param validatorsConsolidations The address of the validators consolidations contract + * @param fromPublicKey The public key of the validator that was consolidated + * @param toPublicKey The public key of the validator that was consolidated to + * @param feePaid The amount of fee that was paid + */ + function consolidateValidator(bytes calldata validator, address validatorsConsolidations) + internal + returns (bytes calldata fromPublicKey, bytes calldata toPublicKey, uint256 feePaid) + { + fromPublicKey = validator[:48]; + toPublicKey = validator[48:96]; + feePaid = uint256(bytes32(Address.functionStaticCall(validatorsConsolidations, ""))); + + Address.functionCallWithValue(validatorsConsolidations, validator, feePaid); } - // refund unused fees - if (totalFeeAssets > 0) { - Address.sendValue(payable(msg.sender), totalFeeAssets); + /** + * @dev Function to consolidate the validators + * @param v2Validators The mapping of public key hashes to registration status + * @param validators The validators data + * @param consolidationsApproved Whether the consolidations are approved + * @param validatorsConsolidations The address of the validators consolidations contract + */ + function consolidateValidators( + mapping(bytes32 publicKeyHash => bool isRegistered) storage v2Validators, + bytes calldata validators, + bool consolidationsApproved, + address validatorsConsolidations + ) external { + // Check validators length is valid + uint256 validatorsCount = validators.length / _validatorConsolidationLength; + unchecked { + if (validatorsCount == 0 || validators.length % _validatorConsolidationLength != 0) { + revert Errors.InvalidValidators(); + } + } + + uint256 totalFeeAssets = msg.value; + + // Process each validator + bytes32 destPubKeyHash; + bytes calldata sourcePublicKey; + bytes calldata destPublicKey; + uint256 feePaid; + uint256 startIndex; + for (uint256 i = 0; i < validatorsCount;) { + // consolidate validators + (sourcePublicKey, destPublicKey, feePaid) = consolidateValidator( + validators[startIndex:startIndex + _validatorConsolidationLength], validatorsConsolidations + ); + + // check whether the destination public key is tracked or approved + destPubKeyHash = keccak256(destPublicKey); + if (consolidationsApproved) { + v2Validators[destPubKeyHash] = true; + } else if (!v2Validators[destPubKeyHash]) { + revert Errors.InvalidValidators(); + } + + // Update fees and emit event + unchecked { + // cannot realistically overflow + totalFeeAssets -= feePaid; + startIndex += _validatorConsolidationLength; + ++i; + } + + // emit event + emit IVaultValidators.ValidatorConsolidationSubmitted(sourcePublicKey, destPublicKey, feePaid); + } + + // refund unused fees + if (totalFeeAssets > 0) { + Address.sendValue(payable(msg.sender), totalFeeAssets); + } } - } } diff --git a/contracts/misc/EthRewardSplitter.sol b/contracts/misc/EthRewardSplitter.sol index affd3502..6062aa47 100644 --- a/contracts/misc/EthRewardSplitter.sol +++ b/contracts/misc/EthRewardSplitter.sol @@ -2,34 +2,34 @@ pragma solidity ^0.8.22; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; -import {RewardSplitter} from './RewardSplitter.sol'; -import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import {RewardSplitter} from "./RewardSplitter.sol"; +import {IRewardSplitter} from "../interfaces/IRewardSplitter.sol"; /** * @title EthRewardSplitter * @author StakeWise - * @notice The EthRewardSplitter can be used on Ethereum networks - to split the rewards of the fee recipient of the vault based on configured shares + * @notice The EthRewardSplitter can be used on Ethereum networks + * to split the rewards of the fee recipient of the vault based on configured shares */ contract EthRewardSplitter is ReentrancyGuardUpgradeable, RewardSplitter { - /** - * @dev Constructor for EthRewardSplitter - */ - constructor() RewardSplitter() {} + /** + * @dev Constructor for EthRewardSplitter + */ + constructor() RewardSplitter() {} - /// Allows to claim rewards from the vault and receive them to the reward splitter address - receive() external payable {} + /// Allows to claim rewards from the vault and receive them to the reward splitter address + receive() external payable {} - /// @inheritdoc IRewardSplitter - function initialize(address _vault) external override initializer { - __ReentrancyGuard_init(); - __RewardSplitter_init(_vault); - } + /// @inheritdoc IRewardSplitter + function initialize(address _vault) external override initializer { + __ReentrancyGuard_init(); + __RewardSplitter_init(_vault); + } - /// @inheritdoc RewardSplitter - function _transferRewards(address shareholder, uint256 amount) internal override nonReentrant { - Address.sendValue(payable(shareholder), amount); - } + /// @inheritdoc RewardSplitter + function _transferRewards(address shareholder, uint256 amount) internal override nonReentrant { + Address.sendValue(payable(shareholder), amount); + } } diff --git a/contracts/misc/GnoDaiDistributor.sol b/contracts/misc/GnoDaiDistributor.sol index dd71d32f..196cdb87 100644 --- a/contracts/misc/GnoDaiDistributor.sol +++ b/contracts/misc/GnoDaiDistributor.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; -import {IGnoDaiDistributor} from '../interfaces/IGnoDaiDistributor.sol'; -import {IMerkleDistributor} from '../interfaces/IMerkleDistributor.sol'; -import {ISavingsXDaiAdapter} from '../interfaces/ISavingsXDaiAdapter.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {IGnoDaiDistributor} from "../interfaces/IGnoDaiDistributor.sol"; +import {IMerkleDistributor} from "../interfaces/IMerkleDistributor.sol"; +import {ISavingsXDaiAdapter} from "../interfaces/ISavingsXDaiAdapter.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title GnoDaiDistributor @@ -16,43 +16,40 @@ import {Errors} from '../libraries/Errors.sol'; * @notice Converts xDAI to sDAI and distributes it to the users using Merkle Distributor on Gnosis chain */ contract GnoDaiDistributor is ReentrancyGuard, IGnoDaiDistributor { - address private immutable _sDaiToken; - IVaultsRegistry private immutable _vaultsRegistry; - ISavingsXDaiAdapter private immutable _savingsXDaiAdapter; - IMerkleDistributor private immutable _merkleDistributor; - - /** - * @dev Constructor - * @param sDaiToken The address of the sDaiToken contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param savingsXDaiAdapter The address of the SavingsXDaiAdapter contract - */ - constructor( - address sDaiToken, - address vaultsRegistry, - address savingsXDaiAdapter, - address merkleDistributor - ) ReentrancyGuard() { - _sDaiToken = sDaiToken; - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - _savingsXDaiAdapter = ISavingsXDaiAdapter(savingsXDaiAdapter); - _merkleDistributor = IMerkleDistributor(merkleDistributor); - IERC20(sDaiToken).approve(merkleDistributor, type(uint256).max); - } - - /// @inheritdoc IGnoDaiDistributor - function distributeSDai() external payable nonReentrant { - // can be called only by vaults - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); - - // convert xDAI to sDAI - uint256 sDaiAmount = _savingsXDaiAdapter.depositXDAI{value: msg.value}(address(this)); - if (sDaiAmount == 0) revert Errors.InvalidAssets(); - - // distribute tokens to vault users - _merkleDistributor.distributeOneTime(_sDaiToken, sDaiAmount, '', abi.encode(msg.sender)); - - // emit event - emit SDaiDistributed(msg.sender, sDaiAmount); - } + address private immutable _sDaiToken; + IVaultsRegistry private immutable _vaultsRegistry; + ISavingsXDaiAdapter private immutable _savingsXDaiAdapter; + IMerkleDistributor private immutable _merkleDistributor; + + /** + * @dev Constructor + * @param sDaiToken The address of the sDaiToken contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param savingsXDaiAdapter The address of the SavingsXDaiAdapter contract + */ + constructor(address sDaiToken, address vaultsRegistry, address savingsXDaiAdapter, address merkleDistributor) + ReentrancyGuard() + { + _sDaiToken = sDaiToken; + _vaultsRegistry = IVaultsRegistry(vaultsRegistry); + _savingsXDaiAdapter = ISavingsXDaiAdapter(savingsXDaiAdapter); + _merkleDistributor = IMerkleDistributor(merkleDistributor); + IERC20(sDaiToken).approve(merkleDistributor, type(uint256).max); + } + + /// @inheritdoc IGnoDaiDistributor + function distributeSDai() external payable nonReentrant { + // can be called only by vaults + if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); + + // convert xDAI to sDAI + uint256 sDaiAmount = _savingsXDaiAdapter.depositXDAI{value: msg.value}(address(this)); + if (sDaiAmount == 0) revert Errors.InvalidAssets(); + + // distribute tokens to vault users + _merkleDistributor.distributeOneTime(_sDaiToken, sDaiAmount, "", abi.encode(msg.sender)); + + // emit event + emit SDaiDistributed(msg.sender, sDaiAmount); + } } diff --git a/contracts/misc/GnoRewardSplitter.sol b/contracts/misc/GnoRewardSplitter.sol index 857b7753..ad47d92b 100644 --- a/contracts/misc/GnoRewardSplitter.sol +++ b/contracts/misc/GnoRewardSplitter.sol @@ -2,35 +2,35 @@ pragma solidity ^0.8.22; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {RewardSplitter} from './RewardSplitter.sol'; -import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {RewardSplitter} from "./RewardSplitter.sol"; +import {IRewardSplitter} from "../interfaces/IRewardSplitter.sol"; /** * @title GnoRewardSplitter * @author StakeWise - * @notice The GnoRewardSplitter can be used on Gnosis networks - to split the rewards of the fee recipient of the vault based on configures shares + * @notice The GnoRewardSplitter can be used on Gnosis networks + * to split the rewards of the fee recipient of the vault based on configures shares */ contract GnoRewardSplitter is RewardSplitter { - IERC20 private immutable _gnoToken; + IERC20 private immutable _gnoToken; - /** - * @dev Constructor for GnoRewardSplitter - * @param gnoToken The address of the GNO token - */ - constructor(address gnoToken) RewardSplitter() { - _gnoToken = IERC20(gnoToken); - } + /** + * @dev Constructor for GnoRewardSplitter + * @param gnoToken The address of the GNO token + */ + constructor(address gnoToken) RewardSplitter() { + _gnoToken = IERC20(gnoToken); + } - /// @inheritdoc IRewardSplitter - function initialize(address _vault) external override initializer { - __RewardSplitter_init(_vault); - } + /// @inheritdoc IRewardSplitter + function initialize(address _vault) external override initializer { + __RewardSplitter_init(_vault); + } - /// @inheritdoc RewardSplitter - function _transferRewards(address shareholder, uint256 amount) internal override { - SafeERC20.safeTransfer(_gnoToken, shareholder, amount); - } + /// @inheritdoc RewardSplitter + function _transferRewards(address shareholder, uint256 amount) internal override { + SafeERC20.safeTransfer(_gnoToken, shareholder, amount); + } } diff --git a/contracts/misc/RewardSplitter.sol b/contracts/misc/RewardSplitter.sol index 973152c6..b7344a8b 100644 --- a/contracts/misc/RewardSplitter.sol +++ b/contracts/misc/RewardSplitter.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.22; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; -import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; -import {IVaultState} from '../interfaces/IVaultState.sol'; -import {IVaultEnterExit} from '../interfaces/IVaultEnterExit.sol'; -import {IVaultAdmin} from '../interfaces/IVaultAdmin.sol'; -import {Multicall} from '../base/Multicall.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IKeeperRewards} from "../interfaces/IKeeperRewards.sol"; +import {IRewardSplitter} from "../interfaces/IRewardSplitter.sol"; +import {IVaultState} from "../interfaces/IVaultState.sol"; +import {IVaultEnterExit} from "../interfaces/IVaultEnterExit.sol"; +import {IVaultAdmin} from "../interfaces/IVaultAdmin.sol"; +import {Multicall} from "../base/Multicall.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title RewardSplitter @@ -21,256 +21,241 @@ import {Errors} from '../libraries/Errors.sol'; * @notice The RewardSplitter can be used to split the rewards of the fee recipient of the vault based on configured shares */ abstract contract RewardSplitter is IRewardSplitter, Initializable, Multicall { - uint256 private constant _wad = 1e18; + uint256 private constant _wad = 1e18; - /// @inheritdoc IRewardSplitter - address public override vault; + /// @inheritdoc IRewardSplitter + address public override vault; - /// @inheritdoc IRewardSplitter - uint256 public override totalShares; + /// @inheritdoc IRewardSplitter + uint256 public override totalShares; - /// @inheritdoc IRewardSplitter - bool public override isClaimOnBehalfEnabled; + /// @inheritdoc IRewardSplitter + bool public override isClaimOnBehalfEnabled; - mapping(address => ShareHolder) private _shareHolders; - mapping(address => uint256) private _unclaimedRewards; - mapping(uint256 positionTicket => address onBehalf) public override exitPositions; + mapping(address => ShareHolder) private _shareHolders; + mapping(address => uint256) private _unclaimedRewards; + mapping(uint256 positionTicket => address onBehalf) public override exitPositions; - uint128 private _totalRewards; - uint128 private _rewardPerShare; + uint128 private _totalRewards; + uint128 private _rewardPerShare; - /** - * @dev Modifier to check if the caller is the vault admin - */ - modifier onlyVaultAdmin() { - if (msg.sender != IVaultAdmin(vault).admin()) { - revert Errors.AccessDenied(); + /** + * @dev Modifier to check if the caller is the vault admin + */ + modifier onlyVaultAdmin() { + if (msg.sender != IVaultAdmin(vault).admin()) { + revert Errors.AccessDenied(); + } + _; } - _; - } - - constructor() { - _disableInitializers(); - } - - /// @inheritdoc IRewardSplitter - function setClaimOnBehalf(bool enabled) external onlyVaultAdmin { - isClaimOnBehalfEnabled = enabled; - emit ClaimOnBehalfUpdated(msg.sender, enabled); - } - - /// @inheritdoc IRewardSplitter - function totalRewards() external view override returns (uint128) { - return _totalRewards; - } - - /// @inheritdoc IRewardSplitter - function sharesOf(address account) external view override returns (uint256) { - return _shareHolders[account].shares; - } - - /// @inheritdoc IRewardSplitter - function rewardsOf(address account) public view override returns (uint256) { - // SLOAD to memory - ShareHolder memory shareHolder = _shareHolders[account]; - // calculate period rewards based on current reward per share - uint256 periodRewards = Math.mulDiv( - shareHolder.shares, - _rewardPerShare - shareHolder.rewardPerShare, - _wad - ); - return _unclaimedRewards[account] + periodRewards; - } - - /// @inheritdoc IRewardSplitter - function canSyncRewards() external view override returns (bool) { - return totalShares > 0 && _totalRewards != IVaultState(vault).getShares(address(this)); - } - - /// @inheritdoc IRewardSplitter - function increaseShares(address account, uint128 amount) external override onlyVaultAdmin { - if (account == address(0)) revert InvalidAccount(); - if (amount == 0) revert InvalidAmount(); - - // update rewards state - syncRewards(); - - // update unclaimed rewards - _unclaimedRewards[account] = rewardsOf(account); - - // increase shares for the account - _shareHolders[account] = ShareHolder({ - shares: _shareHolders[account].shares + amount, - rewardPerShare: _rewardPerShare - }); - totalShares += amount; - - // emit event - emit SharesIncreased(account, amount); - } - - /// @inheritdoc IRewardSplitter - function decreaseShares(address account, uint128 amount) external override onlyVaultAdmin { - if (account == address(0)) revert InvalidAccount(); - if (amount == 0) revert InvalidAmount(); - - // update rewards state - syncRewards(); - - // update unclaimed rewards - _unclaimedRewards[account] = rewardsOf(account); - - // decrease shares for the account - _shareHolders[account] = ShareHolder({ - shares: _shareHolders[account].shares - amount, - rewardPerShare: _rewardPerShare - }); - totalShares -= amount; - - // emit event - emit SharesDecreased(account, amount); - } - - /// @inheritdoc IRewardSplitter - function updateVaultState(IKeeperRewards.HarvestParams calldata harvestParams) external override { - IVaultState(vault).updateState(harvestParams); - } - - /// @inheritdoc IRewardSplitter - function claimVaultTokens(uint256 rewards, address receiver) external override { - rewards = _withdrawRewards(msg.sender, rewards); - // NB! will revert if vault is not ERC-20 - SafeERC20.safeTransfer(IERC20(vault), receiver, rewards); - } - - /// @inheritdoc IRewardSplitter - function enterExitQueue( - uint256 rewards, - address receiver - ) external override returns (uint256 positionTicket) { - rewards = _withdrawRewards(msg.sender, rewards); - return IVaultEnterExit(vault).enterExitQueue(rewards, receiver); - } - - /// @inheritdoc IRewardSplitter - function enterExitQueueOnBehalf( - uint256 rewards, - address onBehalf - ) external override returns (uint256 positionTicket) { - if (!isClaimOnBehalfEnabled) revert Errors.AccessDenied(); - - rewards = _withdrawRewards(onBehalf, rewards); - - // Use the reward splitter address as receiver. This allows the reward splitter to claim the assets. - positionTicket = IVaultEnterExit(vault).enterExitQueue(rewards, address(this)); - exitPositions[positionTicket] = onBehalf; - - emit ExitQueueEnteredOnBehalf(onBehalf, positionTicket, rewards); - } - - /// @inheritdoc IRewardSplitter - function claimExitedAssetsOnBehalf( - uint256 positionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external override { - address onBehalf = exitPositions[positionTicket]; - if (onBehalf == address(0)) revert Errors.InvalidPosition(); - - // calculate exited tickets and assets - (uint256 leftTickets, , uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( - address(this), - positionTicket, - timestamp, - exitQueueIndex - ); - // disallow partial claims (1 ticket could be a rounding error) - if (leftTickets > 1) revert Errors.ExitRequestNotProcessed(); - - IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, exitQueueIndex); - delete exitPositions[positionTicket]; - - _transferRewards(onBehalf, exitedAssets); - - emit ExitedAssetsClaimedOnBehalf(onBehalf, positionTicket, exitedAssets); - } - - /** - * @dev Transfers the specified amount of rewards to the shareholder - * @param shareholder The address of the shareholder - * @param amount The amount of rewards to transfer - */ - function _transferRewards(address shareholder, uint256 amount) internal virtual; - - /// @inheritdoc IRewardSplitter - function syncRewards() public override { - // SLOAD to memory - uint256 _totalShares = totalShares; - if (_totalShares == 0) return; - - address _vault = vault; - // vault state must be up-to-date - if (IVaultState(_vault).isStateUpdateRequired()) revert NotHarvested(); - - // SLOAD to memory - uint256 prevTotalRewards = _totalRewards; - - // retrieve new total rewards - // NB! make sure vault has getShares function to retrieve number of shares assigned - uint256 newTotalRewards = IVaultState(_vault).getShares(address(this)); - if (newTotalRewards == prevTotalRewards) return; - - // calculate new cumulative reward per share - // reverts when total shares is zero - uint256 newRewardPerShare = _rewardPerShare + - Math.mulDiv(newTotalRewards - prevTotalRewards, _wad, _totalShares); - - // update state - _totalRewards = SafeCast.toUint128(newTotalRewards); - _rewardPerShare = SafeCast.toUint128(newRewardPerShare); - - // emit event - emit RewardsSynced(newTotalRewards, newRewardPerShare); - } - - /** - * @dev Withdraws rewards for the given account - * @param account The address of the account to withdraw rewards for - * @param rewards The amount of rewards to withdraw - * @return The actual amount of rewards withdrawn - */ - function _withdrawRewards(address account, uint256 rewards) private returns (uint256) { - // Sync rewards from the vault - syncRewards(); - - // get user total number of rewards - uint256 accountRewards = rewardsOf(account); - - // Set actual amount of rewards if user requested to withdraw all available rewards - if (rewards == type(uint256).max) { - rewards = accountRewards; + + constructor() { + _disableInitializers(); + } + + /// @inheritdoc IRewardSplitter + function setClaimOnBehalf(bool enabled) external onlyVaultAdmin { + isClaimOnBehalfEnabled = enabled; + emit ClaimOnBehalfUpdated(msg.sender, enabled); + } + + /// @inheritdoc IRewardSplitter + function totalRewards() external view override returns (uint128) { + return _totalRewards; + } + + /// @inheritdoc IRewardSplitter + function sharesOf(address account) external view override returns (uint256) { + return _shareHolders[account].shares; + } + + /// @inheritdoc IRewardSplitter + function rewardsOf(address account) public view override returns (uint256) { + // SLOAD to memory + ShareHolder memory shareHolder = _shareHolders[account]; + // calculate period rewards based on current reward per share + uint256 periodRewards = Math.mulDiv(shareHolder.shares, _rewardPerShare - shareHolder.rewardPerShare, _wad); + return _unclaimedRewards[account] + periodRewards; + } + + /// @inheritdoc IRewardSplitter + function canSyncRewards() external view override returns (bool) { + return totalShares > 0 && _totalRewards != IVaultState(vault).getShares(address(this)); } - // withdraw shareholder rewards from the splitter - _totalRewards -= SafeCast.toUint128(rewards); + /// @inheritdoc IRewardSplitter + function increaseShares(address account, uint128 amount) external override onlyVaultAdmin { + if (account == address(0)) revert InvalidAccount(); + if (amount == 0) revert InvalidAmount(); - // update shareholder - // reverts if withdrawn rewards exceed total - _unclaimedRewards[account] = accountRewards - rewards; - _shareHolders[account].rewardPerShare = _rewardPerShare; + // update rewards state + syncRewards(); - // emit event - emit RewardsWithdrawn(account, rewards); + // update unclaimed rewards + _unclaimedRewards[account] = rewardsOf(account); - // return actual amount of rewards withdrawn - return rewards; - } + // increase shares for the account + _shareHolders[account] = + ShareHolder({shares: _shareHolders[account].shares + amount, rewardPerShare: _rewardPerShare}); + totalShares += amount; + + // emit event + emit SharesIncreased(account, amount); + } + + /// @inheritdoc IRewardSplitter + function decreaseShares(address account, uint128 amount) external override onlyVaultAdmin { + if (account == address(0)) revert InvalidAccount(); + if (amount == 0) revert InvalidAmount(); + + // update rewards state + syncRewards(); + + // update unclaimed rewards + _unclaimedRewards[account] = rewardsOf(account); + + // decrease shares for the account + _shareHolders[account] = + ShareHolder({shares: _shareHolders[account].shares - amount, rewardPerShare: _rewardPerShare}); + totalShares -= amount; + + // emit event + emit SharesDecreased(account, amount); + } + + /// @inheritdoc IRewardSplitter + function updateVaultState(IKeeperRewards.HarvestParams calldata harvestParams) external override { + IVaultState(vault).updateState(harvestParams); + } - /** - * @dev Initializes the RewardSplitter contract - * @param _vault The address of the vault to which the RewardSplitter will be connected - */ - function __RewardSplitter_init(address _vault) internal onlyInitializing { - vault = _vault; - } + /// @inheritdoc IRewardSplitter + function claimVaultTokens(uint256 rewards, address receiver) external override { + rewards = _withdrawRewards(msg.sender, rewards); + // NB! will revert if vault is not ERC-20 + SafeERC20.safeTransfer(IERC20(vault), receiver, rewards); + } + + /// @inheritdoc IRewardSplitter + function enterExitQueue(uint256 rewards, address receiver) external override returns (uint256 positionTicket) { + rewards = _withdrawRewards(msg.sender, rewards); + return IVaultEnterExit(vault).enterExitQueue(rewards, receiver); + } + + /// @inheritdoc IRewardSplitter + function enterExitQueueOnBehalf(uint256 rewards, address onBehalf) + external + override + returns (uint256 positionTicket) + { + if (!isClaimOnBehalfEnabled) revert Errors.AccessDenied(); + + rewards = _withdrawRewards(onBehalf, rewards); + + // Use the reward splitter address as receiver. This allows the reward splitter to claim the assets. + positionTicket = IVaultEnterExit(vault).enterExitQueue(rewards, address(this)); + exitPositions[positionTicket] = onBehalf; + + emit ExitQueueEnteredOnBehalf(onBehalf, positionTicket, rewards); + } + + /// @inheritdoc IRewardSplitter + function claimExitedAssetsOnBehalf(uint256 positionTicket, uint256 timestamp, uint256 exitQueueIndex) + external + override + { + address onBehalf = exitPositions[positionTicket]; + if (onBehalf == address(0)) revert Errors.InvalidPosition(); + + // calculate exited tickets and assets + (uint256 leftTickets,, uint256 exitedAssets) = + IVaultEnterExit(vault).calculateExitedAssets(address(this), positionTicket, timestamp, exitQueueIndex); + // disallow partial claims (1 ticket could be a rounding error) + if (leftTickets > 1) revert Errors.ExitRequestNotProcessed(); + + IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + delete exitPositions[positionTicket]; + + _transferRewards(onBehalf, exitedAssets); + + emit ExitedAssetsClaimedOnBehalf(onBehalf, positionTicket, exitedAssets); + } + + /** + * @dev Transfers the specified amount of rewards to the shareholder + * @param shareholder The address of the shareholder + * @param amount The amount of rewards to transfer + */ + function _transferRewards(address shareholder, uint256 amount) internal virtual; + + /// @inheritdoc IRewardSplitter + function syncRewards() public override { + // SLOAD to memory + uint256 _totalShares = totalShares; + if (_totalShares == 0) return; + + address _vault = vault; + // vault state must be up-to-date + if (IVaultState(_vault).isStateUpdateRequired()) revert NotHarvested(); + + // SLOAD to memory + uint256 prevTotalRewards = _totalRewards; + + // retrieve new total rewards + // NB! make sure vault has getShares function to retrieve number of shares assigned + uint256 newTotalRewards = IVaultState(_vault).getShares(address(this)); + if (newTotalRewards == prevTotalRewards) return; + + // calculate new cumulative reward per share + // reverts when total shares is zero + uint256 newRewardPerShare = + _rewardPerShare + Math.mulDiv(newTotalRewards - prevTotalRewards, _wad, _totalShares); + + // update state + _totalRewards = SafeCast.toUint128(newTotalRewards); + _rewardPerShare = SafeCast.toUint128(newRewardPerShare); + + // emit event + emit RewardsSynced(newTotalRewards, newRewardPerShare); + } + + /** + * @dev Withdraws rewards for the given account + * @param account The address of the account to withdraw rewards for + * @param rewards The amount of rewards to withdraw + * @return The actual amount of rewards withdrawn + */ + function _withdrawRewards(address account, uint256 rewards) private returns (uint256) { + // Sync rewards from the vault + syncRewards(); + + // get user total number of rewards + uint256 accountRewards = rewardsOf(account); + + // Set actual amount of rewards if user requested to withdraw all available rewards + if (rewards == type(uint256).max) { + rewards = accountRewards; + } + + // withdraw shareholder rewards from the splitter + _totalRewards -= SafeCast.toUint128(rewards); + + // update shareholder + // reverts if withdrawn rewards exceed total + _unclaimedRewards[account] = accountRewards - rewards; + _shareHolders[account].rewardPerShare = _rewardPerShare; + + // emit event + emit RewardsWithdrawn(account, rewards); + + // return actual amount of rewards withdrawn + return rewards; + } + + /** + * @dev Initializes the RewardSplitter contract + * @param _vault The address of the vault to which the RewardSplitter will be connected + */ + function __RewardSplitter_init(address _vault) internal onlyInitializing { + vault = _vault; + } } diff --git a/contracts/misc/RewardSplitterFactory.sol b/contracts/misc/RewardSplitterFactory.sol index ba0d3f31..3aa327bc 100644 --- a/contracts/misc/RewardSplitterFactory.sol +++ b/contracts/misc/RewardSplitterFactory.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {Clones} from '@openzeppelin/contracts/proxy/Clones.sol'; -import {IRewardSplitter} from '../interfaces/IRewardSplitter.sol'; -import {IRewardSplitterFactory} from '../interfaces/IRewardSplitterFactory.sol'; +import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +import {IRewardSplitter} from "../interfaces/IRewardSplitter.sol"; +import {IRewardSplitterFactory} from "../interfaces/IRewardSplitterFactory.sol"; /** * @title RewardSplitterFactory @@ -12,24 +12,24 @@ import {IRewardSplitterFactory} from '../interfaces/IRewardSplitterFactory.sol'; * @notice Factory for deploying the RewardSplitter contract */ contract RewardSplitterFactory is IRewardSplitterFactory { - /// @inheritdoc IRewardSplitterFactory - address public immutable override implementation; + /// @inheritdoc IRewardSplitterFactory + address public immutable override implementation; - /** - * @dev Constructor - * @param _implementation The implementation address of RewardSplitter - */ - constructor(address _implementation) { - implementation = _implementation; - } + /** + * @dev Constructor + * @param _implementation The implementation address of RewardSplitter + */ + constructor(address _implementation) { + implementation = _implementation; + } - /// @inheritdoc IRewardSplitterFactory - function createRewardSplitter(address vault) external override returns (address rewardSplitter) { - // deploy and initialize reward splitter - rewardSplitter = Clones.clone(implementation); - IRewardSplitter(rewardSplitter).initialize(vault); + /// @inheritdoc IRewardSplitterFactory + function createRewardSplitter(address vault) external override returns (address rewardSplitter) { + // deploy and initialize reward splitter + rewardSplitter = Clones.clone(implementation); + IRewardSplitter(rewardSplitter).initialize(vault); - // emit event - emit RewardSplitterCreated(msg.sender, vault, rewardSplitter); - } + // emit event + emit RewardSplitterCreated(msg.sender, vault, rewardSplitter); + } } diff --git a/contracts/mocks/EthVaultV6Mock.sol b/contracts/mocks/EthVaultV6Mock.sol index c5b12554..87ef1f9f 100644 --- a/contracts/mocks/EthVaultV6Mock.sol +++ b/contracts/mocks/EthVaultV6Mock.sol @@ -2,23 +2,23 @@ pragma solidity ^0.8.22; -import {EthVault, IEthVault} from '../vaults/ethereum/EthVault.sol'; +import {EthVault, IEthVault} from "../vaults/ethereum/EthVault.sol"; contract EthVaultV6Mock is EthVault { - uint128 public newVar; + uint128 public newVar; - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(IEthVault.EthVaultConstructorArgs memory args) EthVault(args) {} + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(IEthVault.EthVaultConstructorArgs memory args) EthVault(args) {} - function initialize(bytes calldata data) external payable virtual override reinitializer(6) { - (newVar) = abi.decode(data, (uint128)); - } + function initialize(bytes calldata data) external payable virtual override reinitializer(6) { + (newVar) = abi.decode(data, (uint128)); + } - function somethingNew() external pure returns (bool) { - return true; - } + function somethingNew() external pure returns (bool) { + return true; + } - function version() public pure virtual override returns (uint8) { - return 6; - } + function version() public pure virtual override returns (uint8) { + return 6; + } } diff --git a/contracts/mocks/EthVaultV7Mock.sol b/contracts/mocks/EthVaultV7Mock.sol index 2d875606..599842bb 100644 --- a/contracts/mocks/EthVaultV7Mock.sol +++ b/contracts/mocks/EthVaultV7Mock.sol @@ -2,16 +2,16 @@ pragma solidity ^0.8.22; -import {IEthVault} from '../interfaces/IEthVault.sol'; -import {EthVaultV6Mock} from './EthVaultV6Mock.sol'; +import {IEthVault} from "../interfaces/IEthVault.sol"; +import {EthVaultV6Mock} from "./EthVaultV6Mock.sol"; contract EthVaultV7Mock is EthVaultV6Mock { - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(IEthVault.EthVaultConstructorArgs memory args) EthVaultV6Mock(args) {} + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(IEthVault.EthVaultConstructorArgs memory args) EthVaultV6Mock(args) {} - function initialize(bytes calldata data) external payable override reinitializer(7) {} + function initialize(bytes calldata data) external payable override reinitializer(7) {} - function version() public pure virtual override returns (uint8) { - return 7; - } + function version() public pure virtual override returns (uint8) { + return 7; + } } diff --git a/contracts/mocks/MulticallMock.sol b/contracts/mocks/MulticallMock.sol index 4ea24ea8..ca4ad268 100644 --- a/contracts/mocks/MulticallMock.sol +++ b/contracts/mocks/MulticallMock.sol @@ -1,56 +1,52 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Multicall} from '../base/Multicall.sol'; +import {Test} from "forge-std/Test.sol"; +import {Multicall} from "../base/Multicall.sol"; contract MulticallMock is Multicall { - uint256 public value; - string public message; - bool public flag; - address public caller; - - function setValue(uint256 _value) external returns (uint256) { - value = _value; - return value; - } - - function setMessage(string calldata _message) external returns (string memory) { - message = _message; - return message; - } - - function setFlag(bool _flag) external returns (bool) { - flag = _flag; - return flag; - } - - function revertWithMessage() external pure { - revert('Intentional revert with message'); - } - - function revertWithoutMessage() external pure { - revert(); - } - - function multipleParams( - uint256 a, - string calldata b, - bool c - ) external returns (uint256, string memory, bool) { - value = a; - message = b; - flag = c; - return (a, b, c); - } - - function checkCaller() external returns (address) { - caller = msg.sender; - return caller; - } - - function addToValue(uint256 amount) external returns (uint256) { - value += amount; - return value; - } + uint256 public value; + string public message; + bool public flag; + address public caller; + + function setValue(uint256 _value) external returns (uint256) { + value = _value; + return value; + } + + function setMessage(string calldata _message) external returns (string memory) { + message = _message; + return message; + } + + function setFlag(bool _flag) external returns (bool) { + flag = _flag; + return flag; + } + + function revertWithMessage() external pure { + revert("Intentional revert with message"); + } + + function revertWithoutMessage() external pure { + revert(); + } + + function multipleParams(uint256 a, string calldata b, bool c) external returns (uint256, string memory, bool) { + value = a; + message = b; + flag = c; + return (a, b, c); + } + + function checkCaller() external returns (address) { + caller = msg.sender; + return caller; + } + + function addToValue(uint256 amount) external returns (uint256) { + value += amount; + return value; + } } diff --git a/contracts/mocks/OsTokenFlashLoanRecipientMock.sol b/contracts/mocks/OsTokenFlashLoanRecipientMock.sol index 79ec4c18..f255608f 100644 --- a/contracts/mocks/OsTokenFlashLoanRecipientMock.sol +++ b/contracts/mocks/OsTokenFlashLoanRecipientMock.sol @@ -1,58 +1,58 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IOsTokenFlashLoanRecipient} from '../interfaces/IOsTokenFlashLoanRecipient.sol'; -import {IOsTokenFlashLoans} from '../interfaces/IOsTokenFlashLoans.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IOsTokenFlashLoanRecipient} from "../interfaces/IOsTokenFlashLoanRecipient.sol"; +import {IOsTokenFlashLoans} from "../interfaces/IOsTokenFlashLoans.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title OsTokenFlashLoanRecipientMock * @notice Mock contract that acts both as the caller and receiver of the flash loan */ contract OsTokenFlashLoanRecipientMock is IOsTokenFlashLoanRecipient { - address public osToken; - bool public shouldRepayLoan; // Simulate success or failure in repaying the loan - address public flashLoanContract; - - /** - * @dev Constructor to set the osToken address and flash loan contract - * @param _osToken The address of the OsToken contract - * @param _flashLoanContract The address of the OsTokenFlashLoans contract - */ - constructor(address _osToken, address _flashLoanContract) { - osToken = _osToken; - flashLoanContract = _flashLoanContract; - shouldRepayLoan = true; // Default to repaying the loan - } - - function receiveFlashLoan(uint256 osTokenShares, bytes calldata) external override { - require(msg.sender == flashLoanContract, 'Caller is not flash loan contract'); - - // Do something with the userData if needed - - // If the recipient is supposed to repay the loan - if (shouldRepayLoan) { - // Repay the loan by transferring back the borrowed osTokenShares - IERC20(osToken).transfer(msg.sender, osTokenShares); + address public osToken; + bool public shouldRepayLoan; // Simulate success or failure in repaying the loan + address public flashLoanContract; + + /** + * @dev Constructor to set the osToken address and flash loan contract + * @param _osToken The address of the OsToken contract + * @param _flashLoanContract The address of the OsTokenFlashLoans contract + */ + constructor(address _osToken, address _flashLoanContract) { + osToken = _osToken; + flashLoanContract = _flashLoanContract; + shouldRepayLoan = true; // Default to repaying the loan + } + + function receiveFlashLoan(uint256 osTokenShares, bytes calldata) external override { + require(msg.sender == flashLoanContract, "Caller is not flash loan contract"); + + // Do something with the userData if needed + + // If the recipient is supposed to repay the loan + if (shouldRepayLoan) { + // Repay the loan by transferring back the borrowed osTokenShares + IERC20(osToken).transfer(msg.sender, osTokenShares); + } + // If shouldRepayLoan is false, we simulate a failure by not transferring back the tokens + } + + /** + * @notice Executes a flash loan from the OsTokenFlashLoans contract + * @param osTokenShares The amount of OsToken shares to borrow + * @param userData Arbitrary data to pass along with the flash loan + */ + function executeFlashLoan(uint256 osTokenShares, bytes calldata userData) external { + IOsTokenFlashLoans(flashLoanContract).flashLoan(osTokenShares, userData); + } + + /** + * @notice Toggle the loan repayment behavior (for testing) + * @param repay Set to true if the loan should be repaid, false otherwise + */ + function setShouldRepayLoan(bool repay) external { + shouldRepayLoan = repay; } - // If shouldRepayLoan is false, we simulate a failure by not transferring back the tokens - } - - /** - * @notice Executes a flash loan from the OsTokenFlashLoans contract - * @param osTokenShares The amount of OsToken shares to borrow - * @param userData Arbitrary data to pass along with the flash loan - */ - function executeFlashLoan(uint256 osTokenShares, bytes calldata userData) external { - IOsTokenFlashLoans(flashLoanContract).flashLoan(osTokenShares, userData); - } - - /** - * @notice Toggle the loan repayment behavior (for testing) - * @param repay Set to true if the loan should be repaid, false otherwise - */ - function setShouldRepayLoan(bool repay) external { - shouldRepayLoan = repay; - } } diff --git a/contracts/mocks/ValidatorsConsolidationsMock.sol b/contracts/mocks/ValidatorsConsolidationsMock.sol index e8394b49..7c300429 100644 --- a/contracts/mocks/ValidatorsConsolidationsMock.sol +++ b/contracts/mocks/ValidatorsConsolidationsMock.sol @@ -3,21 +3,21 @@ pragma solidity ^0.8.22; contract ValidatorsConsolidationsMock { - error InvalidFeeError(); + error InvalidFeeError(); - event ValidatorConsolidated(bytes fromPubkey, bytes toPubkey); + event ValidatorConsolidated(bytes fromPubkey, bytes toPubkey); - uint256 private constant _fee = 0.1 ether; + uint256 private constant _fee = 0.1 ether; - fallback(bytes calldata input) external payable returns (bytes memory output) { - if (input.length == 0) { - return abi.encode(_fee); - } - if (msg.value != _fee) { - revert InvalidFeeError(); - } + fallback(bytes calldata input) external payable returns (bytes memory output) { + if (input.length == 0) { + return abi.encode(_fee); + } + if (msg.value != _fee) { + revert InvalidFeeError(); + } - emit ValidatorConsolidated(input[:48], input[48:96]); - return ''; - } + emit ValidatorConsolidated(input[:48], input[48:96]); + return ""; + } } diff --git a/contracts/mocks/ValidatorsWithdrawalsMock.sol b/contracts/mocks/ValidatorsWithdrawalsMock.sol index 40b3121f..b0b9f50c 100644 --- a/contracts/mocks/ValidatorsWithdrawalsMock.sol +++ b/contracts/mocks/ValidatorsWithdrawalsMock.sol @@ -3,21 +3,21 @@ pragma solidity ^0.8.22; contract ValidatorsWithdrawalsMock { - error InvalidFeeError(); + error InvalidFeeError(); - event ValidatorWithdrawn(address sender, bytes fromPubkey, uint64 amount); + event ValidatorWithdrawn(address sender, bytes fromPubkey, uint64 amount); - uint256 private constant _fee = 0.1 ether; + uint256 private constant _fee = 0.1 ether; - fallback(bytes calldata input) external payable returns (bytes memory output) { - if (input.length == 0) { - return abi.encode(_fee); - } - if (msg.value != _fee) { - revert InvalidFeeError(); - } + fallback(bytes calldata input) external payable returns (bytes memory output) { + if (input.length == 0) { + return abi.encode(_fee); + } + if (msg.value != _fee) { + revert InvalidFeeError(); + } - emit ValidatorWithdrawn(msg.sender, input[:48], uint64(bytes8(input[48:56]))); - return ''; - } + emit ValidatorWithdrawn(msg.sender, input[:48], uint64(bytes8(input[48:56]))); + return ""; + } } diff --git a/contracts/tokens/EthOsTokenVaultEscrow.sol b/contracts/tokens/EthOsTokenVaultEscrow.sol index cf8d7bce..7d06665c 100644 --- a/contracts/tokens/EthOsTokenVaultEscrow.sol +++ b/contracts/tokens/EthOsTokenVaultEscrow.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {OsTokenVaultEscrow} from './OsTokenVaultEscrow.sol'; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {OsTokenVaultEscrow} from "./OsTokenVaultEscrow.sol"; /** * @title EthOsTokenVaultEscrow @@ -13,50 +13,50 @@ import {OsTokenVaultEscrow} from './OsTokenVaultEscrow.sol'; * @notice Used for initiating assets exits from the vault without burning osToken on Ethereum */ contract EthOsTokenVaultEscrow is ReentrancyGuard, OsTokenVaultEscrow { - /** - * @notice Event emitted on assets received by the escrow - * @param sender The address of the sender - * @param value The amount of assets received - */ - event AssetsReceived(address indexed sender, uint256 value); + /** + * @notice Event emitted on assets received by the escrow + * @param sender The address of the sender + * @param value The amount of assets received + */ + event AssetsReceived(address indexed sender, uint256 value); - /** - * @dev Constructor - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param initialOwner The address of the contract owner - * @param _authenticator The address of the OsTokenVaultEscrowAuth contract - * @param _liqThresholdPercent The liquidation threshold percent - * @param _liqBonusPercent The liquidation bonus percent - */ - constructor( - address osTokenVaultController, - address osTokenConfig, - address initialOwner, - address _authenticator, - uint64 _liqThresholdPercent, - uint256 _liqBonusPercent - ) - ReentrancyGuard() - OsTokenVaultEscrow( - osTokenVaultController, - osTokenConfig, - initialOwner, - _authenticator, - _liqThresholdPercent, - _liqBonusPercent + /** + * @dev Constructor + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param initialOwner The address of the contract owner + * @param _authenticator The address of the OsTokenVaultEscrowAuth contract + * @param _liqThresholdPercent The liquidation threshold percent + * @param _liqBonusPercent The liquidation bonus percent + */ + constructor( + address osTokenVaultController, + address osTokenConfig, + address initialOwner, + address _authenticator, + uint64 _liqThresholdPercent, + uint256 _liqBonusPercent ) - {} + ReentrancyGuard() + OsTokenVaultEscrow( + osTokenVaultController, + osTokenConfig, + initialOwner, + _authenticator, + _liqThresholdPercent, + _liqBonusPercent + ) + {} - /** - * @dev Function for receiving assets from the vault - */ - receive() external payable { - emit AssetsReceived(msg.sender, msg.value); - } + /** + * @dev Function for receiving assets from the vault + */ + receive() external payable { + emit AssetsReceived(msg.sender, msg.value); + } - /// @inheritdoc OsTokenVaultEscrow - function _transferAssets(address receiver, uint256 assets) internal override nonReentrant { - return Address.sendValue(payable(receiver), assets); - } + /// @inheritdoc OsTokenVaultEscrow + function _transferAssets(address receiver, uint256 assets) internal override nonReentrant { + return Address.sendValue(payable(receiver), assets); + } } diff --git a/contracts/tokens/GnoOsTokenVaultEscrow.sol b/contracts/tokens/GnoOsTokenVaultEscrow.sol index a2eeb7b3..3cbfb924 100644 --- a/contracts/tokens/GnoOsTokenVaultEscrow.sol +++ b/contracts/tokens/GnoOsTokenVaultEscrow.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {OsTokenVaultEscrow} from './OsTokenVaultEscrow.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {OsTokenVaultEscrow} from "./OsTokenVaultEscrow.sol"; /** * @title GnoOsTokenVaultEscrow @@ -12,41 +12,41 @@ import {OsTokenVaultEscrow} from './OsTokenVaultEscrow.sol'; * @notice Used for initiating assets exits from the vault without burning osToken on Gnosis */ contract GnoOsTokenVaultEscrow is OsTokenVaultEscrow { - IERC20 private immutable _gnoToken; + IERC20 private immutable _gnoToken; - /** - * @dev Constructor - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param initialOwner The address of the contract owner - * @param _authenticator The address of the OsTokenVaultEscrowAuth contract - * @param _liqThresholdPercent The liquidation threshold percent - * @param _liqBonusPercent The liquidation bonus percent - * @param gnoToken The address of the GNO token - */ - constructor( - address osTokenVaultController, - address osTokenConfig, - address initialOwner, - address _authenticator, - uint64 _liqThresholdPercent, - uint256 _liqBonusPercent, - address gnoToken - ) - OsTokenVaultEscrow( - osTokenVaultController, - osTokenConfig, - initialOwner, - _authenticator, - _liqThresholdPercent, - _liqBonusPercent + /** + * @dev Constructor + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param initialOwner The address of the contract owner + * @param _authenticator The address of the OsTokenVaultEscrowAuth contract + * @param _liqThresholdPercent The liquidation threshold percent + * @param _liqBonusPercent The liquidation bonus percent + * @param gnoToken The address of the GNO token + */ + constructor( + address osTokenVaultController, + address osTokenConfig, + address initialOwner, + address _authenticator, + uint64 _liqThresholdPercent, + uint256 _liqBonusPercent, + address gnoToken ) - { - _gnoToken = IERC20(gnoToken); - } + OsTokenVaultEscrow( + osTokenVaultController, + osTokenConfig, + initialOwner, + _authenticator, + _liqThresholdPercent, + _liqBonusPercent + ) + { + _gnoToken = IERC20(gnoToken); + } - /// @inheritdoc OsTokenVaultEscrow - function _transferAssets(address receiver, uint256 assets) internal override { - SafeERC20.safeTransfer(_gnoToken, receiver, assets); - } + /// @inheritdoc OsTokenVaultEscrow + function _transferAssets(address receiver, uint256 assets) internal override { + SafeERC20.safeTransfer(_gnoToken, receiver, assets); + } } diff --git a/contracts/tokens/OsToken.sol b/contracts/tokens/OsToken.sol index edcb81d2..ea316943 100644 --- a/contracts/tokens/OsToken.sol +++ b/contracts/tokens/OsToken.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {ERC20Permit, IERC20Permit, ERC20} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol'; -import {IOsToken} from '../interfaces/IOsToken.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {ERC20Permit, IERC20Permit, ERC20} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {IOsToken} from "../interfaces/IOsToken.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title OsToken @@ -13,57 +13,54 @@ import {Errors} from '../libraries/Errors.sol'; * @notice OsToken is an over-collateralized staked token */ contract OsToken is Ownable2Step, ERC20Permit, IOsToken { - address private immutable _vaultController; + address private immutable _vaultController; - /// @inheritdoc IOsToken - mapping(address controller => bool enabled) public override controllers; + /// @inheritdoc IOsToken + mapping(address controller => bool enabled) public override controllers; - /** - * @dev Constructor - * @param _owner The address of the contract owner - * @param vaultController The address of the OsTokenVaultController contract - * @param _name The name of the ERC20 token - * @param _symbol The symbol of the ERC20 token - */ - constructor( - address _owner, - address vaultController, - string memory _name, - string memory _symbol - ) ERC20(_name, _symbol) ERC20Permit(_name) Ownable(_owner) { - if (vaultController == address(0)) revert Errors.ZeroAddress(); - _vaultController = vaultController; - } + /** + * @dev Constructor + * @param _owner The address of the contract owner + * @param vaultController The address of the OsTokenVaultController contract + * @param _name The name of the ERC20 token + * @param _symbol The symbol of the ERC20 token + */ + constructor(address _owner, address vaultController, string memory _name, string memory _symbol) + ERC20(_name, _symbol) + ERC20Permit(_name) + Ownable(_owner) + { + if (vaultController == address(0)) revert Errors.ZeroAddress(); + _vaultController = vaultController; + } - /** - * @dev Throws if called by any account other than the controller. - */ - modifier onlyController() { - if (msg.sender != _vaultController && !controllers[msg.sender]) revert Errors.AccessDenied(); - _; - } + /** + * @dev Throws if called by any account other than the controller. + */ + modifier onlyController() { + if (msg.sender != _vaultController && !controllers[msg.sender]) revert Errors.AccessDenied(); + _; + } - /// @inheritdoc IOsToken - function mint(address account, uint256 value) external override onlyController { - _mint(account, value); - } + /// @inheritdoc IOsToken + function mint(address account, uint256 value) external override onlyController { + _mint(account, value); + } - /// @inheritdoc IOsToken - function burn(address account, uint256 value) external override onlyController { - _burn(account, value); - } + /// @inheritdoc IOsToken + function burn(address account, uint256 value) external override onlyController { + _burn(account, value); + } - /// @inheritdoc IERC20Permit - function nonces( - address owner - ) public view virtual override(ERC20Permit, IERC20Permit) returns (uint256) { - return super.nonces(owner); - } + /// @inheritdoc IERC20Permit + function nonces(address owner) public view virtual override(ERC20Permit, IERC20Permit) returns (uint256) { + return super.nonces(owner); + } - /// @inheritdoc IOsToken - function setController(address controller, bool enabled) external override onlyOwner { - if (controller == address(0)) revert Errors.ZeroAddress(); - controllers[controller] = enabled; - emit ControllerUpdated(controller, enabled); - } + /// @inheritdoc IOsToken + function setController(address controller, bool enabled) external override onlyOwner { + if (controller == address(0)) revert Errors.ZeroAddress(); + controllers[controller] = enabled; + emit ControllerUpdated(controller, enabled); + } } diff --git a/contracts/tokens/OsTokenConfig.sol b/contracts/tokens/OsTokenConfig.sol index f41463e9..aa3caf55 100644 --- a/contracts/tokens/OsTokenConfig.sol +++ b/contracts/tokens/OsTokenConfig.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {IOsTokenConfig} from '../interfaces/IOsTokenConfig.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IOsTokenConfig} from "../interfaces/IOsTokenConfig.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title OsTokenConfig @@ -13,86 +13,80 @@ import {Errors} from '../libraries/Errors.sol'; * @notice Configuration for minting and liquidating OsToken shares */ contract OsTokenConfig is Ownable2Step, IOsTokenConfig { - uint256 private constant _maxPercent = 1e18; - uint256 private constant _disabledLiqThreshold = type(uint64).max; + uint256 private constant _maxPercent = 1e18; + uint256 private constant _disabledLiqThreshold = type(uint64).max; - /// @inheritdoc IOsTokenConfig - address public override redeemer; + /// @inheritdoc IOsTokenConfig + address public override redeemer; - Config private _defaultConfig; + Config private _defaultConfig; - mapping(address vault => Config config) private _vaultConfigs; + mapping(address vault => Config config) private _vaultConfigs; - /** - * @dev Constructor - * @param _owner The address of the contract owner - * @param defaultConfig The OsToken default configuration - * @param _redeemer The address of the redeemer - */ - constructor(address _owner, Config memory defaultConfig, address _redeemer) Ownable(msg.sender) { - if (_owner == address(0)) revert Errors.ZeroAddress(); - updateConfig(address(0), defaultConfig); - setRedeemer(_redeemer); - _transferOwnership(_owner); - } - - /// @inheritdoc IOsTokenConfig - function getConfig(address vault) external view override returns (Config memory config) { - config = _vaultConfigs[vault]; - if (config.ltvPercent == 0) { - return _defaultConfig; + /** + * @dev Constructor + * @param _owner The address of the contract owner + * @param defaultConfig The OsToken default configuration + * @param _redeemer The address of the redeemer + */ + constructor(address _owner, Config memory defaultConfig, address _redeemer) Ownable(msg.sender) { + if (_owner == address(0)) revert Errors.ZeroAddress(); + updateConfig(address(0), defaultConfig); + setRedeemer(_redeemer); + _transferOwnership(_owner); } - } - /// @inheritdoc IOsTokenConfig - function setRedeemer(address newRedeemer) public override onlyOwner { - if (redeemer == newRedeemer) revert Errors.ValueNotChanged(); - redeemer = newRedeemer; - emit RedeemerUpdated(newRedeemer); - } + /// @inheritdoc IOsTokenConfig + function getConfig(address vault) external view override returns (Config memory config) { + config = _vaultConfigs[vault]; + if (config.ltvPercent == 0) { + return _defaultConfig; + } + } - /// @inheritdoc IOsTokenConfig - function updateConfig(address vault, Config memory config) public override onlyOwner { - // validate loan-to-value percent - if (config.ltvPercent == 0 || config.ltvPercent > _maxPercent) { - revert Errors.InvalidLtvPercent(); + /// @inheritdoc IOsTokenConfig + function setRedeemer(address newRedeemer) public override onlyOwner { + if (redeemer == newRedeemer) revert Errors.ValueNotChanged(); + redeemer = newRedeemer; + emit RedeemerUpdated(newRedeemer); } - if (config.liqThresholdPercent == _disabledLiqThreshold) { - // liquidations are disabled - if (config.liqBonusPercent != 0) revert Errors.InvalidLiqBonusPercent(); - } else { - // validate liquidation threshold percent - if ( - config.liqThresholdPercent == 0 || - config.liqThresholdPercent >= _maxPercent || - config.ltvPercent > config.liqThresholdPercent - ) { - revert Errors.InvalidLiqThresholdPercent(); - } + /// @inheritdoc IOsTokenConfig + function updateConfig(address vault, Config memory config) public override onlyOwner { + // validate loan-to-value percent + if (config.ltvPercent == 0 || config.ltvPercent > _maxPercent) { + revert Errors.InvalidLtvPercent(); + } - // validate liquidation bonus percent - if ( - config.liqBonusPercent < _maxPercent || - Math.mulDiv(config.liqThresholdPercent, config.liqBonusPercent, _maxPercent) > _maxPercent - ) { - revert Errors.InvalidLiqBonusPercent(); - } - } + if (config.liqThresholdPercent == _disabledLiqThreshold) { + // liquidations are disabled + if (config.liqBonusPercent != 0) revert Errors.InvalidLiqBonusPercent(); + } else { + // validate liquidation threshold percent + if ( + config.liqThresholdPercent == 0 || config.liqThresholdPercent >= _maxPercent + || config.ltvPercent > config.liqThresholdPercent + ) { + revert Errors.InvalidLiqThresholdPercent(); + } - // update state - if (vault != address(0)) { - _vaultConfigs[vault] = config; - } else { - _defaultConfig = config; - } + // validate liquidation bonus percent + if ( + config.liqBonusPercent < _maxPercent + || Math.mulDiv(config.liqThresholdPercent, config.liqBonusPercent, _maxPercent) > _maxPercent + ) { + revert Errors.InvalidLiqBonusPercent(); + } + } + + // update state + if (vault != address(0)) { + _vaultConfigs[vault] = config; + } else { + _defaultConfig = config; + } - // emit event - emit OsTokenConfigUpdated( - vault, - config.liqBonusPercent, - config.liqThresholdPercent, - config.ltvPercent - ); - } + // emit event + emit OsTokenConfigUpdated(vault, config.liqBonusPercent, config.liqThresholdPercent, config.ltvPercent); + } } diff --git a/contracts/tokens/OsTokenFlashLoans.sol b/contracts/tokens/OsTokenFlashLoans.sol index c3c46cd0..d914dbdd 100644 --- a/contracts/tokens/OsTokenFlashLoans.sol +++ b/contracts/tokens/OsTokenFlashLoans.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; -import {IOsTokenFlashLoans} from '../interfaces/IOsTokenFlashLoans.sol'; -import {IOsTokenFlashLoanRecipient} from '../interfaces/IOsTokenFlashLoanRecipient.sol'; -import {IOsToken} from '../interfaces/IOsToken.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {IOsTokenFlashLoans} from "../interfaces/IOsTokenFlashLoans.sol"; +import {IOsTokenFlashLoanRecipient} from "../interfaces/IOsTokenFlashLoanRecipient.sol"; +import {IOsToken} from "../interfaces/IOsToken.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title OsTokenFlashLoans @@ -15,45 +15,45 @@ import {Errors} from '../libraries/Errors.sol'; * @notice Mint and burn up to 100 000 osToken shares in single transaction. */ contract OsTokenFlashLoans is ReentrancyGuard, IOsTokenFlashLoans { - uint256 private constant _maxFlashLoanAmount = 100_000 ether; - address private immutable _osToken; - - /** - * @dev Constructor - * @param osToken The address of the OsToken contract - */ - constructor(address osToken) ReentrancyGuard() { - _osToken = osToken; - } - - /// @inheritdoc IOsTokenFlashLoans - function flashLoan(uint256 osTokenShares, bytes memory userData) external override nonReentrant { - // check if not more than max flash loan amount requested - if (osTokenShares == 0 || osTokenShares > _maxFlashLoanAmount) { - revert Errors.InvalidShares(); + uint256 private constant _maxFlashLoanAmount = 100_000 ether; + address private immutable _osToken; + + /** + * @dev Constructor + * @param osToken The address of the OsToken contract + */ + constructor(address osToken) ReentrancyGuard() { + _osToken = osToken; } - // get current balance - uint256 preLoanBalance = IERC20(_osToken).balanceOf(address(this)); + /// @inheritdoc IOsTokenFlashLoans + function flashLoan(uint256 osTokenShares, bytes memory userData) external override nonReentrant { + // check if not more than max flash loan amount requested + if (osTokenShares == 0 || osTokenShares > _maxFlashLoanAmount) { + revert Errors.InvalidShares(); + } - // mint OsToken shares for the caller - IOsToken(_osToken).mint(msg.sender, osTokenShares); + // get current balance + uint256 preLoanBalance = IERC20(_osToken).balanceOf(address(this)); - // execute callback - IOsTokenFlashLoanRecipient(msg.sender).receiveFlashLoan(osTokenShares, userData); + // mint OsToken shares for the caller + IOsToken(_osToken).mint(msg.sender, osTokenShares); - // get post loan balance - uint256 postLoanBalance = IERC20(_osToken).balanceOf(address(this)); + // execute callback + IOsTokenFlashLoanRecipient(msg.sender).receiveFlashLoan(osTokenShares, userData); - // check if the amount was repaid - if (postLoanBalance < preLoanBalance + osTokenShares) { - revert Errors.FlashLoanFailed(); - } + // get post loan balance + uint256 postLoanBalance = IERC20(_osToken).balanceOf(address(this)); + + // check if the amount was repaid + if (postLoanBalance < preLoanBalance + osTokenShares) { + revert Errors.FlashLoanFailed(); + } - // burn OsToken shares - IOsToken(address(_osToken)).burn(address(this), osTokenShares); + // burn OsToken shares + IOsToken(address(_osToken)).burn(address(this), osTokenShares); - // emit event - emit OsTokenFlashLoan(msg.sender, osTokenShares); - } + // emit event + emit OsTokenFlashLoan(msg.sender, osTokenShares); + } } diff --git a/contracts/tokens/OsTokenVaultController.sol b/contracts/tokens/OsTokenVaultController.sol index cbd79c70..85dc6b3c 100644 --- a/contracts/tokens/OsTokenVaultController.sol +++ b/contracts/tokens/OsTokenVaultController.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {IOsToken} from '../interfaces/IOsToken.sol'; -import {IVaultVersion} from '../interfaces/IVaultVersion.sol'; -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {IOsToken} from "../interfaces/IOsToken.sol"; +import {IVaultVersion} from "../interfaces/IVaultVersion.sol"; +import {IOsTokenVaultController} from "../interfaces/IOsTokenVaultController.sol"; /** * @title OsTokenVaultController @@ -17,308 +17,303 @@ import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol * @notice Over-collateralized staked token controller */ contract OsTokenVaultController is Ownable2Step, IOsTokenVaultController { - uint256 private constant _wad = 1e18; - uint256 private constant _maxFeePercent = 10_000; // @dev 100.00 % - - address private immutable _registry; - address private immutable _osToken; - - /// @inheritdoc IOsTokenVaultController - address public override keeper; - - /// @inheritdoc IOsTokenVaultController - uint256 public override capacity; - - /// @inheritdoc IOsTokenVaultController - uint256 public override avgRewardPerSecond; - - /// @inheritdoc IOsTokenVaultController - address public override treasury; - - /// @inheritdoc IOsTokenVaultController - uint64 public override feePercent; - - uint192 private _cumulativeFeePerShare = uint192(_wad); - uint64 private _lastUpdateTimestamp; - - uint128 private _totalShares; - uint128 private _totalAssets; - - /** - * @dev Constructor - * @param _keeper The address of the Keeper contract - * @param registry The address of the VaultsRegistry contract - * @param osToken The address of the OsToken contract - * @param _treasury The address of the DAO treasury - * @param _owner The address of the owner of the contract - * @param _feePercent The fee percent applied on the rewards - * @param _capacity The amount after which the osToken stops accepting deposits - */ - constructor( - address _keeper, - address registry, - address osToken, - address _treasury, - address _owner, - uint16 _feePercent, - uint256 _capacity - ) Ownable(msg.sender) { - if (_owner == address(0)) revert Errors.ZeroAddress(); - keeper = _keeper; - _registry = registry; - _osToken = osToken; - _lastUpdateTimestamp = uint64(block.timestamp); - - setCapacity(_capacity); - setTreasury(_treasury); - setFeePercent(_feePercent); - _transferOwnership(_owner); - } - - /// @inheritdoc IOsTokenVaultController - function totalShares() external view override returns (uint256) { - return _totalShares; - } - - /// @inheritdoc IOsTokenVaultController - function totalAssets() public view override returns (uint256) { - uint256 profitAccrued = _unclaimedAssets(); - if (profitAccrued == 0) return _totalAssets; - - uint256 treasuryAssets = Math.mulDiv(profitAccrued, feePercent, _maxFeePercent); - return _totalAssets + profitAccrued - treasuryAssets; - } - - /// @inheritdoc IOsTokenVaultController - function convertToShares(uint256 assets) public view override returns (uint256 shares) { - return _convertToShares(assets, _totalShares, totalAssets(), Math.Rounding.Floor); - } - - /// @inheritdoc IOsTokenVaultController - function convertToAssets(uint256 shares) public view override returns (uint256 assets) { - return _convertToAssets(shares, _totalShares, totalAssets(), Math.Rounding.Floor); - } - - /// @inheritdoc IOsTokenVaultController - function mintShares(address receiver, uint256 shares) external override returns (uint256 assets) { - if ( - !IVaultsRegistry(_registry).vaults(msg.sender) || - !IVaultsRegistry(_registry).vaultImpls(IVaultVersion(msg.sender).implementation()) - ) { - revert Errors.AccessDenied(); + uint256 private constant _wad = 1e18; + uint256 private constant _maxFeePercent = 10_000; // @dev 100.00 % + + address private immutable _registry; + address private immutable _osToken; + + /// @inheritdoc IOsTokenVaultController + address public override keeper; + + /// @inheritdoc IOsTokenVaultController + uint256 public override capacity; + + /// @inheritdoc IOsTokenVaultController + uint256 public override avgRewardPerSecond; + + /// @inheritdoc IOsTokenVaultController + address public override treasury; + + /// @inheritdoc IOsTokenVaultController + uint64 public override feePercent; + + uint192 private _cumulativeFeePerShare = uint192(_wad); + uint64 private _lastUpdateTimestamp; + + uint128 private _totalShares; + uint128 private _totalAssets; + + /** + * @dev Constructor + * @param _keeper The address of the Keeper contract + * @param registry The address of the VaultsRegistry contract + * @param osToken The address of the OsToken contract + * @param _treasury The address of the DAO treasury + * @param _owner The address of the owner of the contract + * @param _feePercent The fee percent applied on the rewards + * @param _capacity The amount after which the osToken stops accepting deposits + */ + constructor( + address _keeper, + address registry, + address osToken, + address _treasury, + address _owner, + uint16 _feePercent, + uint256 _capacity + ) Ownable(msg.sender) { + if (_owner == address(0)) revert Errors.ZeroAddress(); + keeper = _keeper; + _registry = registry; + _osToken = osToken; + _lastUpdateTimestamp = uint64(block.timestamp); + + setCapacity(_capacity); + setTreasury(_treasury); + setFeePercent(_feePercent); + _transferOwnership(_owner); } - if (receiver == address(0)) revert Errors.ZeroAddress(); - if (shares == 0) revert Errors.InvalidShares(); - // pull accumulated rewards - updateState(); + /// @inheritdoc IOsTokenVaultController + function totalShares() external view override returns (uint256) { + return _totalShares; + } - // calculate amount of assets to mint - assets = convertToAssets(shares); + /// @inheritdoc IOsTokenVaultController + function totalAssets() public view override returns (uint256) { + uint256 profitAccrued = _unclaimedAssets(); + if (profitAccrued == 0) return _totalAssets; - uint256 totalAssetsAfter = _totalAssets + assets; - if (totalAssetsAfter > capacity) revert Errors.CapacityExceeded(); + uint256 treasuryAssets = Math.mulDiv(profitAccrued, feePercent, _maxFeePercent); + return _totalAssets + profitAccrued - treasuryAssets; + } - // update counters - _totalShares += SafeCast.toUint128(shares); - _totalAssets = SafeCast.toUint128(totalAssetsAfter); + /// @inheritdoc IOsTokenVaultController + function convertToShares(uint256 assets) public view override returns (uint256 shares) { + return _convertToShares(assets, _totalShares, totalAssets(), Math.Rounding.Floor); + } - // mint shares - IOsToken(_osToken).mint(receiver, shares); - emit Mint(msg.sender, receiver, assets, shares); - } + /// @inheritdoc IOsTokenVaultController + function convertToAssets(uint256 shares) public view override returns (uint256 assets) { + return _convertToAssets(shares, _totalShares, totalAssets(), Math.Rounding.Floor); + } - /// @inheritdoc IOsTokenVaultController - function burnShares(address owner, uint256 shares) external override returns (uint256 assets) { - if (!IVaultsRegistry(_registry).vaults(msg.sender)) revert Errors.AccessDenied(); - if (shares == 0) revert Errors.InvalidShares(); + /// @inheritdoc IOsTokenVaultController + function mintShares(address receiver, uint256 shares) external override returns (uint256 assets) { + if ( + !IVaultsRegistry(_registry).vaults(msg.sender) + || !IVaultsRegistry(_registry).vaultImpls(IVaultVersion(msg.sender).implementation()) + ) { + revert Errors.AccessDenied(); + } + if (receiver == address(0)) revert Errors.ZeroAddress(); + if (shares == 0) revert Errors.InvalidShares(); + + // pull accumulated rewards + updateState(); + + // calculate amount of assets to mint + assets = convertToAssets(shares); + + uint256 totalAssetsAfter = _totalAssets + assets; + if (totalAssetsAfter > capacity) revert Errors.CapacityExceeded(); + + // update counters + _totalShares += SafeCast.toUint128(shares); + _totalAssets = SafeCast.toUint128(totalAssetsAfter); + + // mint shares + IOsToken(_osToken).mint(receiver, shares); + emit Mint(msg.sender, receiver, assets, shares); + } + + /// @inheritdoc IOsTokenVaultController + function burnShares(address owner, uint256 shares) external override returns (uint256 assets) { + if (!IVaultsRegistry(_registry).vaults(msg.sender)) revert Errors.AccessDenied(); + if (shares == 0) revert Errors.InvalidShares(); - // pull accumulated rewards - updateState(); + // pull accumulated rewards + updateState(); - // calculate amount of assets to burn - assets = convertToAssets(shares); + // calculate amount of assets to burn + assets = convertToAssets(shares); - // burn shares - IOsToken(_osToken).burn(owner, shares); + // burn shares + IOsToken(_osToken).burn(owner, shares); - // update counters - unchecked { - // cannot underflow because the sum of all shares can't exceed the _totalShares - _totalShares -= SafeCast.toUint128(shares); - // cannot underflow because the sum of all assets can't exceed the _totalAssets - _totalAssets -= SafeCast.toUint128(assets); + // update counters + unchecked { + // cannot underflow because the sum of all shares can't exceed the _totalShares + _totalShares -= SafeCast.toUint128(shares); + // cannot underflow because the sum of all assets can't exceed the _totalAssets + _totalAssets -= SafeCast.toUint128(assets); + } + emit Burn(msg.sender, owner, assets, shares); } - emit Burn(msg.sender, owner, assets, shares); - } - - /// @inheritdoc IOsTokenVaultController - function setCapacity(uint256 _capacity) public override onlyOwner { - // update os token capacity - capacity = _capacity; - emit CapacityUpdated(_capacity); - } - - /// @inheritdoc IOsTokenVaultController - function setTreasury(address _treasury) public override onlyOwner { - if (_treasury == address(0)) revert Errors.ZeroAddress(); - - // update DAO treasury address - treasury = _treasury; - emit TreasuryUpdated(_treasury); - } - - /// @inheritdoc IOsTokenVaultController - function setFeePercent(uint16 _feePercent) public override onlyOwner { - if (_feePercent > _maxFeePercent) revert Errors.InvalidFeePercent(); - // pull reward with the current fee percent - updateState(); - - // update fee percent - feePercent = _feePercent; - emit FeePercentUpdated(_feePercent); - } - - /// @inheritdoc IOsTokenVaultController - function setAvgRewardPerSecond(uint256 _avgRewardPerSecond) external override { - if (msg.sender != keeper) revert Errors.AccessDenied(); - - updateState(); - avgRewardPerSecond = _avgRewardPerSecond; - emit AvgRewardPerSecondUpdated(_avgRewardPerSecond); - } - - /// @inheritdoc IOsTokenVaultController - function setKeeper(address _keeper) external override onlyOwner { - if (_keeper == address(0)) revert Errors.ZeroAddress(); - - keeper = _keeper; - emit KeeperUpdated(_keeper); - } - - /// @inheritdoc IOsTokenVaultController - function cumulativeFeePerShare() external view override returns (uint256) { - // SLOAD to memory - uint256 currCumulativeFeePerShare = _cumulativeFeePerShare; - - // calculate rewards - uint256 profitAccrued = _unclaimedAssets(); - if (profitAccrued == 0) return currCumulativeFeePerShare; - - // calculate treasury assets - uint256 treasuryAssets = Math.mulDiv(profitAccrued, feePercent, _maxFeePercent); - if (treasuryAssets == 0) return currCumulativeFeePerShare; - - // SLOAD to memory - uint256 totalShares_ = _totalShares; - - // calculate treasury shares - uint256 treasuryShares; - unchecked { - treasuryShares = _convertToShares( - treasuryAssets, - totalShares_, - // cannot underflow because profitAccrued >= treasuryAssets - _totalAssets + profitAccrued - treasuryAssets, - Math.Rounding.Floor - ); + + /// @inheritdoc IOsTokenVaultController + function setCapacity(uint256 _capacity) public override onlyOwner { + // update os token capacity + capacity = _capacity; + emit CapacityUpdated(_capacity); } - return currCumulativeFeePerShare + Math.mulDiv(treasuryShares, _wad, totalShares_); - } + /// @inheritdoc IOsTokenVaultController + function setTreasury(address _treasury) public override onlyOwner { + if (_treasury == address(0)) revert Errors.ZeroAddress(); + + // update DAO treasury address + treasury = _treasury; + emit TreasuryUpdated(_treasury); + } - /// @inheritdoc IOsTokenVaultController - function updateState() public override { - // calculate rewards - uint256 profitAccrued = _unclaimedAssets(); + /// @inheritdoc IOsTokenVaultController + function setFeePercent(uint16 _feePercent) public override onlyOwner { + if (_feePercent > _maxFeePercent) revert Errors.InvalidFeePercent(); + // pull reward with the current fee percent + updateState(); + + // update fee percent + feePercent = _feePercent; + emit FeePercentUpdated(_feePercent); + } + + /// @inheritdoc IOsTokenVaultController + function setAvgRewardPerSecond(uint256 _avgRewardPerSecond) external override { + if (msg.sender != keeper) revert Errors.AccessDenied(); + + updateState(); + avgRewardPerSecond = _avgRewardPerSecond; + emit AvgRewardPerSecondUpdated(_avgRewardPerSecond); + } + + /// @inheritdoc IOsTokenVaultController + function setKeeper(address _keeper) external override onlyOwner { + if (_keeper == address(0)) revert Errors.ZeroAddress(); + + keeper = _keeper; + emit KeeperUpdated(_keeper); + } + + /// @inheritdoc IOsTokenVaultController + function cumulativeFeePerShare() external view override returns (uint256) { + // SLOAD to memory + uint256 currCumulativeFeePerShare = _cumulativeFeePerShare; + + // calculate rewards + uint256 profitAccrued = _unclaimedAssets(); + if (profitAccrued == 0) return currCumulativeFeePerShare; + + // calculate treasury assets + uint256 treasuryAssets = Math.mulDiv(profitAccrued, feePercent, _maxFeePercent); + if (treasuryAssets == 0) return currCumulativeFeePerShare; + + // SLOAD to memory + uint256 totalShares_ = _totalShares; + + // calculate treasury shares + uint256 treasuryShares; + unchecked { + treasuryShares = _convertToShares( + treasuryAssets, + totalShares_, + // cannot underflow because profitAccrued >= treasuryAssets + _totalAssets + profitAccrued - treasuryAssets, + Math.Rounding.Floor + ); + } + + return currCumulativeFeePerShare + Math.mulDiv(treasuryShares, _wad, totalShares_); + } - // check whether any profit accrued - if (profitAccrued == 0) { - if (_lastUpdateTimestamp != block.timestamp) { + /// @inheritdoc IOsTokenVaultController + function updateState() public override { + // calculate rewards + uint256 profitAccrued = _unclaimedAssets(); + + // check whether any profit accrued + if (profitAccrued == 0) { + if (_lastUpdateTimestamp != block.timestamp) { + _lastUpdateTimestamp = uint64(block.timestamp); + } + return; + } + + // calculate treasury assets + uint256 newTotalAssets = _totalAssets + profitAccrued; + uint256 treasuryAssets = Math.mulDiv(profitAccrued, feePercent, _maxFeePercent); + if (treasuryAssets == 0) { + // no treasury assets + _lastUpdateTimestamp = uint64(block.timestamp); + _totalAssets = SafeCast.toUint128(newTotalAssets); + return; + } + + // SLOAD to memory + uint256 totalShares_ = _totalShares; + + // calculate treasury shares + uint256 treasuryShares; + unchecked { + treasuryShares = _convertToShares( + treasuryAssets, + totalShares_, + // cannot underflow because newTotalAssets >= treasuryAssets + newTotalAssets - treasuryAssets, + Math.Rounding.Floor + ); + } + + // SLOAD to memory + address _treasury = treasury; + + // mint shares to the fee recipient + IOsToken(_osToken).mint(_treasury, treasuryShares); + + // update state + _cumulativeFeePerShare += SafeCast.toUint192(Math.mulDiv(treasuryShares, _wad, totalShares_)); _lastUpdateTimestamp = uint64(block.timestamp); - } - return; + _totalAssets = SafeCast.toUint128(newTotalAssets); + _totalShares = SafeCast.toUint128(totalShares_ + treasuryShares); + emit StateUpdated(profitAccrued, treasuryShares, treasuryAssets); } - // calculate treasury assets - uint256 newTotalAssets = _totalAssets + profitAccrued; - uint256 treasuryAssets = Math.mulDiv(profitAccrued, feePercent, _maxFeePercent); - if (treasuryAssets == 0) { - // no treasury assets - _lastUpdateTimestamp = uint64(block.timestamp); - _totalAssets = SafeCast.toUint128(newTotalAssets); - return; + /** + * @dev Internal conversion function (from assets to shares) with support for rounding direction. + */ + function _convertToShares(uint256 assets, uint256 totalShares_, uint256 totalAssets_, Math.Rounding rounding) + internal + pure + returns (uint256 shares) + { + // Will revert if assets > 0, totalShares > 0 and totalAssets = 0. + // That corresponds to a case where any asset would represent an infinite amount of shares. + return (assets == 0 || totalShares_ == 0) ? assets : Math.mulDiv(assets, totalShares_, totalAssets_, rounding); } - // SLOAD to memory - uint256 totalShares_ = _totalShares; - - // calculate treasury shares - uint256 treasuryShares; - unchecked { - treasuryShares = _convertToShares( - treasuryAssets, - totalShares_, - // cannot underflow because newTotalAssets >= treasuryAssets - newTotalAssets - treasuryAssets, - Math.Rounding.Floor - ); + /** + * @dev Internal conversion function (from shares to assets) with support for rounding direction. + */ + function _convertToAssets(uint256 shares, uint256 totalShares_, uint256 totalAssets_, Math.Rounding rounding) + internal + pure + returns (uint256) + { + return (totalShares_ == 0) ? shares : Math.mulDiv(shares, totalAssets_, totalShares_, rounding); } - // SLOAD to memory - address _treasury = treasury; - - // mint shares to the fee recipient - IOsToken(_osToken).mint(_treasury, treasuryShares); - - // update state - _cumulativeFeePerShare += SafeCast.toUint192(Math.mulDiv(treasuryShares, _wad, totalShares_)); - _lastUpdateTimestamp = uint64(block.timestamp); - _totalAssets = SafeCast.toUint128(newTotalAssets); - _totalShares = SafeCast.toUint128(totalShares_ + treasuryShares); - emit StateUpdated(profitAccrued, treasuryShares, treasuryAssets); - } - - /** - * @dev Internal conversion function (from assets to shares) with support for rounding direction. - */ - function _convertToShares( - uint256 assets, - uint256 totalShares_, - uint256 totalAssets_, - Math.Rounding rounding - ) internal pure returns (uint256 shares) { - // Will revert if assets > 0, totalShares > 0 and totalAssets = 0. - // That corresponds to a case where any asset would represent an infinite amount of shares. - return - (assets == 0 || totalShares_ == 0) - ? assets - : Math.mulDiv(assets, totalShares_, totalAssets_, rounding); - } - - /** - * @dev Internal conversion function (from shares to assets) with support for rounding direction. - */ - function _convertToAssets( - uint256 shares, - uint256 totalShares_, - uint256 totalAssets_, - Math.Rounding rounding - ) internal pure returns (uint256) { - return (totalShares_ == 0) ? shares : Math.mulDiv(shares, totalAssets_, totalShares_, rounding); - } - - /** - * @dev Internal function for calculating assets accumulated since last update - */ - function _unclaimedAssets() internal view returns (uint256) { - // calculate time passed since the last update - uint256 timeElapsed; - unchecked { - // cannot realistically underflow - timeElapsed = block.timestamp - _lastUpdateTimestamp; + /** + * @dev Internal function for calculating assets accumulated since last update + */ + function _unclaimedAssets() internal view returns (uint256) { + // calculate time passed since the last update + uint256 timeElapsed; + unchecked { + // cannot realistically underflow + timeElapsed = block.timestamp - _lastUpdateTimestamp; + } + if (timeElapsed == 0) return 0; + return Math.mulDiv(avgRewardPerSecond * _totalAssets, timeElapsed, _wad); } - if (timeElapsed == 0) return 0; - return Math.mulDiv(avgRewardPerSecond * _totalAssets, timeElapsed, _wad); - } } diff --git a/contracts/tokens/OsTokenVaultEscrow.sol b/contracts/tokens/OsTokenVaultEscrow.sol index 67e51373..0c0a4812 100644 --- a/contracts/tokens/OsTokenVaultEscrow.sol +++ b/contracts/tokens/OsTokenVaultEscrow.sol @@ -2,16 +2,16 @@ pragma solidity ^0.8.22; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {IOsTokenVaultEscrow} from '../interfaces/IOsTokenVaultEscrow.sol'; -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; -import {IVaultEnterExit} from '../interfaces/IVaultEnterExit.sol'; -import {IOsTokenConfig} from '../interfaces/IOsTokenConfig.sol'; -import {IOsTokenVaultEscrowAuth} from '../interfaces/IOsTokenVaultEscrowAuth.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {Multicall} from '../base/Multicall.sol'; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IOsTokenVaultEscrow} from "../interfaces/IOsTokenVaultEscrow.sol"; +import {IOsTokenVaultController} from "../interfaces/IOsTokenVaultController.sol"; +import {IVaultEnterExit} from "../interfaces/IVaultEnterExit.sol"; +import {IOsTokenConfig} from "../interfaces/IOsTokenConfig.sol"; +import {IOsTokenVaultEscrowAuth} from "../interfaces/IOsTokenVaultEscrowAuth.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {Multicall} from "../base/Multicall.sol"; /** * @title OsTokenVaultEscrow @@ -19,353 +19,287 @@ import {Multicall} from '../base/Multicall.sol'; * @notice Used for initiating assets exits from the vault without burning osToken */ abstract contract OsTokenVaultEscrow is Ownable2Step, Multicall, IOsTokenVaultEscrow { - uint256 private constant _maxPercent = 1e18; - uint256 private constant _wad = 1e18; - uint256 private constant _hfLiqThreshold = 1e18; - - IOsTokenVaultController private immutable _osTokenVaultController; - IOsTokenConfig private immutable _osTokenConfig; - - mapping(address vault => mapping(uint256 positionTicket => Position)) private _positions; - - /// @inheritdoc IOsTokenVaultEscrow - uint256 public override liqBonusPercent; - - /// @inheritdoc IOsTokenVaultEscrow - address public override authenticator; - - /// @inheritdoc IOsTokenVaultEscrow - uint64 public override liqThresholdPercent; - - /** - * @dev Constructor - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param initialOwner The address of the contract owner - * @param _authenticator The address of the OsTokenVaultEscrowAuth contract - * @param _liqThresholdPercent The liquidation threshold percent - * @param _liqBonusPercent The liquidation bonus percent - */ - constructor( - address osTokenVaultController, - address osTokenConfig, - address initialOwner, - address _authenticator, - uint64 _liqThresholdPercent, - uint256 _liqBonusPercent - ) Ownable(msg.sender) { - _osTokenVaultController = IOsTokenVaultController(osTokenVaultController); - _osTokenConfig = IOsTokenConfig(osTokenConfig); - updateLiqConfig(_liqThresholdPercent, _liqBonusPercent); - setAuthenticator(_authenticator); - _transferOwnership(initialOwner); - } - - /// @inheritdoc IOsTokenVaultEscrow - function getPosition( - address vault, - uint256 positionTicket - ) external view returns (address, uint256, uint256) { - Position memory position = _positions[vault][positionTicket]; - if (position.osTokenShares != 0) { - _syncPositionFee(position); - } - return (position.owner, position.exitedAssets, position.osTokenShares); - } - - /// @inheritdoc IOsTokenVaultEscrow - function register( - address owner, - uint256 exitPositionTicket, - uint256 osTokenShares, - uint256 cumulativeFeePerShare - ) external override { - // check if caller has permission - if ( - !IOsTokenVaultEscrowAuth(authenticator).canRegister( - msg.sender, - owner, - exitPositionTicket, - osTokenShares - ) - ) { - revert Errors.AccessDenied(); + uint256 private constant _maxPercent = 1e18; + uint256 private constant _wad = 1e18; + uint256 private constant _hfLiqThreshold = 1e18; + + IOsTokenVaultController private immutable _osTokenVaultController; + IOsTokenConfig private immutable _osTokenConfig; + + mapping(address vault => mapping(uint256 positionTicket => Position)) private _positions; + + /// @inheritdoc IOsTokenVaultEscrow + uint256 public override liqBonusPercent; + + /// @inheritdoc IOsTokenVaultEscrow + address public override authenticator; + + /// @inheritdoc IOsTokenVaultEscrow + uint64 public override liqThresholdPercent; + + /** + * @dev Constructor + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param initialOwner The address of the contract owner + * @param _authenticator The address of the OsTokenVaultEscrowAuth contract + * @param _liqThresholdPercent The liquidation threshold percent + * @param _liqBonusPercent The liquidation bonus percent + */ + constructor( + address osTokenVaultController, + address osTokenConfig, + address initialOwner, + address _authenticator, + uint64 _liqThresholdPercent, + uint256 _liqBonusPercent + ) Ownable(msg.sender) { + _osTokenVaultController = IOsTokenVaultController(osTokenVaultController); + _osTokenConfig = IOsTokenConfig(osTokenConfig); + updateLiqConfig(_liqThresholdPercent, _liqBonusPercent); + setAuthenticator(_authenticator); + _transferOwnership(initialOwner); } - // check owner and shares are not zero - if (owner == address(0)) revert Errors.ZeroAddress(); - if (osTokenShares == 0) revert Errors.InvalidShares(); - - // create new position - _positions[msg.sender][exitPositionTicket] = Position({ - owner: owner, - exitedAssets: 0, - osTokenShares: SafeCast.toUint128(osTokenShares), - cumulativeFeePerShare: SafeCast.toUint128(cumulativeFeePerShare) - }); - - // emit event - emit PositionCreated( - msg.sender, - exitPositionTicket, - owner, - osTokenShares, - cumulativeFeePerShare - ); - } - - /// @inheritdoc IOsTokenVaultEscrow - function processExitedAssets( - address vault, - uint256 exitPositionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external override { - // get position - Position storage position = _positions[vault][exitPositionTicket]; - if (position.owner == address(0)) revert Errors.InvalidPosition(); - - // claim exited assets - (uint256 leftTickets, , uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( - address(this), - exitPositionTicket, - timestamp, - uint256(exitQueueIndex) - ); - // the exit request must be fully processed (1 ticket could be a rounding error) - if (leftTickets > 1) revert Errors.ExitRequestNotProcessed(); - IVaultEnterExit(vault).claimExitedAssets( - exitPositionTicket, - timestamp, - uint256(exitQueueIndex) - ); - - // update position - position.exitedAssets = SafeCast.toUint96(exitedAssets); - - // emit event - emit ExitedAssetsProcessed(vault, msg.sender, exitPositionTicket, exitedAssets); - } - - /// @inheritdoc IOsTokenVaultEscrow - function claimExitedAssets( - address vault, - uint256 exitPositionTicket, - uint256 osTokenShares - ) external override returns (uint256 claimedAssets) { - // burn osToken shares - _osTokenVaultController.burnShares(msg.sender, osTokenShares); - - // fetch user position - Position memory position = _positions[vault][exitPositionTicket]; - if (msg.sender != position.owner) revert Errors.AccessDenied(); - - // check whether position exists and there are enough osToken shares - _syncPositionFee(position); - if (position.osTokenShares == 0 || position.osTokenShares < osTokenShares) { - revert Errors.InvalidShares(); + /// @inheritdoc IOsTokenVaultEscrow + function getPosition(address vault, uint256 positionTicket) external view returns (address, uint256, uint256) { + Position memory position = _positions[vault][positionTicket]; + if (position.osTokenShares != 0) { + _syncPositionFee(position); + } + return (position.owner, position.exitedAssets, position.osTokenShares); } - // calculate assets to withdraw - if (position.osTokenShares != osTokenShares) { - claimedAssets = Math.mulDiv(position.exitedAssets, osTokenShares, position.osTokenShares); + /// @inheritdoc IOsTokenVaultEscrow + function register(address owner, uint256 exitPositionTicket, uint256 osTokenShares, uint256 cumulativeFeePerShare) + external + override + { + // check if caller has permission + if (!IOsTokenVaultEscrowAuth(authenticator).canRegister(msg.sender, owner, exitPositionTicket, osTokenShares)) { + revert Errors.AccessDenied(); + } + + // check owner and shares are not zero + if (owner == address(0)) revert Errors.ZeroAddress(); + if (osTokenShares == 0) revert Errors.InvalidShares(); - // update position osTokenShares - position.exitedAssets -= SafeCast.toUint96(claimedAssets); - position.osTokenShares -= SafeCast.toUint128(osTokenShares); - _positions[vault][exitPositionTicket] = position; - } else { - claimedAssets = position.exitedAssets; + // create new position + _positions[msg.sender][exitPositionTicket] = Position({ + owner: owner, + exitedAssets: 0, + osTokenShares: SafeCast.toUint128(osTokenShares), + cumulativeFeePerShare: SafeCast.toUint128(cumulativeFeePerShare) + }); - // remove position as it is fully processed - delete _positions[vault][exitPositionTicket]; + // emit event + emit PositionCreated(msg.sender, exitPositionTicket, owner, osTokenShares, cumulativeFeePerShare); } - if (claimedAssets == 0) revert Errors.ExitRequestNotProcessed(); - - // transfer assets - _transferAssets(position.owner, claimedAssets); - - // emit event - emit ExitedAssetsClaimed(msg.sender, vault, exitPositionTicket, osTokenShares, claimedAssets); - } - - /// @inheritdoc IOsTokenVaultEscrow - function liquidateOsToken( - address vault, - uint256 exitPositionTicket, - uint256 osTokenShares, - address receiver - ) external override { - uint256 receivedAssets = _redeemOsToken( - vault, - exitPositionTicket, - receiver, - osTokenShares, - true - ); - emit OsTokenLiquidated( - msg.sender, - vault, - exitPositionTicket, - receiver, - osTokenShares, - receivedAssets - ); - } - - /// @inheritdoc IOsTokenVaultEscrow - function redeemOsToken( - address vault, - uint256 exitPositionTicket, - uint256 osTokenShares, - address receiver - ) external override { - if (msg.sender != _osTokenConfig.redeemer()) revert Errors.AccessDenied(); - uint256 receivedAssets = _redeemOsToken( - vault, - exitPositionTicket, - receiver, - osTokenShares, - false - ); - emit OsTokenRedeemed( - msg.sender, - vault, - exitPositionTicket, - receiver, - osTokenShares, - receivedAssets - ); - } - - /// @inheritdoc IOsTokenVaultEscrow - function setAuthenticator(address newAuthenticator) public override onlyOwner { - if (authenticator == newAuthenticator) revert Errors.ValueNotChanged(); - authenticator = newAuthenticator; - emit AuthenticatorUpdated(newAuthenticator); - } - - /// @inheritdoc IOsTokenVaultEscrow - function updateLiqConfig( - uint64 _liqThresholdPercent, - uint256 _liqBonusPercent - ) public override onlyOwner { - // validate liquidation threshold percent - if (_liqThresholdPercent == 0 || _liqThresholdPercent >= _maxPercent) { - revert Errors.InvalidLiqThresholdPercent(); + + /// @inheritdoc IOsTokenVaultEscrow + function processExitedAssets(address vault, uint256 exitPositionTicket, uint256 timestamp, uint256 exitQueueIndex) + external + override + { + // get position + Position storage position = _positions[vault][exitPositionTicket]; + if (position.owner == address(0)) revert Errors.InvalidPosition(); + + // claim exited assets + (uint256 leftTickets,, uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( + address(this), exitPositionTicket, timestamp, uint256(exitQueueIndex) + ); + // the exit request must be fully processed (1 ticket could be a rounding error) + if (leftTickets > 1) revert Errors.ExitRequestNotProcessed(); + IVaultEnterExit(vault).claimExitedAssets(exitPositionTicket, timestamp, uint256(exitQueueIndex)); + + // update position + position.exitedAssets = SafeCast.toUint96(exitedAssets); + + // emit event + emit ExitedAssetsProcessed(vault, msg.sender, exitPositionTicket, exitedAssets); } - // validate liquidation bonus percent - if ( - _liqBonusPercent < _maxPercent || - Math.mulDiv(_liqThresholdPercent, _liqBonusPercent, _maxPercent) > _maxPercent - ) { - revert Errors.InvalidLiqBonusPercent(); + /// @inheritdoc IOsTokenVaultEscrow + function claimExitedAssets(address vault, uint256 exitPositionTicket, uint256 osTokenShares) + external + override + returns (uint256 claimedAssets) + { + // burn osToken shares + _osTokenVaultController.burnShares(msg.sender, osTokenShares); + + // fetch user position + Position memory position = _positions[vault][exitPositionTicket]; + if (msg.sender != position.owner) revert Errors.AccessDenied(); + + // check whether position exists and there are enough osToken shares + _syncPositionFee(position); + if (position.osTokenShares == 0 || position.osTokenShares < osTokenShares) { + revert Errors.InvalidShares(); + } + + // calculate assets to withdraw + if (position.osTokenShares != osTokenShares) { + claimedAssets = Math.mulDiv(position.exitedAssets, osTokenShares, position.osTokenShares); + + // update position osTokenShares + position.exitedAssets -= SafeCast.toUint96(claimedAssets); + position.osTokenShares -= SafeCast.toUint128(osTokenShares); + _positions[vault][exitPositionTicket] = position; + } else { + claimedAssets = position.exitedAssets; + + // remove position as it is fully processed + delete _positions[vault][exitPositionTicket]; + } + if (claimedAssets == 0) revert Errors.ExitRequestNotProcessed(); + + // transfer assets + _transferAssets(position.owner, claimedAssets); + + // emit event + emit ExitedAssetsClaimed(msg.sender, vault, exitPositionTicket, osTokenShares, claimedAssets); } - // update config - liqThresholdPercent = _liqThresholdPercent; - liqBonusPercent = _liqBonusPercent; - - // emit event - emit LiqConfigUpdated(_liqThresholdPercent, _liqBonusPercent); - } - - /** - * @dev Internal function for redeeming osToken shares - * @param vault The address of the vault - * @param exitPositionTicket The position ticket of the exit queue - * @param receiver The address of the receiver of the redeemed assets - * @param osTokenShares The amount of osToken shares to redeem - * @param isLiquidation Whether the redeem is a liquidation - * @return receivedAssets The amount of assets received - */ - function _redeemOsToken( - address vault, - uint256 exitPositionTicket, - address receiver, - uint256 osTokenShares, - bool isLiquidation - ) private returns (uint256 receivedAssets) { - if (receiver == address(0)) revert Errors.ZeroAddress(); - - // update osToken state for gas efficiency - _osTokenVaultController.updateState(); - - // fetch user position - Position memory position = _positions[vault][exitPositionTicket]; - if (position.osTokenShares == 0) revert Errors.InvalidPosition(); - _syncPositionFee(position); - - // calculate received assets - if (isLiquidation) { - receivedAssets = Math.mulDiv( - _osTokenVaultController.convertToAssets(osTokenShares), - liqBonusPercent, - _maxPercent - ); - } else { - receivedAssets = _osTokenVaultController.convertToAssets(osTokenShares); + /// @inheritdoc IOsTokenVaultEscrow + function liquidateOsToken(address vault, uint256 exitPositionTicket, uint256 osTokenShares, address receiver) + external + override + { + uint256 receivedAssets = _redeemOsToken(vault, exitPositionTicket, receiver, osTokenShares, true); + emit OsTokenLiquidated(msg.sender, vault, exitPositionTicket, receiver, osTokenShares, receivedAssets); } + /// @inheritdoc IOsTokenVaultEscrow + function redeemOsToken(address vault, uint256 exitPositionTicket, uint256 osTokenShares, address receiver) + external + override { - // check whether received assets are valid - if (receivedAssets > position.exitedAssets) { - revert Errors.InvalidReceivedAssets(); - } - - if (isLiquidation) { - // check health factor violation in case of liquidation - uint256 mintedAssets = _osTokenVaultController.convertToAssets(position.osTokenShares); + if (msg.sender != _osTokenConfig.redeemer()) revert Errors.AccessDenied(); + uint256 receivedAssets = _redeemOsToken(vault, exitPositionTicket, receiver, osTokenShares, false); + emit OsTokenRedeemed(msg.sender, vault, exitPositionTicket, receiver, osTokenShares, receivedAssets); + } + + /// @inheritdoc IOsTokenVaultEscrow + function setAuthenticator(address newAuthenticator) public override onlyOwner { + if (authenticator == newAuthenticator) revert Errors.ValueNotChanged(); + authenticator = newAuthenticator; + emit AuthenticatorUpdated(newAuthenticator); + } + + /// @inheritdoc IOsTokenVaultEscrow + function updateLiqConfig(uint64 _liqThresholdPercent, uint256 _liqBonusPercent) public override onlyOwner { + // validate liquidation threshold percent + if (_liqThresholdPercent == 0 || _liqThresholdPercent >= _maxPercent) { + revert Errors.InvalidLiqThresholdPercent(); + } + + // validate liquidation bonus percent if ( - Math.mulDiv( - position.exitedAssets * _wad, - liqThresholdPercent, - mintedAssets * _maxPercent - ) >= _hfLiqThreshold + _liqBonusPercent < _maxPercent + || Math.mulDiv(_liqThresholdPercent, _liqBonusPercent, _maxPercent) > _maxPercent ) { - revert Errors.InvalidHealthFactor(); + revert Errors.InvalidLiqBonusPercent(); + } + + // update config + liqThresholdPercent = _liqThresholdPercent; + liqBonusPercent = _liqBonusPercent; + + // emit event + emit LiqConfigUpdated(_liqThresholdPercent, _liqBonusPercent); + } + + /** + * @dev Internal function for redeeming osToken shares + * @param vault The address of the vault + * @param exitPositionTicket The position ticket of the exit queue + * @param receiver The address of the receiver of the redeemed assets + * @param osTokenShares The amount of osToken shares to redeem + * @param isLiquidation Whether the redeem is a liquidation + * @return receivedAssets The amount of assets received + */ + function _redeemOsToken( + address vault, + uint256 exitPositionTicket, + address receiver, + uint256 osTokenShares, + bool isLiquidation + ) private returns (uint256 receivedAssets) { + if (receiver == address(0)) revert Errors.ZeroAddress(); + + // update osToken state for gas efficiency + _osTokenVaultController.updateState(); + + // fetch user position + Position memory position = _positions[vault][exitPositionTicket]; + if (position.osTokenShares == 0) revert Errors.InvalidPosition(); + _syncPositionFee(position); + + // calculate received assets + if (isLiquidation) { + receivedAssets = + Math.mulDiv(_osTokenVaultController.convertToAssets(osTokenShares), liqBonusPercent, _maxPercent); + } else { + receivedAssets = _osTokenVaultController.convertToAssets(osTokenShares); } - } + + { + // check whether received assets are valid + if (receivedAssets > position.exitedAssets) { + revert Errors.InvalidReceivedAssets(); + } + + if (isLiquidation) { + // check health factor violation in case of liquidation + uint256 mintedAssets = _osTokenVaultController.convertToAssets(position.osTokenShares); + if ( + Math.mulDiv(position.exitedAssets * _wad, liqThresholdPercent, mintedAssets * _maxPercent) + >= _hfLiqThreshold + ) { + revert Errors.InvalidHealthFactor(); + } + } + } + + // reduce osToken supply + _osTokenVaultController.burnShares(msg.sender, osTokenShares); + + // update position + position.exitedAssets -= SafeCast.toUint96(receivedAssets); + position.osTokenShares -= SafeCast.toUint128(osTokenShares); + _positions[vault][exitPositionTicket] = position; + + // transfer assets to the receiver + _transferAssets(receiver, receivedAssets); + } + + /** + * @dev Internal function for syncing the osToken fee + * @param position The position to sync the fee for + */ + function _syncPositionFee(Position memory position) private view { + // fetch current cumulative fee per share + uint256 cumulativeFeePerShare = _osTokenVaultController.cumulativeFeePerShare(); + + // check whether fee is already up to date + if (cumulativeFeePerShare == position.cumulativeFeePerShare) return; + + // add treasury fee to the position + position.osTokenShares = SafeCast.toUint128( + Math.mulDiv(position.osTokenShares, cumulativeFeePerShare, position.cumulativeFeePerShare) + ); + position.cumulativeFeePerShare = SafeCast.toUint128(cumulativeFeePerShare); } - // reduce osToken supply - _osTokenVaultController.burnShares(msg.sender, osTokenShares); - - // update position - position.exitedAssets -= SafeCast.toUint96(receivedAssets); - position.osTokenShares -= SafeCast.toUint128(osTokenShares); - _positions[vault][exitPositionTicket] = position; - - // transfer assets to the receiver - _transferAssets(receiver, receivedAssets); - } - - /** - * @dev Internal function for syncing the osToken fee - * @param position The position to sync the fee for - */ - function _syncPositionFee(Position memory position) private view { - // fetch current cumulative fee per share - uint256 cumulativeFeePerShare = _osTokenVaultController.cumulativeFeePerShare(); - - // check whether fee is already up to date - if (cumulativeFeePerShare == position.cumulativeFeePerShare) return; - - // add treasury fee to the position - position.osTokenShares = SafeCast.toUint128( - Math.mulDiv(position.osTokenShares, cumulativeFeePerShare, position.cumulativeFeePerShare) - ); - position.cumulativeFeePerShare = SafeCast.toUint128(cumulativeFeePerShare); - } - - /** - * @dev Internal function for transferring assets from the Vault to the receiver - * @dev IMPORTANT: because control is transferred to the receiver, care must be - * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: - * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern - * @param receiver The address that will receive the assets - * @param assets The number of assets to transfer - */ - function _transferAssets(address receiver, uint256 assets) internal virtual; + /** + * @dev Internal function for transferring assets from the Vault to the receiver + * @dev IMPORTANT: because control is transferred to the receiver, care must be + * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: + * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern + * @param receiver The address that will receive the assets + * @param assets The number of assets to transfer + */ + function _transferAssets(address receiver, uint256 assets) internal virtual; } diff --git a/contracts/tokens/PriceFeed.sol b/contracts/tokens/PriceFeed.sol index d6d7b985..84be5353 100644 --- a/contracts/tokens/PriceFeed.sol +++ b/contracts/tokens/PriceFeed.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol'; -import {IChainlinkV3Aggregator} from '../interfaces/IChainlinkV3Aggregator.sol'; -import {IBalancerRateProvider} from '../interfaces/IBalancerRateProvider.sol'; -import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; +import {IChainlinkAggregator} from "../interfaces/IChainlinkAggregator.sol"; +import {IChainlinkV3Aggregator} from "../interfaces/IChainlinkV3Aggregator.sol"; +import {IBalancerRateProvider} from "../interfaces/IBalancerRateProvider.sol"; +import {IOsTokenVaultController} from "../interfaces/IOsTokenVaultController.sol"; /** * @title PriceFeed @@ -13,60 +13,54 @@ import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol * @notice Price feed for osToken (e.g osETH price in ETH) */ contract PriceFeed is IBalancerRateProvider, IChainlinkAggregator, IChainlinkV3Aggregator { - error NotImplemented(); + error NotImplemented(); - /// @inheritdoc IChainlinkV3Aggregator - uint256 public constant override version = 0; + /// @inheritdoc IChainlinkV3Aggregator + uint256 public constant override version = 0; - address public immutable osTokenVaultController; + address public immutable osTokenVaultController; - /// @inheritdoc IChainlinkV3Aggregator - string public override description; + /// @inheritdoc IChainlinkV3Aggregator + string public override description; - /** - * @dev Constructor - * @param _osTokenVaultController The address of the OsTokenVaultController contract - * @param _description The description of the price feed - */ - constructor(address _osTokenVaultController, string memory _description) { - osTokenVaultController = _osTokenVaultController; - description = _description; - } + /** + * @dev Constructor + * @param _osTokenVaultController The address of the OsTokenVaultController contract + * @param _description The description of the price feed + */ + constructor(address _osTokenVaultController, string memory _description) { + osTokenVaultController = _osTokenVaultController; + description = _description; + } - /// @inheritdoc IBalancerRateProvider - function getRate() public view override returns (uint256) { - return IOsTokenVaultController(osTokenVaultController).convertToAssets(10 ** decimals()); - } + /// @inheritdoc IBalancerRateProvider + function getRate() public view override returns (uint256) { + return IOsTokenVaultController(osTokenVaultController).convertToAssets(10 ** decimals()); + } - /// @inheritdoc IChainlinkAggregator - function latestAnswer() public view override returns (int256) { - uint256 value = getRate(); - // cannot realistically overflow, but better to check - return (value > uint256(type(int256).max)) ? type(int256).max : int256(value); - } + /// @inheritdoc IChainlinkAggregator + function latestAnswer() public view override returns (int256) { + uint256 value = getRate(); + // cannot realistically overflow, but better to check + return (value > uint256(type(int256).max)) ? type(int256).max : int256(value); + } - /// @inheritdoc IChainlinkAggregator - function latestTimestamp() external view returns (uint256) { - return block.timestamp; - } + /// @inheritdoc IChainlinkAggregator + function latestTimestamp() external view returns (uint256) { + return block.timestamp; + } - /// @inheritdoc IChainlinkV3Aggregator - function decimals() public pure returns (uint8) { - return 18; - } + /// @inheritdoc IChainlinkV3Aggregator + function decimals() public pure returns (uint8) { + return 18; + } - /// @inheritdoc IChainlinkV3Aggregator - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return (0, latestAnswer(), block.timestamp, block.timestamp, 0); - } + /// @inheritdoc IChainlinkV3Aggregator + function latestRoundData() + external + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, latestAnswer(), block.timestamp, block.timestamp, 0); + } } diff --git a/contracts/validators/ConsolidationsChecker.sol b/contracts/validators/ConsolidationsChecker.sol index 6ae24b37..315aff2e 100644 --- a/contracts/validators/ConsolidationsChecker.sol +++ b/contracts/validators/ConsolidationsChecker.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; -import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; -import {IConsolidationsChecker} from '../interfaces/IConsolidationsChecker.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {IKeeper} from '../interfaces/IKeeper.sol'; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +import {IConsolidationsChecker} from "../interfaces/IConsolidationsChecker.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {IKeeper} from "../interfaces/IKeeper.sol"; /** * @title ConsolidationsChecker @@ -14,92 +14,92 @@ import {IKeeper} from '../interfaces/IKeeper.sol'; * @notice Defines the functionality for checking signatures of oracles for validators consolidations */ contract ConsolidationsChecker is EIP712, IConsolidationsChecker { - uint256 private constant _signatureLength = 65; - bytes32 private constant _consolidationsCheckerTypeHash = - keccak256('ConsolidationsChecker(address vault,bytes validators)'); + uint256 private constant _signatureLength = 65; + bytes32 private constant _consolidationsCheckerTypeHash = + keccak256("ConsolidationsChecker(address vault,bytes validators)"); - IKeeper private immutable _keeper; + IKeeper private immutable _keeper; - /** - * @dev Constructor - * @param keeper The address of the Keeper contract - */ - constructor(address keeper) EIP712('ConsolidationsChecker', '1') { - _keeper = IKeeper(keeper); - } - - /// @inheritdoc IConsolidationsChecker - function verifySignatures( - address vault, - bytes calldata validators, - bytes calldata signatures - ) external view override { - if (!isValidSignatures(vault, validators, signatures)) { - revert Errors.InvalidSignatures(); + /** + * @dev Constructor + * @param keeper The address of the Keeper contract + */ + constructor(address keeper) EIP712("ConsolidationsChecker", "1") { + _keeper = IKeeper(keeper); } - } - - /// @inheritdoc IConsolidationsChecker - function isValidSignatures( - address vault, - bytes calldata validators, - bytes calldata signatures - ) public view override returns (bool) { - return - _isValidSignatures( - _keeper.validatorsMinOracles(), - keccak256(abi.encode(_consolidationsCheckerTypeHash, vault, keccak256(validators))), - signatures - ); - } - /** - * @notice Internal function for verifying oracles' signatures - * @param requiredSignatures The number of signatures required for the verification to pass - * @param message The message that was signed - * @param signatures The concatenation of the oracles' signatures - * @return True if the signatures are valid, otherwise false - */ - function _isValidSignatures( - uint256 requiredSignatures, - bytes32 message, - bytes calldata signatures - ) private view returns (bool) { - if (requiredSignatures == 0) { - return false; + /// @inheritdoc IConsolidationsChecker + function verifySignatures(address vault, bytes calldata validators, bytes calldata signatures) + external + view + override + { + if (!isValidSignatures(vault, validators, signatures)) { + revert Errors.InvalidSignatures(); + } } - // check whether enough signatures - unchecked { - // cannot realistically overflow - if (signatures.length < requiredSignatures * _signatureLength) { - return false; - } + /// @inheritdoc IConsolidationsChecker + function isValidSignatures(address vault, bytes calldata validators, bytes calldata signatures) + public + view + override + returns (bool) + { + return _isValidSignatures( + _keeper.validatorsMinOracles(), + keccak256(abi.encode(_consolidationsCheckerTypeHash, vault, keccak256(validators))), + signatures + ); } - bytes32 data = _hashTypedDataV4(message); - address lastOracle; - address currentOracle; - uint256 startIndex; - for (uint256 i = 0; i < requiredSignatures; i++) { - unchecked { - // cannot overflow as signatures.length is checked above - currentOracle = ECDSA.recover(data, signatures[startIndex:startIndex + _signatureLength]); - } - // signatures must be sorted by oracles' addresses and not repeat - if (currentOracle <= lastOracle || !_keeper.isOracle(currentOracle)) { - return false; - } + /** + * @notice Internal function for verifying oracles' signatures + * @param requiredSignatures The number of signatures required for the verification to pass + * @param message The message that was signed + * @param signatures The concatenation of the oracles' signatures + * @return True if the signatures are valid, otherwise false + */ + function _isValidSignatures(uint256 requiredSignatures, bytes32 message, bytes calldata signatures) + private + view + returns (bool) + { + if (requiredSignatures == 0) { + return false; + } - // update last oracle - lastOracle = currentOracle; + // check whether enough signatures + unchecked { + // cannot realistically overflow + if (signatures.length < requiredSignatures * _signatureLength) { + return false; + } + } - unchecked { - // cannot realistically overflow - startIndex += _signatureLength; - } - } + bytes32 data = _hashTypedDataV4(message); + address lastOracle; + address currentOracle; + uint256 startIndex; + for (uint256 i = 0; i < requiredSignatures; i++) { + unchecked { + // cannot overflow as signatures.length is checked above + currentOracle = ECDSA.recover(data, signatures[startIndex:startIndex + _signatureLength]); + } + // signatures must be sorted by oracles' addresses and not repeat + if (currentOracle <= lastOracle || !_keeper.isOracle(currentOracle)) { + return false; + } - return true; - } + // update last oracle + lastOracle = currentOracle; + + unchecked { + // cannot realistically overflow + startIndex += _signatureLength; + } + } + + return true; + } } diff --git a/contracts/validators/DepositDataRegistry.sol b/contracts/validators/DepositDataRegistry.sol index 5243a527..8b119ccd 100644 --- a/contracts/validators/DepositDataRegistry.sol +++ b/contracts/validators/DepositDataRegistry.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {IDepositDataRegistry} from '../interfaces/IDepositDataRegistry.sol'; -import {IKeeperValidators} from '../interfaces/IKeeperValidators.sol'; -import {IVaultAdmin} from '../interfaces/IVaultAdmin.sol'; -import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; -import {IVaultVersion} from '../interfaces/IVaultVersion.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {IVaultState} from '../interfaces/IVaultState.sol'; -import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {Multicall} from '../base/Multicall.sol'; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +import {IDepositDataRegistry} from "../interfaces/IDepositDataRegistry.sol"; +import {IKeeperValidators} from "../interfaces/IKeeperValidators.sol"; +import {IVaultAdmin} from "../interfaces/IVaultAdmin.sol"; +import {IVaultValidators} from "../interfaces/IVaultValidators.sol"; +import {IVaultVersion} from "../interfaces/IVaultVersion.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {IVaultState} from "../interfaces/IVaultState.sol"; +import {IKeeperRewards} from "../interfaces/IKeeperRewards.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {Multicall} from "../base/Multicall.sol"; /** * @title DepositDataRegistry @@ -20,176 +20,165 @@ import {Multicall} from '../base/Multicall.sol'; * @notice Defines the functionality for the Vault's deposit data management */ contract DepositDataRegistry is Multicall, IDepositDataRegistry { - IVaultsRegistry private immutable _vaultsRegistry; + IVaultsRegistry private immutable _vaultsRegistry; - /// @inheritdoc IDepositDataRegistry - mapping(address => uint256) public override depositDataIndexes; + /// @inheritdoc IDepositDataRegistry + mapping(address => uint256) public override depositDataIndexes; - /// @inheritdoc IDepositDataRegistry - mapping(address => bytes32) public override depositDataRoots; + /// @inheritdoc IDepositDataRegistry + mapping(address => bytes32) public override depositDataRoots; - mapping(address => address) private _depositDataManagers; - mapping(address => bool) private _migrated; + mapping(address => address) private _depositDataManagers; + mapping(address => bool) private _migrated; - /** - * @dev Modifier to check if the caller is a valid vault - * @param vault The address of the vault - */ - modifier onlyValidVault(address vault) { - if (!_vaultsRegistry.vaults(vault) || IVaultVersion(vault).version() < 2) { - revert Errors.InvalidVault(); + /** + * @dev Modifier to check if the caller is a valid vault + * @param vault The address of the vault + */ + modifier onlyValidVault(address vault) { + if (!_vaultsRegistry.vaults(vault) || IVaultVersion(vault).version() < 2) { + revert Errors.InvalidVault(); + } + _; } - _; - } - - /** - * @dev Constructor - * @param vaultsRegistry The address of the vaults registry contract - */ - constructor(address vaultsRegistry) { - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - } - - /// @inheritdoc IDepositDataRegistry - function getDepositDataManager(address vault) public view override returns (address) { - address depositDataManager = _depositDataManagers[vault]; - return depositDataManager == address(0) ? IVaultAdmin(vault).admin() : depositDataManager; - } - - /// @inheritdoc IDepositDataRegistry - function setDepositDataManager( - address vault, - address depositDataManager - ) external override onlyValidVault(vault) { - // only vault admin can set deposit data manager - if (msg.sender != IVaultAdmin(vault).admin()) revert Errors.AccessDenied(); - - // update deposit data manager - _depositDataManagers[vault] = depositDataManager; - emit DepositDataManagerUpdated(vault, depositDataManager); - } - - /// @inheritdoc IDepositDataRegistry - function setDepositDataRoot( - address vault, - bytes32 depositDataRoot - ) external override onlyValidVault(vault) { - if (msg.sender != getDepositDataManager(vault)) revert Errors.AccessDenied(); - if (depositDataRoots[vault] == depositDataRoot) revert Errors.ValueNotChanged(); - - depositDataRoots[vault] = depositDataRoot; - // reset validator index on every root update - depositDataIndexes[vault] = 0; - emit DepositDataRootUpdated(vault, depositDataRoot); - } - - /// @inheritdoc IDepositDataRegistry - function updateVaultState( - address vault, - IKeeperRewards.HarvestParams calldata harvestParams - ) external override { - IVaultState(vault).updateState(harvestParams); - } - - /// @inheritdoc IDepositDataRegistry - function registerValidator( - address vault, - IKeeperValidators.ApprovalParams calldata keeperParams, - bytes32[] calldata proof - ) external override onlyValidVault(vault) { - // register validator - IVaultValidators(vault).registerValidators(keeperParams, ''); - - // SLOAD to memory - uint256 currentIndex = depositDataIndexes[vault]; - bytes32 depositDataRoot = depositDataRoots[vault]; - - // check matches merkle root and next validator index - if ( - !MerkleProof.verifyCalldata( - proof, - depositDataRoot, - keccak256(bytes.concat(keccak256(abi.encode(keeperParams.validators, currentIndex)))) - ) - ) { - revert Errors.InvalidProof(); + + /** + * @dev Constructor + * @param vaultsRegistry The address of the vaults registry contract + */ + constructor(address vaultsRegistry) { + _vaultsRegistry = IVaultsRegistry(vaultsRegistry); } - // increment index for the next validator - unchecked { - // cannot realistically overflow - depositDataIndexes[vault] = currentIndex + 1; + /// @inheritdoc IDepositDataRegistry + function getDepositDataManager(address vault) public view override returns (address) { + address depositDataManager = _depositDataManagers[vault]; + return depositDataManager == address(0) ? IVaultAdmin(vault).admin() : depositDataManager; } - } - - /// @inheritdoc IDepositDataRegistry - function registerValidators( - address vault, - IKeeperValidators.ApprovalParams calldata keeperParams, - uint256[] calldata indexes, - bool[] calldata proofFlags, - bytes32[] calldata proof - ) external override onlyValidVault(vault) { - // register validator - IVaultValidators(vault).registerValidators(keeperParams, ''); - - // SLOAD to memory - uint256 currentIndex = depositDataIndexes[vault]; - - // define leaves for multiproof - uint256 validatorsCount = indexes.length; - if (validatorsCount == 0) revert Errors.InvalidValidators(); - - // calculate validator length - uint256 validatorLength = keeperParams.validators.length / validatorsCount; - if (validatorLength == 0) revert Errors.InvalidValidators(); - - // calculate leaves - bytes32[] memory leaves = new bytes32[](validatorsCount); - { - uint256 startIndex; - uint256 endIndex; - for (uint256 i = 0; i < validatorsCount; ) { - endIndex += validatorLength; - leaves[indexes[i]] = keccak256( - bytes.concat( - keccak256(abi.encode(keeperParams.validators[startIndex:endIndex], currentIndex)) - ) - ); - - startIndex = endIndex; + + /// @inheritdoc IDepositDataRegistry + function setDepositDataManager(address vault, address depositDataManager) external override onlyValidVault(vault) { + // only vault admin can set deposit data manager + if (msg.sender != IVaultAdmin(vault).admin()) revert Errors.AccessDenied(); + + // update deposit data manager + _depositDataManagers[vault] = depositDataManager; + emit DepositDataManagerUpdated(vault, depositDataManager); + } + + /// @inheritdoc IDepositDataRegistry + function setDepositDataRoot(address vault, bytes32 depositDataRoot) external override onlyValidVault(vault) { + if (msg.sender != getDepositDataManager(vault)) revert Errors.AccessDenied(); + if (depositDataRoots[vault] == depositDataRoot) revert Errors.ValueNotChanged(); + + depositDataRoots[vault] = depositDataRoot; + // reset validator index on every root update + depositDataIndexes[vault] = 0; + emit DepositDataRootUpdated(vault, depositDataRoot); + } + + /// @inheritdoc IDepositDataRegistry + function updateVaultState(address vault, IKeeperRewards.HarvestParams calldata harvestParams) external override { + IVaultState(vault).updateState(harvestParams); + } + + /// @inheritdoc IDepositDataRegistry + function registerValidator( + address vault, + IKeeperValidators.ApprovalParams calldata keeperParams, + bytes32[] calldata proof + ) external override onlyValidVault(vault) { + // register validator + IVaultValidators(vault).registerValidators(keeperParams, ""); + + // SLOAD to memory + uint256 currentIndex = depositDataIndexes[vault]; + bytes32 depositDataRoot = depositDataRoots[vault]; + + // check matches merkle root and next validator index + if ( + !MerkleProof.verifyCalldata( + proof, + depositDataRoot, + keccak256(bytes.concat(keccak256(abi.encode(keeperParams.validators, currentIndex)))) + ) + ) { + revert Errors.InvalidProof(); + } + + // increment index for the next validator unchecked { - // cannot realistically overflow - ++currentIndex; - ++i; + // cannot realistically overflow + depositDataIndexes[vault] = currentIndex + 1; } - } } - // increment index for the next validator - depositDataIndexes[vault] = currentIndex; + /// @inheritdoc IDepositDataRegistry + function registerValidators( + address vault, + IKeeperValidators.ApprovalParams calldata keeperParams, + uint256[] calldata indexes, + bool[] calldata proofFlags, + bytes32[] calldata proof + ) external override onlyValidVault(vault) { + // register validator + IVaultValidators(vault).registerValidators(keeperParams, ""); + + // SLOAD to memory + uint256 currentIndex = depositDataIndexes[vault]; + + // define leaves for multiproof + uint256 validatorsCount = indexes.length; + if (validatorsCount == 0) revert Errors.InvalidValidators(); + + // calculate validator length + uint256 validatorLength = keeperParams.validators.length / validatorsCount; + if (validatorLength == 0) revert Errors.InvalidValidators(); + + // calculate leaves + bytes32[] memory leaves = new bytes32[](validatorsCount); + { + uint256 startIndex; + uint256 endIndex; + for (uint256 i = 0; i < validatorsCount;) { + endIndex += validatorLength; + leaves[indexes[i]] = keccak256( + bytes.concat(keccak256(abi.encode(keeperParams.validators[startIndex:endIndex], currentIndex))) + ); + + startIndex = endIndex; + unchecked { + // cannot realistically overflow + ++currentIndex; + ++i; + } + } + } + + // increment index for the next validator + depositDataIndexes[vault] = currentIndex; + + // check matches merkle root and next validator index + bytes32 depositDataRoot = depositDataRoots[vault]; + if (!MerkleProof.multiProofVerifyCalldata(proof, proofFlags, depositDataRoot, leaves)) { + revert Errors.InvalidProof(); + } + } + + /// @inheritdoc IDepositDataRegistry + function migrate(bytes32 depositDataRoot, uint256 validatorIndex, address depositDataManager) + external + override + onlyValidVault(msg.sender) + { + if (_migrated[msg.sender]) revert Errors.AccessDenied(); + + depositDataRoots[msg.sender] = depositDataRoot; + depositDataIndexes[msg.sender] = validatorIndex; + _depositDataManagers[msg.sender] = depositDataManager; - // check matches merkle root and next validator index - bytes32 depositDataRoot = depositDataRoots[vault]; - if (!MerkleProof.multiProofVerifyCalldata(proof, proofFlags, depositDataRoot, leaves)) { - revert Errors.InvalidProof(); + // only allow migration once + _migrated[msg.sender] = true; + emit DepositDataMigrated(msg.sender, depositDataRoot, validatorIndex, depositDataManager); } - } - - /// @inheritdoc IDepositDataRegistry - function migrate( - bytes32 depositDataRoot, - uint256 validatorIndex, - address depositDataManager - ) external override onlyValidVault(msg.sender) { - if (_migrated[msg.sender]) revert Errors.AccessDenied(); - - depositDataRoots[msg.sender] = depositDataRoot; - depositDataIndexes[msg.sender] = validatorIndex; - _depositDataManagers[msg.sender] = depositDataManager; - - // only allow migration once - _migrated[msg.sender] = true; - emit DepositDataMigrated(msg.sender, depositDataRoot, validatorIndex, depositDataManager); - } } diff --git a/contracts/validators/EthValidatorsChecker.sol b/contracts/validators/EthValidatorsChecker.sol index 32d0a210..24eb350f 100644 --- a/contracts/validators/EthValidatorsChecker.sol +++ b/contracts/validators/EthValidatorsChecker.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.22; -import {ValidatorsChecker} from './ValidatorsChecker.sol'; +import {ValidatorsChecker} from "./ValidatorsChecker.sol"; /** * @title EthValidatorsChecker @@ -10,27 +10,24 @@ import {ValidatorsChecker} from './ValidatorsChecker.sol'; * @notice Defines functionality for checking validators registration on Ethereum */ contract EthValidatorsChecker is ValidatorsChecker { - /** - * @dev Constructor - * @param validatorsRegistry The address of the beacon chain validators registry contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param depositDataRegistry The address of the DepositDataRegistry contract - */ - constructor( - address validatorsRegistry, - address keeper, - address vaultsRegistry, - address depositDataRegistry - ) ValidatorsChecker(validatorsRegistry, keeper, vaultsRegistry, depositDataRegistry) {} + /** + * @dev Constructor + * @param validatorsRegistry The address of the beacon chain validators registry contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param depositDataRegistry The address of the DepositDataRegistry contract + */ + constructor(address validatorsRegistry, address keeper, address vaultsRegistry, address depositDataRegistry) + ValidatorsChecker(validatorsRegistry, keeper, vaultsRegistry, depositDataRegistry) + {} - /// @inheritdoc ValidatorsChecker - function _depositAmount() internal pure override returns (uint256) { - return 32 ether; - } + /// @inheritdoc ValidatorsChecker + function _depositAmount() internal pure override returns (uint256) { + return 32 ether; + } - /// @inheritdoc ValidatorsChecker - function _vaultAssets(address vault) internal view override returns (uint256) { - return address(vault).balance; - } + /// @inheritdoc ValidatorsChecker + function _vaultAssets(address vault) internal view override returns (uint256) { + return address(vault).balance; + } } diff --git a/contracts/validators/GnoValidatorsChecker.sol b/contracts/validators/GnoValidatorsChecker.sol index 530a5da3..b8dc7c0e 100644 --- a/contracts/validators/GnoValidatorsChecker.sol +++ b/contracts/validators/GnoValidatorsChecker.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {ValidatorsChecker} from './ValidatorsChecker.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ValidatorsChecker} from "./ValidatorsChecker.sol"; /** * @title GnoValidatorsChecker @@ -11,33 +11,33 @@ import {ValidatorsChecker} from './ValidatorsChecker.sol'; * @notice Defines functionality for checking validators registration on Gnosis */ contract GnoValidatorsChecker is ValidatorsChecker { - address private immutable _gnoToken; + address private immutable _gnoToken; - /** - * @dev Constructor - * @param validatorsRegistry The address of the beacon chain validators registry contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param gnoToken The address of the Gnosis token contract - */ - constructor( - address validatorsRegistry, - address keeper, - address vaultsRegistry, - address depositDataRegistry, - address gnoToken - ) ValidatorsChecker(validatorsRegistry, keeper, vaultsRegistry, depositDataRegistry) { - _gnoToken = gnoToken; - } + /** + * @dev Constructor + * @param validatorsRegistry The address of the beacon chain validators registry contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param gnoToken The address of the Gnosis token contract + */ + constructor( + address validatorsRegistry, + address keeper, + address vaultsRegistry, + address depositDataRegistry, + address gnoToken + ) ValidatorsChecker(validatorsRegistry, keeper, vaultsRegistry, depositDataRegistry) { + _gnoToken = gnoToken; + } - /// @inheritdoc ValidatorsChecker - function _depositAmount() internal pure override returns (uint256) { - return 1 ether; - } + /// @inheritdoc ValidatorsChecker + function _depositAmount() internal pure override returns (uint256) { + return 1 ether; + } - /// @inheritdoc ValidatorsChecker - function _vaultAssets(address vault) internal view override returns (uint256) { - return IERC20(_gnoToken).balanceOf(vault); - } + /// @inheritdoc ValidatorsChecker + function _vaultAssets(address vault) internal view override returns (uint256) { + return IERC20(_gnoToken).balanceOf(vault); + } } diff --git a/contracts/validators/ValidatorsChecker.sol b/contracts/validators/ValidatorsChecker.sol index 1e728a09..9383fd9b 100644 --- a/contracts/validators/ValidatorsChecker.sol +++ b/contracts/validators/ValidatorsChecker.sol @@ -2,24 +2,24 @@ pragma solidity ^0.8.22; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {IDepositDataRegistry} from '../interfaces/IDepositDataRegistry.sol'; -import {IKeeper} from '../interfaces/IKeeper.sol'; -import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; -import {IValidatorsChecker} from '../interfaces/IValidatorsChecker.sol'; -import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; -import {IVaultState} from '../interfaces/IVaultState.sol'; -import {IVaultValidators} from '../interfaces/IVaultValidators.sol'; -import {IVaultVersion} from '../interfaces/IVaultVersion.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {EIP712Utils} from '../libraries/EIP712Utils.sol'; -import {ValidatorUtils} from '../libraries/ValidatorUtils.sol'; -import {Multicall} from '../base/Multicall.sol'; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +import {IDepositDataRegistry} from "../interfaces/IDepositDataRegistry.sol"; +import {IKeeper} from "../interfaces/IKeeper.sol"; +import {IKeeperRewards} from "../interfaces/IKeeperRewards.sol"; +import {IValidatorsChecker} from "../interfaces/IValidatorsChecker.sol"; +import {IValidatorsRegistry} from "../interfaces/IValidatorsRegistry.sol"; +import {IVaultState} from "../interfaces/IVaultState.sol"; +import {IVaultValidators} from "../interfaces/IVaultValidators.sol"; +import {IVaultVersion} from "../interfaces/IVaultVersion.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {EIP712Utils} from "../libraries/EIP712Utils.sol"; +import {ValidatorUtils} from "../libraries/ValidatorUtils.sol"; +import {Multicall} from "../base/Multicall.sol"; interface IVaultValidatorsV1 { - function validatorsRoot() external view returns (bytes32); - function validatorIndex() external view returns (uint256); + function validatorsRoot() external view returns (bytes32); + function validatorIndex() external view returns (uint256); } /** @@ -30,232 +30,212 @@ interface IVaultValidatorsV1 { * * checking deposit data root */ abstract contract ValidatorsChecker is Multicall, IValidatorsChecker { - IValidatorsRegistry private immutable _validatorsRegistry; - IKeeper private immutable _keeper; - IVaultsRegistry private immutable _vaultsRegistry; - IDepositDataRegistry private immutable _depositDataRegistry; - - /** - * @dev Constructor - * @param validatorsRegistry The address of the beacon chain validators registry contract - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param depositDataRegistry The address of the DepositDataRegistry contract - */ - constructor( - address validatorsRegistry, - address keeper, - address vaultsRegistry, - address depositDataRegistry - ) { - _validatorsRegistry = IValidatorsRegistry(validatorsRegistry); - _keeper = IKeeper(keeper); - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - _depositDataRegistry = IDepositDataRegistry(depositDataRegistry); - } - - /// @inheritdoc IValidatorsChecker - function updateVaultState( - address vault, - IKeeperRewards.HarvestParams calldata harvestParams - ) external override { - IVaultState(vault).updateState(harvestParams); - } - - /// @inheritdoc IValidatorsChecker - function getExitQueueCumulativeTickets(address vault) external view override returns (uint256) { - ( - uint128 queuedShares, - , - uint128 totalExitingTickets, - , - uint256 totalTickets - ) = IVaultValidators(vault).getExitQueueData(); - return totalTickets + queuedShares + totalExitingTickets; - } + IValidatorsRegistry private immutable _validatorsRegistry; + IKeeper private immutable _keeper; + IVaultsRegistry private immutable _vaultsRegistry; + IDepositDataRegistry private immutable _depositDataRegistry; + + /** + * @dev Constructor + * @param validatorsRegistry The address of the beacon chain validators registry contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param depositDataRegistry The address of the DepositDataRegistry contract + */ + constructor(address validatorsRegistry, address keeper, address vaultsRegistry, address depositDataRegistry) { + _validatorsRegistry = IValidatorsRegistry(validatorsRegistry); + _keeper = IKeeper(keeper); + _vaultsRegistry = IVaultsRegistry(vaultsRegistry); + _depositDataRegistry = IDepositDataRegistry(depositDataRegistry); + } + + /// @inheritdoc IValidatorsChecker + function updateVaultState(address vault, IKeeperRewards.HarvestParams calldata harvestParams) external override { + IVaultState(vault).updateState(harvestParams); + } + + /// @inheritdoc IValidatorsChecker + function getExitQueueCumulativeTickets(address vault) external view override returns (uint256) { + (uint128 queuedShares,, uint128 totalExitingTickets,, uint256 totalTickets) = + IVaultValidators(vault).getExitQueueData(); + return totalTickets + queuedShares + totalExitingTickets; + } + + /// @inheritdoc IValidatorsChecker + function getExitQueueMissingAssets(address vault, uint256 withdrawingAssets, uint256 targetCumulativeTickets) + external + view + override + returns (uint256 missingAssets) + { + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = IVaultValidators(vault).getExitQueueData(); + // check whether already covered + if (totalTickets >= targetCumulativeTickets) { + return 0; + } - /// @inheritdoc IValidatorsChecker - function getExitQueueMissingAssets( - address vault, - uint256 withdrawingAssets, - uint256 targetCumulativeTickets - ) external view override returns (uint256 missingAssets) { - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = IVaultValidators(vault).getExitQueueData(); - // check whether already covered - if (totalTickets >= targetCumulativeTickets) { - return 0; - } + // calculate the amount of tickets that need to be covered + uint256 totalTicketsToCover = targetCumulativeTickets - totalTickets; - // calculate the amount of tickets that need to be covered - uint256 totalTicketsToCover = targetCumulativeTickets - totalTickets; + // calculate missing assets from legacy exits + uint256 ticketsToCover; + if (totalExitingTickets > 0) { + ticketsToCover = Math.min(totalTicketsToCover, totalExitingTickets); + missingAssets = Math.mulDiv(ticketsToCover, totalExitingAssets, totalExitingTickets); + totalTicketsToCover -= ticketsToCover; + } - // calculate missing assets from legacy exits - uint256 ticketsToCover; - if (totalExitingTickets > 0) { - ticketsToCover = Math.min(totalTicketsToCover, totalExitingTickets); - missingAssets = Math.mulDiv(ticketsToCover, totalExitingAssets, totalExitingTickets); - totalTicketsToCover -= ticketsToCover; - } + // calculate missing assets from queued shares + if (totalTicketsToCover > 0 && queuedShares > 0) { + ticketsToCover = Math.min(totalTicketsToCover, queuedShares); + missingAssets += IVaultState(vault).convertToAssets(ticketsToCover); + } - // calculate missing assets from queued shares - if (totalTicketsToCover > 0 && queuedShares > 0) { - ticketsToCover = Math.min(totalTicketsToCover, queuedShares); - missingAssets += IVaultState(vault).convertToAssets(ticketsToCover); + // check whether there is enough available assets + uint256 availableAssets = withdrawingAssets + _vaultAssets(vault) - unclaimedAssets; + return availableAssets >= missingAssets ? 0 : missingAssets - availableAssets; } - // check whether there is enough available assets - uint256 availableAssets = withdrawingAssets + _vaultAssets(vault) - unclaimedAssets; - return availableAssets >= missingAssets ? 0 : missingAssets - availableAssets; - } + /// @inheritdoc IValidatorsChecker + function checkValidatorsManagerSignature( + address vault, + bytes32 validatorsRegistryRoot, + bytes calldata validators, + bytes calldata signature + ) external view override returns (uint256 blockNumber, Status status) { + if (_validatorsRegistry.get_deposit_root() != validatorsRegistryRoot) { + return (block.number, Status.INVALID_VALIDATORS_REGISTRY_ROOT); + } + if (!_vaultsRegistry.vaults(vault) || IVaultVersion(vault).version() < 2) { + return (block.number, Status.INVALID_VAULT); + } - /// @inheritdoc IValidatorsChecker - function checkValidatorsManagerSignature( - address vault, - bytes32 validatorsRegistryRoot, - bytes calldata validators, - bytes calldata signature - ) external view override returns (uint256 blockNumber, Status status) { - if (_validatorsRegistry.get_deposit_root() != validatorsRegistryRoot) { - return (block.number, Status.INVALID_VALIDATORS_REGISTRY_ROOT); - } - if (!_vaultsRegistry.vaults(vault) || IVaultVersion(vault).version() < 2) { - return (block.number, Status.INVALID_VAULT); - } + // verify vault has enough assets + if (!_keeper.isCollateralized(vault) && IVaultState(vault).withdrawableAssets() < _depositAmount()) { + return (block.number, Status.INSUFFICIENT_ASSETS); + } - // verify vault has enough assets - if ( - !_keeper.isCollateralized(vault) && IVaultState(vault).withdrawableAssets() < _depositAmount() - ) { - return (block.number, Status.INSUFFICIENT_ASSETS); - } + // validate signature + bool isValidSignature = ValidatorUtils.isValidManagerSignature( + validatorsRegistryRoot, + _computeVaultValidatorsDomain(vault), + IVaultValidators(vault).validatorsManager(), + validators, + signature + ); - // validate signature - bool isValidSignature = ValidatorUtils.isValidManagerSignature( - validatorsRegistryRoot, - _computeVaultValidatorsDomain(vault), - IVaultValidators(vault).validatorsManager(), - validators, - signature - ); + // verify validators manager ECDSA signature + if (!isValidSignature) { + return (block.number, Status.INVALID_SIGNATURE); + } - // verify validators manager ECDSA signature - if (!isValidSignature) { - return (block.number, Status.INVALID_SIGNATURE); + return (block.number, Status.SUCCEEDED); } - return (block.number, Status.SUCCEEDED); - } - - /// @inheritdoc IValidatorsChecker - function checkDepositDataRoot( - DepositDataRootCheckParams calldata params - ) external view override returns (uint256 blockNumber, Status status) { - if (_validatorsRegistry.get_deposit_root() != params.validatorsRegistryRoot) { - return (block.number, Status.INVALID_VALIDATORS_REGISTRY_ROOT); - } - if (!_vaultsRegistry.vaults(params.vault)) { - return (block.number, Status.INVALID_VAULT); - } + /// @inheritdoc IValidatorsChecker + function checkDepositDataRoot(DepositDataRootCheckParams calldata params) + external + view + override + returns (uint256 blockNumber, Status status) + { + if (_validatorsRegistry.get_deposit_root() != params.validatorsRegistryRoot) { + return (block.number, Status.INVALID_VALIDATORS_REGISTRY_ROOT); + } + if (!_vaultsRegistry.vaults(params.vault)) { + return (block.number, Status.INVALID_VAULT); + } - // verify vault has enough assets - if ( - !_keeper.isCollateralized(params.vault) && - IVaultState(params.vault).withdrawableAssets() < _depositAmount() - ) { - return (block.number, Status.INSUFFICIENT_ASSETS); - } + // verify vault has enough assets + if ( + !_keeper.isCollateralized(params.vault) && IVaultState(params.vault).withdrawableAssets() < _depositAmount() + ) { + return (block.number, Status.INSUFFICIENT_ASSETS); + } - uint8 vaultVersion = IVaultVersion(params.vault).version(); - if (vaultVersion >= 2) { - // verify vault did not set custom validators manager - if (IVaultValidators(params.vault).validatorsManager() != address(_depositDataRegistry)) { - return (block.number, Status.INVALID_VALIDATORS_MANAGER); - } - } + uint8 vaultVersion = IVaultVersion(params.vault).version(); + if (vaultVersion >= 2) { + // verify vault did not set custom validators manager + if (IVaultValidators(params.vault).validatorsManager() != address(_depositDataRegistry)) { + return (block.number, Status.INVALID_VALIDATORS_MANAGER); + } + } - uint256 currentIndex; - bytes32 depositDataRoot; + uint256 currentIndex; + bytes32 depositDataRoot; - if (vaultVersion >= 2) { - currentIndex = _depositDataRegistry.depositDataIndexes(params.vault); - depositDataRoot = _depositDataRegistry.depositDataRoots(params.vault); - } else { - currentIndex = IVaultValidatorsV1(params.vault).validatorIndex(); - depositDataRoot = IVaultValidatorsV1(params.vault).validatorsRoot(); - } + if (vaultVersion >= 2) { + currentIndex = _depositDataRegistry.depositDataIndexes(params.vault); + depositDataRoot = _depositDataRegistry.depositDataRoots(params.vault); + } else { + currentIndex = IVaultValidatorsV1(params.vault).validatorIndex(); + depositDataRoot = IVaultValidatorsV1(params.vault).validatorsRoot(); + } - // define leaves for multiproof - uint256 validatorsCount = params.proofIndexes.length; - if (validatorsCount == 0) { - return (block.number, Status.INVALID_VALIDATORS_COUNT); - } + // define leaves for multiproof + uint256 validatorsCount = params.proofIndexes.length; + if (validatorsCount == 0) { + return (block.number, Status.INVALID_VALIDATORS_COUNT); + } - // calculate validator length - uint256 validatorLength = params.validators.length / params.proofIndexes.length; - if (validatorLength == 0 || params.validators.length % validatorLength != 0) { - return (block.number, Status.INVALID_VALIDATORS_LENGTH); - } + // calculate validator length + uint256 validatorLength = params.validators.length / params.proofIndexes.length; + if (validatorLength == 0 || params.validators.length % validatorLength != 0) { + return (block.number, Status.INVALID_VALIDATORS_LENGTH); + } - // calculate leaves - bytes32[] memory leaves = new bytes32[](validatorsCount); - { - uint256 startIndex; - uint256 endIndex; - for (uint256 i = 0; i < validatorsCount; ) { - endIndex += validatorLength; - leaves[params.proofIndexes[i]] = keccak256( - bytes.concat(keccak256(abi.encode(params.validators[startIndex:endIndex], currentIndex))) - ); + // calculate leaves + bytes32[] memory leaves = new bytes32[](validatorsCount); + { + uint256 startIndex; + uint256 endIndex; + for (uint256 i = 0; i < validatorsCount;) { + endIndex += validatorLength; + leaves[params.proofIndexes[i]] = + keccak256(bytes.concat(keccak256(abi.encode(params.validators[startIndex:endIndex], currentIndex)))); + + startIndex = endIndex; + unchecked { + // cannot realistically overflow + ++currentIndex; + ++i; + } + } + } - startIndex = endIndex; - unchecked { - // cannot realistically overflow - ++currentIndex; - ++i; + // check matches merkle root and next validator index + if (!MerkleProof.multiProofVerifyCalldata(params.proof, params.proofFlags, depositDataRoot, leaves)) { + return (block.number, Status.INVALID_PROOF); } - } - } - // check matches merkle root and next validator index - if ( - !MerkleProof.multiProofVerifyCalldata( - params.proof, - params.proofFlags, - depositDataRoot, - leaves - ) - ) { - return (block.number, Status.INVALID_PROOF); + return (block.number, Status.SUCCEEDED); } - return (block.number, Status.SUCCEEDED); - } - - /** - * @notice Computes the hash of the EIP712 typed data for the vault - * @dev This function is used to compute the hash of the EIP712 typed data - * @return The hash of the EIP712 typed data - */ - function _computeVaultValidatorsDomain(address vault) private view returns (bytes32) { - return EIP712Utils.computeDomainSeparator('VaultValidators', vault); - } + /** + * @notice Computes the hash of the EIP712 typed data for the vault + * @dev This function is used to compute the hash of the EIP712 typed data + * @return The hash of the EIP712 typed data + */ + function _computeVaultValidatorsDomain(address vault) private view returns (bytes32) { + return EIP712Utils.computeDomainSeparator("VaultValidators", vault); + } - /** - * @notice Get the amount of assets required for validator deposit - * @return The amount of assets required for deposit - */ - function _depositAmount() internal pure virtual returns (uint256); + /** + * @notice Get the amount of assets required for validator deposit + * @return The amount of assets required for deposit + */ + function _depositAmount() internal pure virtual returns (uint256); - /** - * @notice Get the amount of assets in the vault - * @param vault The address of the vault - * @return The amount of assets in the vault - */ - function _vaultAssets(address vault) internal view virtual returns (uint256); + /** + * @notice Get the amount of assets in the vault + * @param vault The address of the vault + * @return The amount of assets in the vault + */ + function _vaultAssets(address vault) internal view virtual returns (uint256); } diff --git a/contracts/vaults/VaultsRegistry.sol b/contracts/vaults/VaultsRegistry.sol index c824858f..b8baf717 100644 --- a/contracts/vaults/VaultsRegistry.sol +++ b/contracts/vaults/VaultsRegistry.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; -import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; -import {Errors} from '../libraries/Errors.sol'; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {Errors} from "../libraries/Errors.sol"; /** * @title VaultsRegistry @@ -12,65 +12,65 @@ import {Errors} from '../libraries/Errors.sol'; * @notice Defines the registry functionality that keeps track of Vaults, Factories and Vault upgrades */ contract VaultsRegistry is Ownable2Step, IVaultsRegistry { - /// @inheritdoc IVaultsRegistry - mapping(address => bool) public override vaults; + /// @inheritdoc IVaultsRegistry + mapping(address => bool) public override vaults; - /// @inheritdoc IVaultsRegistry - mapping(address => bool) public override factories; + /// @inheritdoc IVaultsRegistry + mapping(address => bool) public override factories; - /// @inheritdoc IVaultsRegistry - mapping(address => bool) public override vaultImpls; + /// @inheritdoc IVaultsRegistry + mapping(address => bool) public override vaultImpls; - bool private _initialized; + bool private _initialized; - /** - * @dev Constructor - */ - constructor() Ownable(msg.sender) {} + /** + * @dev Constructor + */ + constructor() Ownable(msg.sender) {} - /// @inheritdoc IVaultsRegistry - function addVault(address vault) external override { - if (!factories[msg.sender] && msg.sender != owner()) revert Errors.AccessDenied(); + /// @inheritdoc IVaultsRegistry + function addVault(address vault) external override { + if (!factories[msg.sender] && msg.sender != owner()) revert Errors.AccessDenied(); - vaults[vault] = true; - emit VaultAdded(msg.sender, vault); - } + vaults[vault] = true; + emit VaultAdded(msg.sender, vault); + } - /// @inheritdoc IVaultsRegistry - function addVaultImpl(address newImpl) external override onlyOwner { - if (vaultImpls[newImpl]) revert Errors.AlreadyAdded(); - vaultImpls[newImpl] = true; - emit VaultImplAdded(newImpl); - } + /// @inheritdoc IVaultsRegistry + function addVaultImpl(address newImpl) external override onlyOwner { + if (vaultImpls[newImpl]) revert Errors.AlreadyAdded(); + vaultImpls[newImpl] = true; + emit VaultImplAdded(newImpl); + } - /// @inheritdoc IVaultsRegistry - function removeVaultImpl(address impl) external override onlyOwner { - if (!vaultImpls[impl]) revert Errors.AlreadyRemoved(); - vaultImpls[impl] = false; - emit VaultImplRemoved(impl); - } + /// @inheritdoc IVaultsRegistry + function removeVaultImpl(address impl) external override onlyOwner { + if (!vaultImpls[impl]) revert Errors.AlreadyRemoved(); + vaultImpls[impl] = false; + emit VaultImplRemoved(impl); + } - /// @inheritdoc IVaultsRegistry - function addFactory(address factory) external override onlyOwner { - if (factories[factory]) revert Errors.AlreadyAdded(); - factories[factory] = true; - emit FactoryAdded(factory); - } + /// @inheritdoc IVaultsRegistry + function addFactory(address factory) external override onlyOwner { + if (factories[factory]) revert Errors.AlreadyAdded(); + factories[factory] = true; + emit FactoryAdded(factory); + } - /// @inheritdoc IVaultsRegistry - function removeFactory(address factory) external override onlyOwner { - if (!factories[factory]) revert Errors.AlreadyRemoved(); - factories[factory] = false; - emit FactoryRemoved(factory); - } + /// @inheritdoc IVaultsRegistry + function removeFactory(address factory) external override onlyOwner { + if (!factories[factory]) revert Errors.AlreadyRemoved(); + factories[factory] = false; + emit FactoryRemoved(factory); + } - /// @inheritdoc IVaultsRegistry - function initialize(address _owner) external override onlyOwner { - if (_owner == address(0)) revert Errors.ZeroAddress(); - if (_initialized) revert Errors.AccessDenied(); + /// @inheritdoc IVaultsRegistry + function initialize(address _owner) external override onlyOwner { + if (_owner == address(0)) revert Errors.ZeroAddress(); + if (_initialized) revert Errors.AccessDenied(); - // transfer ownership - _transferOwnership(_owner); - _initialized = true; - } + // transfer ownership + _transferOwnership(_owner); + _initialized = true; + } } diff --git a/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol b/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol index 37d38873..fbaeabc1 100644 --- a/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol +++ b/contracts/vaults/ethereum/EthBlocklistErc20Vault.sol @@ -2,109 +2,110 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthBlocklistErc20Vault} from '../../interfaces/IEthBlocklistErc20Vault.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {VaultBlocklist} from '../modules/VaultBlocklist.sol'; -import {EthErc20Vault, IEthErc20Vault} from './EthErc20Vault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthBlocklistErc20Vault} from "../../interfaces/IEthBlocklistErc20Vault.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultEthStaking, IVaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {VaultBlocklist} from "../modules/VaultBlocklist.sol"; +import {EthErc20Vault, IEthErc20Vault} from "./EthErc20Vault.sol"; /** * @title EthBlocklistErc20Vault * @author StakeWise * @notice Defines the Ethereum staking Vault with blocking and ERC-20 functionality */ -contract EthBlocklistErc20Vault is - Initializable, - EthErc20Vault, - VaultBlocklist, - IEthBlocklistErc20Vault -{ - // slither-disable-next-line shadowing-state - uint8 private constant _version = 5; +contract EthBlocklistErc20Vault is Initializable, EthErc20Vault, VaultBlocklist, IEthBlocklistErc20Vault { + // slither-disable-next-line shadowing-state + uint8 private constant _version = 5; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthErc20Vault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(EthErc20VaultConstructorArgs memory args) EthErc20Vault(args) { - _disableInitializers(); - } - - /// @inheritdoc IEthErc20Vault - function initialize( - bytes calldata params - ) external payable virtual override(IEthErc20Vault, EthErc20Vault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 4 to 5 - if (admin != address(0)) { - __EthErc20Vault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthErc20Vault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthErc20VaultConstructorArgs memory args) EthErc20Vault(args) { + _disableInitializers(); } - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthErc20Vault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthErc20VaultInitParams)) - ); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(_admin); - } + /// @inheritdoc IEthErc20Vault + function initialize(bytes calldata params) + external + payable + virtual + override(IEthErc20Vault, EthErc20Vault) + reinitializer(_version) + { + // if admin is already set, it's an upgrade from version 4 to 5 + if (admin != address(0)) { + __EthErc20Vault_upgrade(); + return; + } - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(receiver, referrer); - } + // initialize deployed vault + address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); + __EthErc20Vault_init( + _admin, IEthVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (EthErc20VaultInitParams)) + ); + // blocklist manager is initially set to admin address + __VaultBlocklist_init(_admin); + } - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - _checkBlocklist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } + /// @inheritdoc IVaultEthStaking + function deposit(address receiver, address referrer) + public + payable + virtual + override(IVaultEthStaking, VaultEthStaking) + returns (uint256 shares) + { + _checkBlocklist(msg.sender); + _checkBlocklist(receiver); + return super.deposit(receiver, referrer); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkBlocklist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc VaultEthStaking + receive() external payable virtual override { + _checkBlocklist(msg.sender); + _deposit(msg.sender, msg.value, address(0)); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, EthErc20Vault) returns (bytes32) { - return keccak256('EthBlocklistErc20Vault'); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkBlocklist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthErc20Vault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, EthErc20Vault) returns (bytes32) { + return keccak256("EthBlocklistErc20Vault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, EthErc20Vault) returns (uint8) { + return _version; + } - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - _checkBlocklist(from); - _checkBlocklist(to); - super._transfer(from, to, amount); - } + /// @inheritdoc ERC20Upgradeable + function _transfer(address from, address to, uint256 amount) internal virtual override { + _checkBlocklist(from); + _checkBlocklist(to); + super._transfer(from, to, amount); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthBlocklistVault.sol b/contracts/vaults/ethereum/EthBlocklistVault.sol index a656eec5..0e58a4aa 100644 --- a/contracts/vaults/ethereum/EthBlocklistVault.sol +++ b/contracts/vaults/ethereum/EthBlocklistVault.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthBlocklistVault} from '../../interfaces/IEthBlocklistVault.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultBlocklist} from '../modules/VaultBlocklist.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {EthVault, IEthVault} from './EthVault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthBlocklistVault} from "../../interfaces/IEthBlocklistVault.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultEthStaking, IVaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultBlocklist} from "../modules/VaultBlocklist.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {EthVault, IEthVault} from "./EthVault.sol"; /** * @title EthBlocklistVault @@ -17,81 +17,85 @@ import {EthVault, IEthVault} from './EthVault.sol'; * @notice Defines the Ethereum staking Vault with blocking addresses functionality */ contract EthBlocklistVault is Initializable, EthVault, VaultBlocklist, IEthBlocklistVault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 5; + // slither-disable-next-line shadowing-state + uint8 private constant _version = 5; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthVault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(EthVaultConstructorArgs memory args) EthVault(args) { - _disableInitializers(); - } - - /// @inheritdoc IEthVault - function initialize( - bytes calldata params - ) external payable virtual override(IEthVault, EthVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 4 to 5 - if (admin != address(0)) { - __EthVault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthVaultConstructorArgs memory args) EthVault(args) { + _disableInitializers(); } - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthVault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthVaultInitParams)) - ); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(_admin); - } + /// @inheritdoc IEthVault + function initialize(bytes calldata params) + external + payable + virtual + override(IEthVault, EthVault) + reinitializer(_version) + { + // if admin is already set, it's an upgrade from version 4 to 5 + if (admin != address(0)) { + __EthVault_upgrade(); + return; + } + + // initialize deployed vault + address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); + __EthVault_init(_admin, IEthVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (EthVaultInitParams))); + // blocklist manager is initially set to admin address + __VaultBlocklist_init(_admin); + } - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(receiver, referrer); - } + /// @inheritdoc IVaultEthStaking + function deposit(address receiver, address referrer) + public + payable + virtual + override(IVaultEthStaking, VaultEthStaking) + returns (uint256 shares) + { + _checkBlocklist(msg.sender); + _checkBlocklist(receiver); + return super.deposit(receiver, referrer); + } - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - _checkBlocklist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } + /// @inheritdoc VaultEthStaking + receive() external payable virtual override { + _checkBlocklist(msg.sender); + _deposit(msg.sender, msg.value, address(0)); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkBlocklist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkBlocklist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, EthVault) returns (bytes32) { - return keccak256('EthBlocklistVault'); - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, EthVault) returns (bytes32) { + return keccak256("EthBlocklistVault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthVault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, EthVault) returns (uint8) { + return _version; + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthErc20Vault.sol b/contracts/vaults/ethereum/EthErc20Vault.sol index 9533b953..edf73921 100644 --- a/contracts/vaults/ethereum/EthErc20Vault.sol +++ b/contracts/vaults/ethereum/EthErc20Vault.sol @@ -2,25 +2,25 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IEthErc20Vault} from '../../interfaces/IEthErc20Vault.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {Multicall} from '../../base/Multicall.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultValidators} from '../modules/VaultValidators.sol'; -import {VaultAdmin} from '../modules/VaultAdmin.sol'; -import {VaultFee} from '../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {VaultImmutables} from '../modules/VaultImmutables.sol'; -import {VaultState} from '../modules/VaultState.sol'; -import {VaultEnterExit, IVaultEnterExit} from '../modules/VaultEnterExit.sol'; -import {VaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultMev} from '../modules/VaultMev.sol'; -import {VaultToken} from '../modules/VaultToken.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IEthErc20Vault} from "../../interfaces/IEthErc20Vault.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {Multicall} from "../../base/Multicall.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultValidators} from "../modules/VaultValidators.sol"; +import {VaultAdmin} from "../modules/VaultAdmin.sol"; +import {VaultFee} from "../modules/VaultFee.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {VaultImmutables} from "../modules/VaultImmutables.sol"; +import {VaultState} from "../modules/VaultState.sol"; +import {VaultEnterExit, IVaultEnterExit} from "../modules/VaultEnterExit.sol"; +import {VaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultMev} from "../modules/VaultMev.sol"; +import {VaultToken} from "../modules/VaultToken.sol"; /** * @title EthErc20Vault @@ -28,206 +28,183 @@ import {VaultToken} from '../modules/VaultToken.sol'; * @notice Defines the Ethereum staking Vault with ERC-20 token */ contract EthErc20Vault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultOsToken, - VaultMev, - VaultToken, - VaultEthStaking, - Multicall, - IEthErc20Vault + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultValidators, + VaultEnterExit, + VaultOsToken, + VaultMev, + VaultToken, + VaultEthStaking, + Multicall, + IEthErc20Vault { - uint8 private constant _version = 5; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthErc20Vault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - EthErc20VaultConstructorArgs memory args - ) - VaultImmutables(args.keeper, args.vaultsRegistry) - VaultValidators( - args.depositDataRegistry, - args.validatorsRegistry, - args.validatorsWithdrawals, - args.validatorsConsolidations, - args.consolidationsChecker - ) - VaultEnterExit(args.exitingAssetsClaimDelay) - VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) - VaultMev(args.sharedMevEscrow) - { - _disableInitializers(); - } - - /// @inheritdoc IEthErc20Vault - function initialize( - bytes calldata params - ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 4 to 5 - if (admin != address(0)) { - __EthErc20Vault_upgrade(); - return; + uint8 private constant _version = 5; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthErc20Vault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthErc20VaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) + { + _disableInitializers(); } - // initialize deployed vault - __EthErc20Vault_init( - IEthVaultFactory(msg.sender).vaultAdmin(), - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthErc20VaultInitParams)) - ); - } - - /// @inheritdoc IEthErc20Vault - function depositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public payable override returns (uint256) { - deposit(msg.sender, referrer); - return mintOsToken(receiver, osTokenShares, referrer); - } - - /// @inheritdoc IEthErc20Vault - function updateStateAndDepositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer, - IKeeperRewards.HarvestParams calldata harvestParams - ) external payable override returns (uint256) { - updateState(harvestParams); - return depositAndMintOsToken(receiver, osTokenShares, referrer); - } - - /// @inheritdoc IERC20 - function transfer( - address to, - uint256 amount - ) public virtual override(IERC20, ERC20Upgradeable) returns (bool) { - bool success = super.transfer(to, amount); - _checkOsTokenPosition(msg.sender); - return success; - } - - /// @inheritdoc IERC20 - function transferFrom( - address from, - address to, - uint256 amount - ) public virtual override(IERC20, ERC20Upgradeable) returns (bool) { - bool success = super.transferFrom(from, to, amount); - _checkOsTokenPosition(from); - return success; - } - - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) - public - virtual - override(IVaultEnterExit, VaultEnterExit, VaultOsToken) - returns (uint256 positionTicket) - { - positionTicket = super.enterExitQueue(shares, receiver); - emit Transfer(msg.sender, address(this), shares); - } - - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('EthErc20Vault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } - - /// @inheritdoc VaultState - function _updateExitQueue() - internal - virtual - override(VaultState, VaultToken) - returns (uint256 burnedShares) - { - return super._updateExitQueue(); - } - - /// @inheritdoc VaultState - function _mintShares( - address owner, - uint256 shares - ) internal virtual override(VaultState, VaultToken) { - super._mintShares(owner, shares); - } - - /// @inheritdoc VaultState - function _burnShares( - address owner, - uint256 shares - ) internal virtual override(VaultState, VaultToken) { - super._burnShares(owner, shares); - } - - /// @inheritdoc VaultValidators - function _checkCanWithdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) internal override { - if ( - !_isValidatorsManager( - validators, - bytes32(validatorsManagerNonce), - validatorsManagerSignature - ) && msg.sender != _osTokenConfig.redeemer() - ) { - revert Errors.AccessDenied(); + /// @inheritdoc IEthErc20Vault + function initialize(bytes calldata params) external payable virtual override reinitializer(_version) { + // if admin is already set, it's an upgrade from version 4 to 5 + if (admin != address(0)) { + __EthErc20Vault_upgrade(); + return; + } + + // initialize deployed vault + __EthErc20Vault_init( + IEthVaultFactory(msg.sender).vaultAdmin(), + IEthVaultFactory(msg.sender).ownMevEscrow(), + abi.decode(params, (EthErc20VaultInitParams)) + ); } - } - - /** - * @dev Upgrades the EthErc20Vault contract - */ - function __EthErc20Vault_upgrade() internal { - __VaultValidators_upgrade(); - } - - /** - * @dev Initializes the EthErc20Vault contract - * @param admin The address of the admin of the Vault - * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. - * @param params The decoded parameters for initializing the EthErc20Vault contract - */ - function __EthErc20Vault_init( - address admin, - address ownMevEscrow, - EthErc20VaultInitParams memory params - ) internal onlyInitializing { - __VaultAdmin_init(admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(ownMevEscrow); - __VaultToken_init(params.name, params.symbol); - __VaultEthStaking_init(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + + /// @inheritdoc IEthErc20Vault + function depositAndMintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + payable + override + returns (uint256) + { + deposit(msg.sender, referrer); + return mintOsToken(receiver, osTokenShares, referrer); + } + + /// @inheritdoc IEthErc20Vault + function updateStateAndDepositAndMintOsToken( + address receiver, + uint256 osTokenShares, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable override returns (uint256) { + updateState(harvestParams); + return depositAndMintOsToken(receiver, osTokenShares, referrer); + } + + /// @inheritdoc IERC20 + function transfer(address to, uint256 amount) public virtual override(IERC20, ERC20Upgradeable) returns (bool) { + bool success = super.transfer(to, amount); + _checkOsTokenPosition(msg.sender); + return success; + } + + /// @inheritdoc IERC20 + function transferFrom(address from, address to, uint256 amount) + public + virtual + override(IERC20, ERC20Upgradeable) + returns (bool) + { + bool success = super.transferFrom(from, to, amount); + _checkOsTokenPosition(from); + return success; + } + + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit, VaultOsToken) + returns (uint256 positionTicket) + { + positionTicket = super.enterExitQueue(shares, receiver); + emit Transfer(msg.sender, address(this), shares); + } + + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("EthErc20Vault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } + + /// @inheritdoc VaultState + function _updateExitQueue() internal virtual override(VaultState, VaultToken) returns (uint256 burnedShares) { + return super._updateExitQueue(); + } + + /// @inheritdoc VaultState + function _mintShares(address owner, uint256 shares) internal virtual override(VaultState, VaultToken) { + super._mintShares(owner, shares); + } + + /// @inheritdoc VaultState + function _burnShares(address owner, uint256 shares) internal virtual override(VaultState, VaultToken) { + super._burnShares(owner, shares); + } + + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + internal + override + { + if ( + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) + && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /** + * @dev Upgrades the EthErc20Vault contract + */ + function __EthErc20Vault_upgrade() internal { + __VaultValidators_upgrade(); + } + + /** + * @dev Initializes the EthErc20Vault contract + * @param admin The address of the admin of the Vault + * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. + * @param params The decoded parameters for initializing the EthErc20Vault contract + */ + function __EthErc20Vault_init(address admin, address ownMevEscrow, EthErc20VaultInitParams memory params) + internal + onlyInitializing + { + __VaultAdmin_init(admin, params.metadataIpfsHash); + // fee recipient is initially set to admin address + __VaultFee_init(admin, params.feePercent); + __VaultState_init(params.capacity); + __VaultValidators_init(); + __VaultMev_init(ownMevEscrow); + __VaultToken_init(params.name, params.symbol); + __VaultEthStaking_init(); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthGenesisVault.sol b/contracts/vaults/ethereum/EthGenesisVault.sol index 7c938744..7b22bd23 100644 --- a/contracts/vaults/ethereum/EthGenesisVault.sol +++ b/contracts/vaults/ethereum/EthGenesisVault.sol @@ -2,20 +2,20 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IVaultVersion} from '../../interfaces/IVaultVersion.sol'; -import {IEthPoolEscrow} from '../../interfaces/IEthPoolEscrow.sol'; -import {IEthGenesisVault} from '../../interfaces/IEthGenesisVault.sol'; -import {IRewardEthToken} from '../../interfaces/IRewardEthToken.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; -import {VaultValidators} from '../modules/VaultValidators.sol'; -import {VaultEnterExit} from '../modules/VaultEnterExit.sol'; -import {VaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultState, IVaultState} from '../modules/VaultState.sol'; -import {EthVault, IEthVault} from './EthVault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {IVaultVersion} from "../../interfaces/IVaultVersion.sol"; +import {IEthPoolEscrow} from "../../interfaces/IEthPoolEscrow.sol"; +import {IEthGenesisVault} from "../../interfaces/IEthGenesisVault.sol"; +import {IRewardEthToken} from "../../interfaces/IRewardEthToken.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {ValidatorUtils} from "../../libraries/ValidatorUtils.sol"; +import {VaultValidators} from "../modules/VaultValidators.sol"; +import {VaultEnterExit} from "../modules/VaultEnterExit.sol"; +import {VaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultState, IVaultState} from "../modules/VaultState.sol"; +import {EthVault, IEthVault} from "./EthVault.sol"; /** * @title EthGenesisVault @@ -23,156 +23,150 @@ import {EthVault, IEthVault} from './EthVault.sol'; * @notice Defines the Genesis Vault for Ethereum staking migrated from StakeWise Legacy */ contract EthGenesisVault is Initializable, EthVault, IEthGenesisVault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 5; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IEthPoolEscrow private immutable _poolEscrow; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IRewardEthToken private immutable _rewardEthToken; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthVault contract - * @param poolEscrow The address of the pool escrow contract - * @param rewardEthToken The address of the reward ETH token contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - EthVaultConstructorArgs memory args, - address poolEscrow, - address rewardEthToken - ) EthVault(args) { - _poolEscrow = IEthPoolEscrow(poolEscrow); - _rewardEthToken = IRewardEthToken(rewardEthToken); - } - - /// @inheritdoc IEthVault - function initialize( - bytes calldata - ) external payable virtual override(IEthVault, EthVault) reinitializer(_version) { - if (admin == address(0)) { - revert Errors.UpgradeFailed(); + // slither-disable-next-line shadowing-state + uint8 private constant _version = 5; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IEthPoolEscrow private immutable _poolEscrow; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IRewardEthToken private immutable _rewardEthToken; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthVault contract + * @param poolEscrow The address of the pool escrow contract + * @param rewardEthToken The address of the reward ETH token contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthVaultConstructorArgs memory args, address poolEscrow, address rewardEthToken) EthVault(args) { + _poolEscrow = IEthPoolEscrow(poolEscrow); + _rewardEthToken = IRewardEthToken(rewardEthToken); } - __EthVault_upgrade(); - } - - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, EthVault) returns (bytes32) { - return keccak256('EthGenesisVault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthVault) returns (uint8) { - return _version; - } - - /// @inheritdoc IEthGenesisVault - function migrate(address receiver, uint256 assets) external override returns (uint256 shares) { - if (msg.sender != address(_rewardEthToken) || _poolEscrow.owner() != address(this)) { - revert Errors.AccessDenied(); + + /// @inheritdoc IEthVault + function initialize(bytes calldata) + external + payable + virtual + override(IEthVault, EthVault) + reinitializer(_version) + { + if (admin == address(0)) { + revert Errors.UpgradeFailed(); + } + __EthVault_upgrade(); + } + + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, EthVault) returns (bytes32) { + return keccak256("EthGenesisVault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, EthVault) returns (uint8) { + return _version; + } + + /// @inheritdoc IEthGenesisVault + function migrate(address receiver, uint256 assets) external override returns (uint256 shares) { + if (msg.sender != address(_rewardEthToken) || _poolEscrow.owner() != address(this)) { + revert Errors.AccessDenied(); + } + + _checkCollateralized(); + _checkHarvested(); + if (receiver == address(0)) revert Errors.ZeroAddress(); + if (assets == 0) revert Errors.InvalidAssets(); + + // calculate amount of shares to mint + shares = convertToShares(assets); + + // update state + _totalAssets += SafeCast.toUint128(assets); + _mintShares(receiver, shares); + + // mint max possible OsToken shares + uint256 mintOsTokenShares = Math.min(_calcMaxMintOsTokenShares(receiver), _calcMaxOsTokenShares(assets)); + if (mintOsTokenShares > 0) { + _mintOsToken(receiver, receiver, mintOsTokenShares, address(0)); + } + + emit Migrated(receiver, assets, shares); } - _checkCollateralized(); - _checkHarvested(); - if (receiver == address(0)) revert Errors.ZeroAddress(); - if (assets == 0) revert Errors.InvalidAssets(); - - // calculate amount of shares to mint - shares = convertToShares(assets); - - // update state - _totalAssets += SafeCast.toUint128(assets); - _mintShares(receiver, shares); - - // mint max possible OsToken shares - uint256 mintOsTokenShares = Math.min( - _calcMaxMintOsTokenShares(receiver), - _calcMaxOsTokenShares(assets) - ); - if (mintOsTokenShares > 0) { - _mintOsToken(receiver, receiver, mintOsTokenShares, address(0)); + /** + * @dev Function for depositing using fallback function + */ + receive() external payable virtual override { + if (msg.sender != address(_poolEscrow)) { + _deposit(msg.sender, msg.value, address(0)); + } } - emit Migrated(receiver, assets, shares); - } + /** + * @dev Internal function for calculating the maximum amount of osToken shares that can be minted + * based on the current user balance + * @param user The address of the user + * @return The maximum amount of osToken shares that can be minted + */ + function _calcMaxMintOsTokenShares(address user) private view returns (uint256) { + uint256 userAssets = convertToAssets(_balances[user]); + if (userAssets == 0) return 0; + + // fetch user position + uint256 mintedShares = osTokenPositions(user); + + // calculate max osToken shares that user can mint based on its current staked balance and osToken position + uint256 userMaxOsTokenShares = _calcMaxOsTokenShares(userAssets); + unchecked { + // cannot underflow because mintedShares < userMaxOsTokenShares + return mintedShares < userMaxOsTokenShares ? userMaxOsTokenShares - mintedShares : 0; + } + } - /** - * @dev Function for depositing using fallback function - */ - receive() external payable virtual override { - if (msg.sender != address(_poolEscrow)) { - _deposit(msg.sender, msg.value, address(0)); + /// @inheritdoc VaultEnterExit + function _transferVaultAssets(address receiver, uint256 assets) + internal + virtual + override(VaultEnterExit, VaultEthStaking) + { + if (assets > super._vaultAssets()) _pullWithdrawals(); + return super._transferVaultAssets(receiver, assets); } - } - - /** - * @dev Internal function for calculating the maximum amount of osToken shares that can be minted - * based on the current user balance - * @param user The address of the user - * @return The maximum amount of osToken shares that can be minted - */ - function _calcMaxMintOsTokenShares(address user) private view returns (uint256) { - uint256 userAssets = convertToAssets(_balances[user]); - if (userAssets == 0) return 0; - - // fetch user position - uint256 mintedShares = osTokenPositions(user); - - // calculate max osToken shares that user can mint based on its current staked balance and osToken position - uint256 userMaxOsTokenShares = _calcMaxOsTokenShares(userAssets); - unchecked { - // cannot underflow because mintedShares < userMaxOsTokenShares - return mintedShares < userMaxOsTokenShares ? userMaxOsTokenShares - mintedShares : 0; + + /// @inheritdoc VaultState + function _vaultAssets() internal view virtual override(VaultState, VaultEthStaking) returns (uint256) { + unchecked { + // cannot overflow because of ETH total supply + return super._vaultAssets() + address(_poolEscrow).balance; + } } - } - - /// @inheritdoc VaultEnterExit - function _transferVaultAssets( - address receiver, - uint256 assets - ) internal virtual override(VaultEnterExit, VaultEthStaking) { - if (assets > super._vaultAssets()) _pullWithdrawals(); - return super._transferVaultAssets(receiver, assets); - } - - /// @inheritdoc VaultState - function _vaultAssets() - internal - view - virtual - override(VaultState, VaultEthStaking) - returns (uint256) - { - unchecked { - // cannot overflow because of ETH total supply - return super._vaultAssets() + address(_poolEscrow).balance; + + /// @inheritdoc VaultValidators + function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) + internal + virtual + override(VaultValidators, VaultEthStaking) + { + _pullWithdrawals(); + return super._registerValidators(deposits); + } + + /** + * @dev Pulls assets from pool escrow + */ + function _pullWithdrawals() private { + uint256 escrowBalance = address(_poolEscrow).balance; + if (escrowBalance != 0) _poolEscrow.withdraw(payable(this), escrowBalance); } - } - - /// @inheritdoc VaultValidators - function _registerValidators( - ValidatorUtils.ValidatorDeposit[] memory deposits - ) internal virtual override(VaultValidators, VaultEthStaking) { - _pullWithdrawals(); - return super._registerValidators(deposits); - } - - /** - * @dev Pulls assets from pool escrow - */ - function _pullWithdrawals() private { - uint256 escrowBalance = address(_poolEscrow).balance; - if (escrowBalance != 0) _poolEscrow.withdraw(payable(this), escrowBalance); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthPrivErc20Vault.sol b/contracts/vaults/ethereum/EthPrivErc20Vault.sol index 9f9259f8..20c0ff0b 100644 --- a/contracts/vaults/ethereum/EthPrivErc20Vault.sol +++ b/contracts/vaults/ethereum/EthPrivErc20Vault.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthPrivErc20Vault} from '../../interfaces/IEthPrivErc20Vault.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultWhitelist} from '../modules/VaultWhitelist.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {EthErc20Vault, IEthErc20Vault} from './EthErc20Vault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthPrivErc20Vault} from "../../interfaces/IEthPrivErc20Vault.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultEthStaking, IVaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultWhitelist} from "../modules/VaultWhitelist.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {EthErc20Vault, IEthErc20Vault} from "./EthErc20Vault.sol"; /** * @title EthPrivErc20Vault @@ -18,88 +18,94 @@ import {EthErc20Vault, IEthErc20Vault} from './EthErc20Vault.sol'; * @notice Defines the Ethereum staking Vault with whitelist and ERC-20 token */ contract EthPrivErc20Vault is Initializable, EthErc20Vault, VaultWhitelist, IEthPrivErc20Vault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 5; + // slither-disable-next-line shadowing-state + uint8 private constant _version = 5; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthErc20Vault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(EthErc20VaultConstructorArgs memory args) EthErc20Vault(args) { - _disableInitializers(); - } - - /// @inheritdoc IEthErc20Vault - function initialize( - bytes calldata params - ) external payable virtual override(IEthErc20Vault, EthErc20Vault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 4 to 5 - if (admin != address(0)) { - __EthErc20Vault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthErc20Vault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthErc20VaultConstructorArgs memory args) EthErc20Vault(args) { + _disableInitializers(); } - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthErc20Vault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthErc20VaultInitParams)) - ); - // whitelister is initially set to admin address - __VaultWhitelist_init(_admin); - } + /// @inheritdoc IEthErc20Vault + function initialize(bytes calldata params) + external + payable + virtual + override(IEthErc20Vault, EthErc20Vault) + reinitializer(_version) + { + // if admin is already set, it's an upgrade from version 4 to 5 + if (admin != address(0)) { + __EthErc20Vault_upgrade(); + return; + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, EthErc20Vault) returns (bytes32) { - return keccak256('EthPrivErc20Vault'); - } + // initialize deployed vault + address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); + __EthErc20Vault_init( + _admin, IEthVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (EthErc20VaultInitParams)) + ); + // whitelister is initially set to admin address + __VaultWhitelist_init(_admin); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthErc20Vault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, EthErc20Vault) returns (bytes32) { + return keccak256("EthPrivErc20Vault"); + } - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkWhitelist(msg.sender); - _checkWhitelist(receiver); - return super.deposit(receiver, referrer); - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, EthErc20Vault) returns (uint8) { + return _version; + } - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - _checkWhitelist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } + /// @inheritdoc IVaultEthStaking + function deposit(address receiver, address referrer) + public + payable + virtual + override(IVaultEthStaking, VaultEthStaking) + returns (uint256 shares) + { + _checkWhitelist(msg.sender); + _checkWhitelist(receiver); + return super.deposit(receiver, referrer); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkWhitelist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc VaultEthStaking + receive() external payable virtual override { + _checkWhitelist(msg.sender); + _deposit(msg.sender, msg.value, address(0)); + } + + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkWhitelist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - _checkWhitelist(from); - _checkWhitelist(to); - super._transfer(from, to, amount); - } + /// @inheritdoc ERC20Upgradeable + function _transfer(address from, address to, uint256 amount) internal virtual override { + _checkWhitelist(from); + _checkWhitelist(to); + super._transfer(from, to, amount); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthPrivVault.sol b/contracts/vaults/ethereum/EthPrivVault.sol index 206f5180..dd086193 100644 --- a/contracts/vaults/ethereum/EthPrivVault.sol +++ b/contracts/vaults/ethereum/EthPrivVault.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthPrivVault} from '../../interfaces/IEthPrivVault.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultWhitelist} from '../modules/VaultWhitelist.sol'; -import {IVaultVersion} from '../modules/VaultVersion.sol'; -import {EthVault, IEthVault} from './EthVault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthPrivVault} from "../../interfaces/IEthPrivVault.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {VaultEthStaking, IVaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultWhitelist} from "../modules/VaultWhitelist.sol"; +import {IVaultVersion} from "../modules/VaultVersion.sol"; +import {EthVault, IEthVault} from "./EthVault.sol"; /** * @title EthPrivVault @@ -17,81 +17,85 @@ import {EthVault, IEthVault} from './EthVault.sol'; * @notice Defines the Ethereum staking Vault with whitelist */ contract EthPrivVault is Initializable, EthVault, VaultWhitelist, IEthPrivVault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 5; + // slither-disable-next-line shadowing-state + uint8 private constant _version = 5; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthVault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(EthVaultConstructorArgs memory args) EthVault(args) { - _disableInitializers(); - } - - /// @inheritdoc IEthVault - function initialize( - bytes calldata params - ) external payable virtual override(IEthVault, EthVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 4 to 5 - if (admin != address(0)) { - __EthVault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthVaultConstructorArgs memory args) EthVault(args) { + _disableInitializers(); } - // initialize deployed vault - address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); - __EthVault_init( - _admin, - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthVaultInitParams)) - ); - // whitelister is initially set to admin address - __VaultWhitelist_init(_admin); - } + /// @inheritdoc IEthVault + function initialize(bytes calldata params) + external + payable + virtual + override(IEthVault, EthVault) + reinitializer(_version) + { + // if admin is already set, it's an upgrade from version 4 to 5 + if (admin != address(0)) { + __EthVault_upgrade(); + return; + } + + // initialize deployed vault + address _admin = IEthVaultFactory(msg.sender).vaultAdmin(); + __EthVault_init(_admin, IEthVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (EthVaultInitParams))); + // whitelister is initially set to admin address + __VaultWhitelist_init(_admin); + } - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkWhitelist(msg.sender); - _checkWhitelist(receiver); - return super.deposit(receiver, referrer); - } + /// @inheritdoc IVaultEthStaking + function deposit(address receiver, address referrer) + public + payable + virtual + override(IVaultEthStaking, VaultEthStaking) + returns (uint256 shares) + { + _checkWhitelist(msg.sender); + _checkWhitelist(receiver); + return super.deposit(receiver, referrer); + } - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - _checkWhitelist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } + /// @inheritdoc VaultEthStaking + receive() external payable virtual override { + _checkWhitelist(msg.sender); + _deposit(msg.sender, msg.value, address(0)); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkWhitelist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkWhitelist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, EthVault) returns (bytes32) { - return keccak256('EthPrivVault'); - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, EthVault) returns (bytes32) { + return keccak256("EthPrivVault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, EthVault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, EthVault) returns (uint8) { + return _version; + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthVault.sol b/contracts/vaults/ethereum/EthVault.sol index 1f97d18b..733a9afb 100644 --- a/contracts/vaults/ethereum/EthVault.sol +++ b/contracts/vaults/ethereum/EthVault.sol @@ -2,22 +2,22 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthVault} from '../../interfaces/IEthVault.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {Multicall} from '../../base/Multicall.sol'; -import {VaultValidators} from '../modules/VaultValidators.sol'; -import {VaultAdmin} from '../modules/VaultAdmin.sol'; -import {VaultFee} from '../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {VaultImmutables} from '../modules/VaultImmutables.sol'; -import {VaultState} from '../modules/VaultState.sol'; -import {VaultEnterExit, IVaultEnterExit} from '../modules/VaultEnterExit.sol'; -import {VaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultEthStaking} from '../modules/VaultEthStaking.sol'; -import {VaultMev} from '../modules/VaultMev.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthVault} from "../../interfaces/IEthVault.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {Multicall} from "../../base/Multicall.sol"; +import {VaultValidators} from "../modules/VaultValidators.sol"; +import {VaultAdmin} from "../modules/VaultAdmin.sol"; +import {VaultFee} from "../modules/VaultFee.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {VaultImmutables} from "../modules/VaultImmutables.sol"; +import {VaultState} from "../modules/VaultState.sol"; +import {VaultEnterExit, IVaultEnterExit} from "../modules/VaultEnterExit.sol"; +import {VaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultEthStaking} from "../modules/VaultEthStaking.sol"; +import {VaultMev} from "../modules/VaultMev.sol"; /** * @title EthVault @@ -25,156 +25,146 @@ import {VaultMev} from '../modules/VaultMev.sol'; * @notice Defines the Ethereum staking Vault */ contract EthVault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultOsToken, - VaultMev, - VaultEthStaking, - Multicall, - IEthVault + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultValidators, + VaultEnterExit, + VaultOsToken, + VaultMev, + VaultEthStaking, + Multicall, + IEthVault { - uint8 private constant _version = 5; + uint8 private constant _version = 5; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the EthVault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - EthVaultConstructorArgs memory args - ) - VaultImmutables(args.keeper, args.vaultsRegistry) - VaultValidators( - args.depositDataRegistry, - args.validatorsRegistry, - args.validatorsWithdrawals, - args.validatorsConsolidations, - args.consolidationsChecker - ) - VaultEnterExit(args.exitingAssetsClaimDelay) - VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) - VaultMev(args.sharedMevEscrow) - { - _disableInitializers(); - } - - /// @inheritdoc IEthVault - function initialize( - bytes calldata params - ) external payable virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 4 to 5 - if (admin != address(0)) { - __EthVault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthVaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) + { + _disableInitializers(); } - // initialize deployed vault - __EthVault_init( - IEthVaultFactory(msg.sender).vaultAdmin(), - IEthVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (EthVaultInitParams)) - ); - } + /// @inheritdoc IEthVault + function initialize(bytes calldata params) external payable virtual override reinitializer(_version) { + // if admin is already set, it's an upgrade from version 4 to 5 + if (admin != address(0)) { + __EthVault_upgrade(); + return; + } - /// @inheritdoc IEthVault - function depositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public payable override returns (uint256) { - deposit(msg.sender, referrer); - return mintOsToken(receiver, osTokenShares, referrer); - } + // initialize deployed vault + __EthVault_init( + IEthVaultFactory(msg.sender).vaultAdmin(), + IEthVaultFactory(msg.sender).ownMevEscrow(), + abi.decode(params, (EthVaultInitParams)) + ); + } - /// @inheritdoc IEthVault - function updateStateAndDepositAndMintOsToken( - address receiver, - uint256 osTokenShares, - address referrer, - IKeeperRewards.HarvestParams calldata harvestParams - ) external payable override returns (uint256) { - updateState(harvestParams); - return depositAndMintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IEthVault + function depositAndMintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + payable + override + returns (uint256) + { + deposit(msg.sender, referrer); + return mintOsToken(receiver, osTokenShares, referrer); + } + + /// @inheritdoc IEthVault + function updateStateAndDepositAndMintOsToken( + address receiver, + uint256 osTokenShares, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable override returns (uint256) { + updateState(harvestParams); + return depositAndMintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) - public - virtual - override(IVaultEnterExit, VaultEnterExit, VaultOsToken) - returns (uint256 positionTicket) - { - return super.enterExitQueue(shares, receiver); - } + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit, VaultOsToken) + returns (uint256 positionTicket) + { + return super.enterExitQueue(shares, receiver); + } - /// @inheritdoc VaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('EthVault'); - } + /// @inheritdoc VaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("EthVault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } - /// @inheritdoc VaultValidators - function _checkCanWithdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) internal override { - if ( - !_isValidatorsManager( - validators, - bytes32(validatorsManagerNonce), - validatorsManagerSignature - ) && msg.sender != _osTokenConfig.redeemer() - ) { - revert Errors.AccessDenied(); + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + internal + override + { + if ( + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) + && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } } - } - /** - * @dev Upgrades the EthVault contract - */ - function __EthVault_upgrade() internal { - __VaultValidators_upgrade(); - } + /** + * @dev Upgrades the EthVault contract + */ + function __EthVault_upgrade() internal { + __VaultValidators_upgrade(); + } - /** - * @dev Initializes the EthVault contract - * @param admin The address of the admin of the Vault - * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. - * @param params The decoded parameters for initializing the EthVault contract - */ - function __EthVault_init( - address admin, - address ownMevEscrow, - EthVaultInitParams memory params - ) internal onlyInitializing { - __VaultAdmin_init(admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(ownMevEscrow); - __VaultEthStaking_init(); - } + /** + * @dev Initializes the EthVault contract + * @param admin The address of the admin of the Vault + * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. + * @param params The decoded parameters for initializing the EthVault contract + */ + function __EthVault_init(address admin, address ownMevEscrow, EthVaultInitParams memory params) + internal + onlyInitializing + { + __VaultAdmin_init(admin, params.metadataIpfsHash); + // fee recipient is initially set to admin address + __VaultFee_init(admin, params.feePercent); + __VaultState_init(params.capacity); + __VaultValidators_init(); + __VaultMev_init(ownMevEscrow); + __VaultEthStaking_init(); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/EthVaultFactory.sol b/contracts/vaults/ethereum/EthVaultFactory.sol index c677b69d..787aadb7 100644 --- a/contracts/vaults/ethereum/EthVaultFactory.sol +++ b/contracts/vaults/ethereum/EthVaultFactory.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol'; -import {IEthVault} from '../../interfaces/IEthVault.sol'; -import {IVaultsRegistry} from '../../interfaces/IVaultsRegistry.sol'; -import {OwnMevEscrow} from './mev/OwnMevEscrow.sol'; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {IEthVaultFactory} from "../../interfaces/IEthVaultFactory.sol"; +import {IEthVault} from "../../interfaces/IEthVault.sol"; +import {IVaultsRegistry} from "../../interfaces/IVaultsRegistry.sol"; +import {OwnMevEscrow} from "./mev/OwnMevEscrow.sol"; /** * @title EthVaultFactory @@ -14,59 +14,61 @@ import {OwnMevEscrow} from './mev/OwnMevEscrow.sol'; * @notice Factory for deploying Ethereum staking Vaults */ contract EthVaultFactory is IEthVaultFactory { - IVaultsRegistry internal immutable _vaultsRegistry; + IVaultsRegistry internal immutable _vaultsRegistry; - /// @inheritdoc IEthVaultFactory - address public immutable override implementation; + /// @inheritdoc IEthVaultFactory + address public immutable override implementation; - /// @inheritdoc IEthVaultFactory - address public override ownMevEscrow; + /// @inheritdoc IEthVaultFactory + address public override ownMevEscrow; - /// @inheritdoc IEthVaultFactory - address public override vaultAdmin; + /// @inheritdoc IEthVaultFactory + address public override vaultAdmin; - /** - * @dev Constructor - * @param _implementation The implementation address of Vault - * @param vaultsRegistry The address of the VaultsRegistry contract - */ - constructor(address _implementation, IVaultsRegistry vaultsRegistry) { - implementation = _implementation; - _vaultsRegistry = vaultsRegistry; - } + /** + * @dev Constructor + * @param _implementation The implementation address of Vault + * @param vaultsRegistry The address of the VaultsRegistry contract + */ + constructor(address _implementation, IVaultsRegistry vaultsRegistry) { + implementation = _implementation; + _vaultsRegistry = vaultsRegistry; + } - /// @inheritdoc IEthVaultFactory - function createVault( - bytes calldata params, - bool isOwnMevEscrow - ) external payable override returns (address vault) { - // create vault - vault = address(new ERC1967Proxy(implementation, '')); + /// @inheritdoc IEthVaultFactory + function createVault(bytes calldata params, bool isOwnMevEscrow) + external + payable + override + returns (address vault) + { + // create vault + vault = address(new ERC1967Proxy(implementation, "")); - // create MEV escrow contract if needed - address _mevEscrow; - if (isOwnMevEscrow) { - _mevEscrow = address(new OwnMevEscrow(vault)); - // set MEV escrow contract so that it can be initialized in the Vault - ownMevEscrow = _mevEscrow; - } + // create MEV escrow contract if needed + address _mevEscrow; + if (isOwnMevEscrow) { + _mevEscrow = address(new OwnMevEscrow(vault)); + // set MEV escrow contract so that it can be initialized in the Vault + ownMevEscrow = _mevEscrow; + } - // set admin so that it can be initialized in the Vault - vaultAdmin = msg.sender; + // set admin so that it can be initialized in the Vault + vaultAdmin = msg.sender; - // initialize Vault - IEthVault(vault).initialize{value: msg.value}(params); + // initialize Vault + IEthVault(vault).initialize{value: msg.value}(params); - // cleanup MEV escrow contract - if (isOwnMevEscrow) delete ownMevEscrow; + // cleanup MEV escrow contract + if (isOwnMevEscrow) delete ownMevEscrow; - // cleanup admin - delete vaultAdmin; + // cleanup admin + delete vaultAdmin; - // add vault to the registry - _vaultsRegistry.addVault(vault); + // add vault to the registry + _vaultsRegistry.addVault(vault); - // emit event - emit VaultCreated(msg.sender, vault, _mevEscrow, params); - } + // emit event + emit VaultCreated(msg.sender, vault, _mevEscrow, params); + } } diff --git a/contracts/vaults/ethereum/custom/EthFoxVault.sol b/contracts/vaults/ethereum/custom/EthFoxVault.sol index 0bede682..15e2cb26 100644 --- a/contracts/vaults/ethereum/custom/EthFoxVault.sol +++ b/contracts/vaults/ethereum/custom/EthFoxVault.sol @@ -2,20 +2,20 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthFoxVault} from '../../../interfaces/IEthFoxVault.sol'; -import {Errors} from '../../../libraries/Errors.sol'; -import {Multicall} from '../../../base/Multicall.sol'; -import {VaultValidators} from '../../modules/VaultValidators.sol'; -import {VaultAdmin} from '../../modules/VaultAdmin.sol'; -import {VaultFee} from '../../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../../modules/VaultVersion.sol'; -import {VaultImmutables} from '../../modules/VaultImmutables.sol'; -import {VaultState} from '../../modules/VaultState.sol'; -import {VaultEnterExit} from '../../modules/VaultEnterExit.sol'; -import {VaultEthStaking, IVaultEthStaking} from '../../modules/VaultEthStaking.sol'; -import {VaultMev} from '../../modules/VaultMev.sol'; -import {VaultBlocklist} from '../../modules/VaultBlocklist.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthFoxVault} from "../../../interfaces/IEthFoxVault.sol"; +import {Errors} from "../../../libraries/Errors.sol"; +import {Multicall} from "../../../base/Multicall.sol"; +import {VaultValidators} from "../../modules/VaultValidators.sol"; +import {VaultAdmin} from "../../modules/VaultAdmin.sol"; +import {VaultFee} from "../../modules/VaultFee.sol"; +import {VaultVersion, IVaultVersion} from "../../modules/VaultVersion.sol"; +import {VaultImmutables} from "../../modules/VaultImmutables.sol"; +import {VaultState} from "../../modules/VaultState.sol"; +import {VaultEnterExit} from "../../modules/VaultEnterExit.sol"; +import {VaultEthStaking, IVaultEthStaking} from "../../modules/VaultEthStaking.sol"; +import {VaultMev} from "../../modules/VaultMev.sol"; +import {VaultBlocklist} from "../../modules/VaultBlocklist.sol"; /** * @title EthFoxVault @@ -23,126 +23,127 @@ import {VaultBlocklist} from '../../modules/VaultBlocklist.sol'; * @notice Custom Ethereum non-ERC20 vault with blocklist, own MEV and without osToken minting. */ contract EthFoxVault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultMev, - VaultEthStaking, - VaultBlocklist, - Multicall, - IEthFoxVault + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultValidators, + VaultEnterExit, + VaultMev, + VaultEthStaking, + VaultBlocklist, + Multicall, + IEthFoxVault { - uint8 private constant _version = 2; + uint8 private constant _version = 2; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for checking consolidations - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address keeper, - address vaultsRegistry, - address validatorsRegistry, - address validatorsWithdrawals, - address validatorsConsolidations, - address consolidationsChecker, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - VaultImmutables(keeper, vaultsRegistry) - VaultValidators( - depositDataRegistry, - validatorsRegistry, - validatorsWithdrawals, - validatorsConsolidations, - consolidationsChecker + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor( + address keeper, + address vaultsRegistry, + address validatorsRegistry, + address validatorsWithdrawals, + address validatorsConsolidations, + address consolidationsChecker, + address sharedMevEscrow, + address depositDataRegistry, + uint256 exitingAssetsClaimDelay ) - VaultEnterExit(exitingAssetsClaimDelay) - VaultMev(sharedMevEscrow) - { - _disableInitializers(); - } + VaultImmutables(keeper, vaultsRegistry) + VaultValidators( + depositDataRegistry, + validatorsRegistry, + validatorsWithdrawals, + validatorsConsolidations, + consolidationsChecker + ) + VaultEnterExit(exitingAssetsClaimDelay) + VaultMev(sharedMevEscrow) + { + _disableInitializers(); + } - /// @inheritdoc IEthFoxVault - function initialize(bytes calldata) external payable virtual override reinitializer(_version) { - if (admin == address(0)) { - revert Errors.UpgradeFailed(); + /// @inheritdoc IEthFoxVault + function initialize(bytes calldata) external payable virtual override reinitializer(_version) { + if (admin == address(0)) { + revert Errors.UpgradeFailed(); + } + __VaultValidators_upgrade(); } - __VaultValidators_upgrade(); - } - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override(IVaultEthStaking, VaultEthStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(receiver, referrer); - } + /// @inheritdoc IVaultEthStaking + function deposit(address receiver, address referrer) + public + payable + virtual + override(IVaultEthStaking, VaultEthStaking) + returns (uint256 shares) + { + _checkBlocklist(msg.sender); + _checkBlocklist(receiver); + return super.deposit(receiver, referrer); + } - /// @inheritdoc IEthFoxVault - function ejectUser(address user) external override { - // add user to blocklist - updateBlocklist(user, true); + /// @inheritdoc IEthFoxVault + function ejectUser(address user) external override { + // add user to blocklist + updateBlocklist(user, true); - // fetch shares of the user - uint256 userShares = _balances[user]; - if (userShares == 0 || convertToAssets(userShares) == 0) return; + // fetch shares of the user + uint256 userShares = _balances[user]; + if (userShares == 0 || convertToAssets(userShares) == 0) return; - // send user shares to exit queue - _enterExitQueue(user, userShares, user); - emit UserEjected(user, userShares); - } + // send user shares to exit queue + _enterExitQueue(user, userShares, user); + emit UserEjected(user, userShares); + } - /// @inheritdoc VaultEthStaking - receive() external payable virtual override { - _checkBlocklist(msg.sender); - _deposit(msg.sender, msg.value, address(0)); - } + /// @inheritdoc VaultEthStaking + receive() external payable virtual override { + _checkBlocklist(msg.sender); + _deposit(msg.sender, msg.value, address(0)); + } - /// @inheritdoc VaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('EthFoxVault'); - } + /// @inheritdoc VaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("EthFoxVault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } - /// @inheritdoc VaultValidators - function _checkCanWithdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) internal override { - if ( - !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) - ) { - revert Errors.AccessDenied(); + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + internal + override + { + if (!_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature)) { + revert Errors.AccessDenied(); + } } - } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/ethereum/mev/OwnMevEscrow.sol b/contracts/vaults/ethereum/mev/OwnMevEscrow.sol index a7c3d9b5..0022e68d 100644 --- a/contracts/vaults/ethereum/mev/OwnMevEscrow.sol +++ b/contracts/vaults/ethereum/mev/OwnMevEscrow.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {IOwnMevEscrow} from '../../../interfaces/IOwnMevEscrow.sol'; -import {IVaultEthStaking} from '../../../interfaces/IVaultEthStaking.sol'; -import {Errors} from '../../../libraries/Errors.sol'; +import {IOwnMevEscrow} from "../../../interfaces/IOwnMevEscrow.sol"; +import {IVaultEthStaking} from "../../../interfaces/IVaultEthStaking.sol"; +import {Errors} from "../../../libraries/Errors.sol"; /** * @title OwnMevEscrow @@ -12,29 +12,29 @@ import {Errors} from '../../../libraries/Errors.sol'; * @notice Accumulates received MEV. The escrow is owned by the Vault. */ contract OwnMevEscrow is IOwnMevEscrow { - address payable public immutable override vault; - - /// @dev Constructor - constructor(address _vault) { - vault = payable(_vault); - } - - /// @inheritdoc IOwnMevEscrow - function harvest() external returns (uint256 assets) { - if (msg.sender != vault) revert Errors.HarvestFailed(); - - assets = address(this).balance; - if (assets == 0) return 0; - - emit Harvested(assets); - // slither-disable-next-line arbitrary-send-eth - IVaultEthStaking(msg.sender).receiveFromMevEscrow{value: assets}(); - } - - /** - * @dev Function for receiving MEV - */ - receive() external payable { - emit MevReceived(msg.value); - } + address payable public immutable override vault; + + /// @dev Constructor + constructor(address _vault) { + vault = payable(_vault); + } + + /// @inheritdoc IOwnMevEscrow + function harvest() external returns (uint256 assets) { + if (msg.sender != vault) revert Errors.HarvestFailed(); + + assets = address(this).balance; + if (assets == 0) return 0; + + emit Harvested(assets); + // slither-disable-next-line arbitrary-send-eth + IVaultEthStaking(msg.sender).receiveFromMevEscrow{value: assets}(); + } + + /** + * @dev Function for receiving MEV + */ + receive() external payable { + emit MevReceived(msg.value); + } } diff --git a/contracts/vaults/ethereum/mev/SharedMevEscrow.sol b/contracts/vaults/ethereum/mev/SharedMevEscrow.sol index aa35ddc6..1fac86b9 100644 --- a/contracts/vaults/ethereum/mev/SharedMevEscrow.sol +++ b/contracts/vaults/ethereum/mev/SharedMevEscrow.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {ISharedMevEscrow} from '../../../interfaces/ISharedMevEscrow.sol'; -import {IVaultsRegistry} from '../../../interfaces/IVaultsRegistry.sol'; -import {IVaultEthStaking} from '../../../interfaces/IVaultEthStaking.sol'; -import {Errors} from '../../../libraries/Errors.sol'; +import {ISharedMevEscrow} from "../../../interfaces/ISharedMevEscrow.sol"; +import {IVaultsRegistry} from "../../../interfaces/IVaultsRegistry.sol"; +import {IVaultEthStaking} from "../../../interfaces/IVaultEthStaking.sol"; +import {Errors} from "../../../libraries/Errors.sol"; /** * @title SharedMevEscrow @@ -13,26 +13,26 @@ import {Errors} from '../../../libraries/Errors.sol'; * @notice Accumulates received MEV. The rewards are shared by multiple Vaults. */ contract SharedMevEscrow is ISharedMevEscrow { - IVaultsRegistry private immutable _vaultsRegistry; + IVaultsRegistry private immutable _vaultsRegistry; - /// @dev Constructor - constructor(address vaultsRegistry) { - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - } + /// @dev Constructor + constructor(address vaultsRegistry) { + _vaultsRegistry = IVaultsRegistry(vaultsRegistry); + } - /// @inheritdoc ISharedMevEscrow - function harvest(uint256 assets) external override { - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.HarvestFailed(); + /// @inheritdoc ISharedMevEscrow + function harvest(uint256 assets) external override { + if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.HarvestFailed(); - emit Harvested(msg.sender, assets); - // slither-disable-next-line arbitrary-send-eth - IVaultEthStaking(msg.sender).receiveFromMevEscrow{value: assets}(); - } + emit Harvested(msg.sender, assets); + // slither-disable-next-line arbitrary-send-eth + IVaultEthStaking(msg.sender).receiveFromMevEscrow{value: assets}(); + } - /** - * @dev Function for receiving MEV - */ - receive() external payable { - emit MevReceived(msg.value); - } + /** + * @dev Function for receiving MEV + */ + receive() external payable { + emit MevReceived(msg.value); + } } diff --git a/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol b/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol index 735fac1e..6540f5f0 100644 --- a/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol @@ -2,104 +2,102 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoBlocklistErc20Vault} from '../../interfaces/IGnoBlocklistErc20Vault.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultGnoStaking, IVaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {VaultBlocklist} from '../modules/VaultBlocklist.sol'; -import {GnoErc20Vault, IGnoErc20Vault} from './GnoErc20Vault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoBlocklistErc20Vault} from "../../interfaces/IGnoBlocklistErc20Vault.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultGnoStaking, IVaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {VaultBlocklist} from "../modules/VaultBlocklist.sol"; +import {GnoErc20Vault, IGnoErc20Vault} from "./GnoErc20Vault.sol"; /** * @title GnoBlocklistErc20Vault * @author StakeWise * @notice Defines the Gnosis staking Vault with blocking and ERC-20 functionality */ -contract GnoBlocklistErc20Vault is - Initializable, - GnoErc20Vault, - VaultBlocklist, - IGnoBlocklistErc20Vault -{ - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; +contract GnoBlocklistErc20Vault is Initializable, GnoErc20Vault, VaultBlocklist, IGnoBlocklistErc20Vault { + // slither-disable-next-line shadowing-state + uint8 private constant _version = 3; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoErc20Vault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { - _disableInitializers(); - } - - /// @inheritdoc IGnoErc20Vault - function initialize( - bytes calldata params - ) external virtual override(IGnoErc20Vault, GnoErc20Vault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __GnoErc20Vault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoErc20Vault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { + _disableInitializers(); } - // initialize deployed vault - address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); - __GnoErc20Vault_init( - _admin, - IGnoVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (GnoErc20VaultInitParams)) - ); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(_admin); - } + /// @inheritdoc IGnoErc20Vault + function initialize(bytes calldata params) + external + virtual + override(IGnoErc20Vault, GnoErc20Vault) + reinitializer(_version) + { + // if admin is already set, it's an upgrade from version 2 to 3 + if (admin != address(0)) { + __GnoErc20Vault_upgrade(); + return; + } + + // initialize deployed vault + address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); + __GnoErc20Vault_init( + _admin, IGnoVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (GnoErc20VaultInitParams)) + ); + // blocklist manager is initially set to admin address + __VaultBlocklist_init(_admin); + } - /// @inheritdoc IVaultGnoStaking - function deposit( - uint256 assets, - address receiver, - address referrer - ) public virtual override(IVaultGnoStaking, VaultGnoStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(assets, receiver, referrer); - } + /// @inheritdoc IVaultGnoStaking + function deposit(uint256 assets, address receiver, address referrer) + public + virtual + override(IVaultGnoStaking, VaultGnoStaking) + returns (uint256 shares) + { + _checkBlocklist(msg.sender); + _checkBlocklist(receiver); + return super.deposit(assets, receiver, referrer); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkBlocklist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkBlocklist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (bytes32) { - return keccak256('GnoBlocklistErc20Vault'); - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (bytes32) { + return keccak256("GnoBlocklistErc20Vault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (uint8) { + return _version; + } - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - _checkBlocklist(from); - _checkBlocklist(to); - super._transfer(from, to, amount); - } + /// @inheritdoc ERC20Upgradeable + function _transfer(address from, address to, uint256 amount) internal virtual override { + _checkBlocklist(from); + _checkBlocklist(to); + super._transfer(from, to, amount); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoBlocklistVault.sol b/contracts/vaults/gnosis/GnoBlocklistVault.sol index 69a97dbf..9a225a5b 100644 --- a/contracts/vaults/gnosis/GnoBlocklistVault.sol +++ b/contracts/vaults/gnosis/GnoBlocklistVault.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoBlocklistVault} from '../../interfaces/IGnoBlocklistVault.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultGnoStaking, IVaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultBlocklist} from '../modules/VaultBlocklist.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {GnoVault, IGnoVault} from './GnoVault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoBlocklistVault} from "../../interfaces/IGnoBlocklistVault.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultGnoStaking, IVaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultBlocklist} from "../modules/VaultBlocklist.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {GnoVault, IGnoVault} from "./GnoVault.sol"; /** * @title GnoBlocklistVault @@ -17,74 +17,70 @@ import {GnoVault, IGnoVault} from './GnoVault.sol'; * @notice Defines the Gnosis staking Vault with blocking addresses functionality */ contract GnoBlocklistVault is Initializable, GnoVault, VaultBlocklist, IGnoBlocklistVault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; + // slither-disable-next-line shadowing-state + uint8 private constant _version = 3; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoVault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(GnoVaultConstructorArgs memory args) GnoVault(args) {} + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoVaultConstructorArgs memory args) GnoVault(args) {} - /// @inheritdoc IGnoVault - function initialize( - bytes calldata params - ) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __GnoVault_upgrade(); - return; - } + /// @inheritdoc IGnoVault + function initialize(bytes calldata params) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { + // if admin is already set, it's an upgrade from version 2 to 3 + if (admin != address(0)) { + __GnoVault_upgrade(); + return; + } - // initialize deployed vault - address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); - __GnoVault_init( - _admin, - IGnoVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (GnoVaultInitParams)) - ); - // blocklist manager is initially set to admin address - __VaultBlocklist_init(_admin); - } + // initialize deployed vault + address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); + __GnoVault_init(_admin, IGnoVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (GnoVaultInitParams))); + // blocklist manager is initially set to admin address + __VaultBlocklist_init(_admin); + } - /// @inheritdoc IVaultGnoStaking - function deposit( - uint256 assets, - address receiver, - address referrer - ) public virtual override(IVaultGnoStaking, VaultGnoStaking) returns (uint256 shares) { - _checkBlocklist(msg.sender); - _checkBlocklist(receiver); - return super.deposit(assets, receiver, referrer); - } + /// @inheritdoc IVaultGnoStaking + function deposit(uint256 assets, address receiver, address referrer) + public + virtual + override(IVaultGnoStaking, VaultGnoStaking) + returns (uint256 shares) + { + _checkBlocklist(msg.sender); + _checkBlocklist(receiver); + return super.deposit(assets, receiver, referrer); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkBlocklist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkBlocklist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, GnoVault) returns (bytes32) { - return keccak256('GnoBlocklistVault'); - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, GnoVault) returns (bytes32) { + return keccak256("GnoBlocklistVault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, GnoVault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, GnoVault) returns (uint8) { + return _version; + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoErc20Vault.sol b/contracts/vaults/gnosis/GnoErc20Vault.sol index b0df4e13..36d0efa5 100644 --- a/contracts/vaults/gnosis/GnoErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoErc20Vault.sol @@ -2,24 +2,24 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoErc20Vault} from '../../interfaces/IGnoErc20Vault.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {Multicall} from '../../base/Multicall.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultValidators} from '../modules/VaultValidators.sol'; -import {VaultAdmin} from '../modules/VaultAdmin.sol'; -import {VaultFee} from '../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {VaultImmutables} from '../modules/VaultImmutables.sol'; -import {VaultState} from '../modules/VaultState.sol'; -import {VaultEnterExit, IVaultEnterExit} from '../modules/VaultEnterExit.sol'; -import {VaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultMev} from '../modules/VaultMev.sol'; -import {VaultToken} from '../modules/VaultToken.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoErc20Vault} from "../../interfaces/IGnoErc20Vault.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {Multicall} from "../../base/Multicall.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultValidators} from "../modules/VaultValidators.sol"; +import {VaultAdmin} from "../modules/VaultAdmin.sol"; +import {VaultFee} from "../modules/VaultFee.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {VaultImmutables} from "../modules/VaultImmutables.sol"; +import {VaultState} from "../modules/VaultState.sol"; +import {VaultEnterExit, IVaultEnterExit} from "../modules/VaultEnterExit.sol"; +import {VaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultMev} from "../modules/VaultMev.sol"; +import {VaultToken} from "../modules/VaultToken.sol"; /** * @title GnoErc20Vault @@ -27,193 +27,169 @@ import {VaultToken} from '../modules/VaultToken.sol'; * @notice Defines the Gnosis staking Vault with ERC-20 token */ contract GnoErc20Vault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultOsToken, - VaultMev, - VaultToken, - VaultGnoStaking, - Multicall, - IGnoErc20Vault + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultValidators, + VaultEnterExit, + VaultOsToken, + VaultMev, + VaultToken, + VaultGnoStaking, + Multicall, + IGnoErc20Vault { - uint8 private constant _version = 3; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoErc20Vault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - GnoErc20VaultConstructorArgs memory args - ) - VaultImmutables(args.keeper, args.vaultsRegistry) - VaultValidators( - args.depositDataRegistry, - args.validatorsRegistry, - args.validatorsWithdrawals, - args.validatorsConsolidations, - args.consolidationsChecker - ) - VaultEnterExit(args.exitingAssetsClaimDelay) - VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) - VaultMev(args.sharedMevEscrow) - VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) - { - _disableInitializers(); - } - - /// @inheritdoc IGnoErc20Vault - function initialize(bytes calldata params) external virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __GnoErc20Vault_upgrade(); - return; + uint8 private constant _version = 3; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoErc20Vault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoErc20VaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) + VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) + { + _disableInitializers(); } - // initialize deployed vault - __GnoErc20Vault_init( - IGnoVaultFactory(msg.sender).vaultAdmin(), - IGnoVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (GnoErc20VaultInitParams)) - ); - } - - /// @inheritdoc IERC20 - function transfer( - address to, - uint256 amount - ) public virtual override(IERC20, ERC20Upgradeable) returns (bool) { - bool success = super.transfer(to, amount); - _checkOsTokenPosition(msg.sender); - return success; - } - - /// @inheritdoc IERC20 - function transferFrom( - address from, - address to, - uint256 amount - ) public virtual override(IERC20, ERC20Upgradeable) returns (bool) { - bool success = super.transferFrom(from, to, amount); - _checkOsTokenPosition(from); - return success; - } - - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) - public - virtual - override(IVaultEnterExit, VaultEnterExit, VaultOsToken) - returns (uint256 positionTicket) - { - positionTicket = super.enterExitQueue(shares, receiver); - emit Transfer(msg.sender, address(this), shares); - } - - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('GnoErc20Vault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } - - /// @inheritdoc VaultState - function _processTotalAssetsDelta( - int256 assetsDelta - ) internal virtual override(VaultState, VaultGnoStaking) { - super._processTotalAssetsDelta(assetsDelta); - } - - /// @inheritdoc VaultState - function _updateExitQueue() - internal - virtual - override(VaultState, VaultToken) - returns (uint256 burnedShares) - { - return super._updateExitQueue(); - } - - /// @inheritdoc VaultState - function _mintShares( - address owner, - uint256 shares - ) internal virtual override(VaultState, VaultToken) { - super._mintShares(owner, shares); - } - - /// @inheritdoc VaultState - function _burnShares( - address owner, - uint256 shares - ) internal virtual override(VaultState, VaultToken) { - super._burnShares(owner, shares); - } - - /// @inheritdoc VaultValidators - function _checkCanWithdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) internal override { - if ( - !_isValidatorsManager( - validators, - bytes32(validatorsManagerNonce), - validatorsManagerSignature - ) && msg.sender != _osTokenConfig.redeemer() - ) { - revert Errors.AccessDenied(); + /// @inheritdoc IGnoErc20Vault + function initialize(bytes calldata params) external virtual override reinitializer(_version) { + // if admin is already set, it's an upgrade from version 2 to 3 + if (admin != address(0)) { + __GnoErc20Vault_upgrade(); + return; + } + + // initialize deployed vault + __GnoErc20Vault_init( + IGnoVaultFactory(msg.sender).vaultAdmin(), + IGnoVaultFactory(msg.sender).ownMevEscrow(), + abi.decode(params, (GnoErc20VaultInitParams)) + ); } - } - - /** - * @dev Upgrades the GnoErc20Vault contract - */ - function __GnoErc20Vault_upgrade() internal { - __VaultState_upgrade(); - __VaultValidators_upgrade(); - __VaultGnoStaking_upgrade(); - } - - /** - * @dev Initializes the GnoErc20Vault contract - * @param admin The address of the admin of the Vault - * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. - * @param params The decoded parameters for initializing the GnoErc20Vault contract - */ - function __GnoErc20Vault_init( - address admin, - address ownMevEscrow, - GnoErc20VaultInitParams memory params - ) internal onlyInitializing { - __VaultAdmin_init(admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(ownMevEscrow); - __VaultToken_init(params.name, params.symbol); - __VaultGnoStaking_init(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + + /// @inheritdoc IERC20 + function transfer(address to, uint256 amount) public virtual override(IERC20, ERC20Upgradeable) returns (bool) { + bool success = super.transfer(to, amount); + _checkOsTokenPosition(msg.sender); + return success; + } + + /// @inheritdoc IERC20 + function transferFrom(address from, address to, uint256 amount) + public + virtual + override(IERC20, ERC20Upgradeable) + returns (bool) + { + bool success = super.transferFrom(from, to, amount); + _checkOsTokenPosition(from); + return success; + } + + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit, VaultOsToken) + returns (uint256 positionTicket) + { + positionTicket = super.enterExitQueue(shares, receiver); + emit Transfer(msg.sender, address(this), shares); + } + + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("GnoErc20Vault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } + + /// @inheritdoc VaultState + function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override(VaultState, VaultGnoStaking) { + super._processTotalAssetsDelta(assetsDelta); + } + + /// @inheritdoc VaultState + function _updateExitQueue() internal virtual override(VaultState, VaultToken) returns (uint256 burnedShares) { + return super._updateExitQueue(); + } + + /// @inheritdoc VaultState + function _mintShares(address owner, uint256 shares) internal virtual override(VaultState, VaultToken) { + super._mintShares(owner, shares); + } + + /// @inheritdoc VaultState + function _burnShares(address owner, uint256 shares) internal virtual override(VaultState, VaultToken) { + super._burnShares(owner, shares); + } + + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + internal + override + { + if ( + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) + && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /** + * @dev Upgrades the GnoErc20Vault contract + */ + function __GnoErc20Vault_upgrade() internal { + __VaultState_upgrade(); + __VaultValidators_upgrade(); + __VaultGnoStaking_upgrade(); + } + + /** + * @dev Initializes the GnoErc20Vault contract + * @param admin The address of the admin of the Vault + * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. + * @param params The decoded parameters for initializing the GnoErc20Vault contract + */ + function __GnoErc20Vault_init(address admin, address ownMevEscrow, GnoErc20VaultInitParams memory params) + internal + onlyInitializing + { + __VaultAdmin_init(admin, params.metadataIpfsHash); + // fee recipient is initially set to admin address + __VaultFee_init(admin, params.feePercent); + __VaultState_init(params.capacity); + __VaultValidators_init(); + __VaultMev_init(ownMevEscrow); + __VaultToken_init(params.name, params.symbol); + __VaultGnoStaking_init(); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoGenesisVault.sol b/contracts/vaults/gnosis/GnoGenesisVault.sol index 9e89408c..0d53f49a 100644 --- a/contracts/vaults/gnosis/GnoGenesisVault.sol +++ b/contracts/vaults/gnosis/GnoGenesisVault.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IGnoValidatorsRegistry} from '../../interfaces/IGnoValidatorsRegistry.sol'; -import {IVaultVersion} from '../../interfaces/IVaultVersion.sol'; -import {IGnoPoolEscrow} from '../../interfaces/IGnoPoolEscrow.sol'; -import {IGnoGenesisVault} from '../../interfaces/IGnoGenesisVault.sol'; -import {IRewardGnoToken} from '../../interfaces/IRewardGnoToken.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultState, IVaultState} from '../modules/VaultState.sol'; -import {GnoVault, IGnoVault} from './GnoVault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {IGnoValidatorsRegistry} from "../../interfaces/IGnoValidatorsRegistry.sol"; +import {IVaultVersion} from "../../interfaces/IVaultVersion.sol"; +import {IGnoPoolEscrow} from "../../interfaces/IGnoPoolEscrow.sol"; +import {IGnoGenesisVault} from "../../interfaces/IGnoGenesisVault.sol"; +import {IRewardGnoToken} from "../../interfaces/IRewardGnoToken.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultState, IVaultState} from "../modules/VaultState.sol"; +import {GnoVault, IGnoVault} from "./GnoVault.sol"; /** * @title GnoGenesisVault @@ -21,134 +21,117 @@ import {GnoVault, IGnoVault} from './GnoVault.sol'; * @notice Defines the Genesis Vault for Gnosis staking migrated from StakeWise Legacy */ contract GnoGenesisVault is Initializable, GnoVault, IGnoGenesisVault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 4; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IGnoPoolEscrow private immutable _poolEscrow; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IRewardGnoToken private immutable _rewardGnoToken; - - error InvalidInitialHarvest(); - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoVault contract - * @param poolEscrow The address of the pool escrow from StakeWise Legacy - * @param rewardGnoToken The address of the rGNO token from StakeWise Legacy - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - GnoVaultConstructorArgs memory args, - address poolEscrow, - address rewardGnoToken - ) GnoVault(args) { - _poolEscrow = IGnoPoolEscrow(poolEscrow); - _rewardGnoToken = IRewardGnoToken(rewardGnoToken); - } - - /// @inheritdoc IGnoVault - function initialize( - bytes calldata - ) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { - if (admin == address(0)) { - revert Errors.UpgradeFailed(); + // slither-disable-next-line shadowing-state + uint8 private constant _version = 4; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IGnoPoolEscrow private immutable _poolEscrow; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IRewardGnoToken private immutable _rewardGnoToken; + + error InvalidInitialHarvest(); + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoVault contract + * @param poolEscrow The address of the pool escrow from StakeWise Legacy + * @param rewardGnoToken The address of the rGNO token from StakeWise Legacy + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoVaultConstructorArgs memory args, address poolEscrow, address rewardGnoToken) GnoVault(args) { + _poolEscrow = IGnoPoolEscrow(poolEscrow); + _rewardGnoToken = IRewardGnoToken(rewardGnoToken); } - __GnoVault_upgrade(); - } - - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, GnoVault) returns (bytes32) { - return keccak256('GnoGenesisVault'); - } - - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, GnoVault) returns (uint8) { - return _version; - } - - /// @inheritdoc IGnoGenesisVault - function migrate(address receiver, uint256 assets) external override returns (uint256 shares) { - if (msg.sender != address(_rewardGnoToken) || _poolEscrow.owner() != address(this)) { - revert Errors.AccessDenied(); + + /// @inheritdoc IGnoVault + function initialize(bytes calldata) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { + if (admin == address(0)) { + revert Errors.UpgradeFailed(); + } + __GnoVault_upgrade(); + } + + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, GnoVault) returns (bytes32) { + return keccak256("GnoGenesisVault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, GnoVault) returns (uint8) { + return _version; + } + + /// @inheritdoc IGnoGenesisVault + function migrate(address receiver, uint256 assets) external override returns (uint256 shares) { + if (msg.sender != address(_rewardGnoToken) || _poolEscrow.owner() != address(this)) { + revert Errors.AccessDenied(); + } + + _checkCollateralized(); + _checkHarvested(); + if (receiver == address(0)) revert Errors.ZeroAddress(); + if (assets == 0) revert Errors.InvalidAssets(); + + // calculate amount of shares to mint + shares = convertToShares(assets); + + // update state + _totalAssets += SafeCast.toUint128(assets); + _mintShares(receiver, shares); + + // mint max possible OsToken shares + uint256 mintOsTokenShares = Math.min(_calcMaxMintOsTokenShares(receiver), _calcMaxOsTokenShares(assets)); + if (mintOsTokenShares > 0) { + _mintOsToken(receiver, receiver, mintOsTokenShares, address(0)); + } + + emit Migrated(receiver, assets, shares); } - _checkCollateralized(); - _checkHarvested(); - if (receiver == address(0)) revert Errors.ZeroAddress(); - if (assets == 0) revert Errors.InvalidAssets(); - - // calculate amount of shares to mint - shares = convertToShares(assets); - - // update state - _totalAssets += SafeCast.toUint128(assets); - _mintShares(receiver, shares); - - // mint max possible OsToken shares - uint256 mintOsTokenShares = Math.min( - _calcMaxMintOsTokenShares(receiver), - _calcMaxOsTokenShares(assets) - ); - if (mintOsTokenShares > 0) { - _mintOsToken(receiver, receiver, mintOsTokenShares, address(0)); + /** + * @dev Internal function for calculating the maximum amount of osToken shares that can be minted + * based on the current user balance + * @param user The address of the user + * @return The maximum amount of osToken shares that can be minted + */ + function _calcMaxMintOsTokenShares(address user) private view returns (uint256) { + uint256 userAssets = convertToAssets(_balances[user]); + if (userAssets == 0) return 0; + + // fetch user position + uint256 mintedShares = osTokenPositions(user); + + // calculate max osToken shares that user can mint based on its current staked balance and osToken position + uint256 userMaxOsTokenShares = _calcMaxOsTokenShares(userAssets); + unchecked { + // cannot underflow because mintedShares < userMaxOsTokenShares + return mintedShares < userMaxOsTokenShares ? userMaxOsTokenShares - mintedShares : 0; + } } - emit Migrated(receiver, assets, shares); - } - - /** - * @dev Internal function for calculating the maximum amount of osToken shares that can be minted - * based on the current user balance - * @param user The address of the user - * @return The maximum amount of osToken shares that can be minted - */ - function _calcMaxMintOsTokenShares(address user) private view returns (uint256) { - uint256 userAssets = convertToAssets(_balances[user]); - if (userAssets == 0) return 0; - - // fetch user position - uint256 mintedShares = osTokenPositions(user); - - // calculate max osToken shares that user can mint based on its current staked balance and osToken position - uint256 userMaxOsTokenShares = _calcMaxOsTokenShares(userAssets); - unchecked { - // cannot underflow because mintedShares < userMaxOsTokenShares - return mintedShares < userMaxOsTokenShares ? userMaxOsTokenShares - mintedShares : 0; + /// @inheritdoc VaultState + function _vaultAssets() internal view virtual override(VaultState, VaultGnoStaking) returns (uint256) { + return super._vaultAssets() + _gnoToken.balanceOf(address(_poolEscrow)) + + IGnoValidatorsRegistry(_validatorsRegistry).withdrawableAmount(address(_poolEscrow)); } - } - - /// @inheritdoc VaultState - function _vaultAssets() - internal - view - virtual - override(VaultState, VaultGnoStaking) - returns (uint256) - { - return - super._vaultAssets() + - _gnoToken.balanceOf(address(_poolEscrow)) + - IGnoValidatorsRegistry(_validatorsRegistry).withdrawableAmount(address(_poolEscrow)); - } - - /// @inheritdoc VaultGnoStaking - function _pullWithdrawals() internal override { - super._pullWithdrawals(); - IGnoValidatorsRegistry(_validatorsRegistry).claimWithdrawal(address(_poolEscrow)); - uint256 escrowAssets = _gnoToken.balanceOf(address(_poolEscrow)); - if (escrowAssets != 0) { - _poolEscrow.withdrawTokens(address(_gnoToken), address(this), escrowAssets); + + /// @inheritdoc VaultGnoStaking + function _pullWithdrawals() internal override { + super._pullWithdrawals(); + IGnoValidatorsRegistry(_validatorsRegistry).claimWithdrawal(address(_poolEscrow)); + uint256 escrowAssets = _gnoToken.balanceOf(address(_poolEscrow)); + if (escrowAssets != 0) { + _poolEscrow.withdrawTokens(address(_gnoToken), address(this), escrowAssets); + } } - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoPrivErc20Vault.sol b/contracts/vaults/gnosis/GnoPrivErc20Vault.sol index def22260..85f591d4 100644 --- a/contracts/vaults/gnosis/GnoPrivErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoPrivErc20Vault.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoPrivErc20Vault} from '../../interfaces/IGnoPrivErc20Vault.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultGnoStaking, IVaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultWhitelist} from '../modules/VaultWhitelist.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {GnoErc20Vault, IGnoErc20Vault} from './GnoErc20Vault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoPrivErc20Vault} from "../../interfaces/IGnoPrivErc20Vault.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultGnoStaking, IVaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultWhitelist} from "../modules/VaultWhitelist.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {GnoErc20Vault, IGnoErc20Vault} from "./GnoErc20Vault.sol"; /** * @title GnoPrivErc20Vault @@ -18,83 +18,86 @@ import {GnoErc20Vault, IGnoErc20Vault} from './GnoErc20Vault.sol'; * @notice Defines the Gnosis staking Vault with whitelist and ERC-20 token */ contract GnoPrivErc20Vault is Initializable, GnoErc20Vault, VaultWhitelist, IGnoPrivErc20Vault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; + // slither-disable-next-line shadowing-state + uint8 private constant _version = 3; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoErc20Vault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { - _disableInitializers(); - } - - /// @inheritdoc IGnoErc20Vault - function initialize( - bytes calldata params - ) external virtual override(IGnoErc20Vault, GnoErc20Vault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __GnoErc20Vault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoErc20Vault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { + _disableInitializers(); } - // initialize deployed vault - address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); - __GnoErc20Vault_init( - _admin, - IGnoVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (GnoErc20VaultInitParams)) - ); - // whitelister is initially set to admin address - __VaultWhitelist_init(_admin); - } + /// @inheritdoc IGnoErc20Vault + function initialize(bytes calldata params) + external + virtual + override(IGnoErc20Vault, GnoErc20Vault) + reinitializer(_version) + { + // if admin is already set, it's an upgrade from version 2 to 3 + if (admin != address(0)) { + __GnoErc20Vault_upgrade(); + return; + } + + // initialize deployed vault + address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); + __GnoErc20Vault_init( + _admin, IGnoVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (GnoErc20VaultInitParams)) + ); + // whitelister is initially set to admin address + __VaultWhitelist_init(_admin); + } - /// @inheritdoc IVaultGnoStaking - function deposit( - uint256 assets, - address receiver, - address referrer - ) public virtual override(IVaultGnoStaking, VaultGnoStaking) returns (uint256 shares) { - _checkWhitelist(msg.sender); - _checkWhitelist(receiver); - return super.deposit(assets, receiver, referrer); - } + /// @inheritdoc IVaultGnoStaking + function deposit(uint256 assets, address receiver, address referrer) + public + virtual + override(IVaultGnoStaking, VaultGnoStaking) + returns (uint256 shares) + { + _checkWhitelist(msg.sender); + _checkWhitelist(receiver); + return super.deposit(assets, receiver, referrer); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkWhitelist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkWhitelist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (bytes32) { - return keccak256('GnoPrivErc20Vault'); - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (bytes32) { + return keccak256("GnoPrivErc20Vault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, GnoErc20Vault) returns (uint8) { + return _version; + } - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - _checkWhitelist(from); - _checkWhitelist(to); - super._transfer(from, to, amount); - } + /// @inheritdoc ERC20Upgradeable + function _transfer(address from, address to, uint256 amount) internal virtual override { + _checkWhitelist(from); + _checkWhitelist(to); + super._transfer(from, to, amount); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoPrivVault.sol b/contracts/vaults/gnosis/GnoPrivVault.sol index e9fad519..2f90f441 100644 --- a/contracts/vaults/gnosis/GnoPrivVault.sol +++ b/contracts/vaults/gnosis/GnoPrivVault.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoPrivVault} from '../../interfaces/IGnoPrivVault.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {VaultGnoStaking, IVaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultOsToken, IVaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultWhitelist} from '../modules/VaultWhitelist.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {GnoVault, IGnoVault} from './GnoVault.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoPrivVault} from "../../interfaces/IGnoPrivVault.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {VaultGnoStaking, IVaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultOsToken, IVaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultWhitelist} from "../modules/VaultWhitelist.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {GnoVault, IGnoVault} from "./GnoVault.sol"; /** * @title GnoPrivVault @@ -17,74 +17,70 @@ import {GnoVault, IGnoVault} from './GnoVault.sol'; * @notice Defines the Gnosis staking Vault with whitelist */ contract GnoPrivVault is Initializable, GnoVault, VaultWhitelist, IGnoPrivVault { - // slither-disable-next-line shadowing-state - uint8 private constant _version = 3; + // slither-disable-next-line shadowing-state + uint8 private constant _version = 3; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoVault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(GnoVaultConstructorArgs memory args) GnoVault(args) {} + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoVaultConstructorArgs memory args) GnoVault(args) {} - /// @inheritdoc IGnoVault - function initialize( - bytes calldata params - ) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __GnoVault_upgrade(); - return; - } + /// @inheritdoc IGnoVault + function initialize(bytes calldata params) external virtual override(IGnoVault, GnoVault) reinitializer(_version) { + // if admin is already set, it's an upgrade from version 2 to 3 + if (admin != address(0)) { + __GnoVault_upgrade(); + return; + } - // initialize deployed vault - address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); - __GnoVault_init( - _admin, - IGnoVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (GnoVaultInitParams)) - ); - // whitelister is initially set to admin address - __VaultWhitelist_init(_admin); - } + // initialize deployed vault + address _admin = IGnoVaultFactory(msg.sender).vaultAdmin(); + __GnoVault_init(_admin, IGnoVaultFactory(msg.sender).ownMevEscrow(), abi.decode(params, (GnoVaultInitParams))); + // whitelister is initially set to admin address + __VaultWhitelist_init(_admin); + } - /// @inheritdoc IVaultGnoStaking - function deposit( - uint256 assets, - address receiver, - address referrer - ) public virtual override(IVaultGnoStaking, VaultGnoStaking) returns (uint256 shares) { - _checkWhitelist(msg.sender); - _checkWhitelist(receiver); - return super.deposit(assets, receiver, referrer); - } + /// @inheritdoc IVaultGnoStaking + function deposit(uint256 assets, address receiver, address referrer) + public + virtual + override(IVaultGnoStaking, VaultGnoStaking) + returns (uint256 shares) + { + _checkWhitelist(msg.sender); + _checkWhitelist(receiver); + return super.deposit(assets, receiver, referrer); + } - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override(IVaultOsToken, VaultOsToken) returns (uint256 assets) { - _checkWhitelist(msg.sender); - return super.mintOsToken(receiver, osTokenShares, referrer); - } + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override(IVaultOsToken, VaultOsToken) + returns (uint256 assets) + { + _checkWhitelist(msg.sender); + return super.mintOsToken(receiver, osTokenShares, referrer); + } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override(IVaultVersion, GnoVault) returns (bytes32) { - return keccak256('GnoPrivVault'); - } + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override(IVaultVersion, GnoVault) returns (bytes32) { + return keccak256("GnoPrivVault"); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, GnoVault) returns (uint8) { - return _version; - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, GnoVault) returns (uint8) { + return _version; + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoVault.sol b/contracts/vaults/gnosis/GnoVault.sol index 5fb0bff2..e17bf831 100644 --- a/contracts/vaults/gnosis/GnoVault.sol +++ b/contracts/vaults/gnosis/GnoVault.sol @@ -2,21 +2,21 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoVault} from '../../interfaces/IGnoVault.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {Multicall} from '../../base/Multicall.sol'; -import {VaultValidators} from '../modules/VaultValidators.sol'; -import {VaultAdmin} from '../modules/VaultAdmin.sol'; -import {VaultFee} from '../modules/VaultFee.sol'; -import {VaultVersion, IVaultVersion} from '../modules/VaultVersion.sol'; -import {VaultImmutables} from '../modules/VaultImmutables.sol'; -import {VaultState} from '../modules/VaultState.sol'; -import {VaultEnterExit, IVaultEnterExit} from '../modules/VaultEnterExit.sol'; -import {VaultOsToken} from '../modules/VaultOsToken.sol'; -import {VaultGnoStaking} from '../modules/VaultGnoStaking.sol'; -import {VaultMev} from '../modules/VaultMev.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoVault} from "../../interfaces/IGnoVault.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {Multicall} from "../../base/Multicall.sol"; +import {VaultValidators} from "../modules/VaultValidators.sol"; +import {VaultAdmin} from "../modules/VaultAdmin.sol"; +import {VaultFee} from "../modules/VaultFee.sol"; +import {VaultVersion, IVaultVersion} from "../modules/VaultVersion.sol"; +import {VaultImmutables} from "../modules/VaultImmutables.sol"; +import {VaultState} from "../modules/VaultState.sol"; +import {VaultEnterExit, IVaultEnterExit} from "../modules/VaultEnterExit.sol"; +import {VaultOsToken} from "../modules/VaultOsToken.sol"; +import {VaultGnoStaking} from "../modules/VaultGnoStaking.sol"; +import {VaultMev} from "../modules/VaultMev.sol"; /** * @title GnoVault @@ -24,143 +24,132 @@ import {VaultMev} from '../modules/VaultMev.sol'; * @notice Defines the Gnosis staking Vault */ contract GnoVault is - VaultImmutables, - Initializable, - VaultAdmin, - VaultVersion, - VaultFee, - VaultState, - VaultValidators, - VaultEnterExit, - VaultOsToken, - VaultMev, - VaultGnoStaking, - Multicall, - IGnoVault + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultValidators, + VaultEnterExit, + VaultOsToken, + VaultMev, + VaultGnoStaking, + Multicall, + IGnoVault { - uint8 private constant _version = 3; + uint8 private constant _version = 3; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param args The arguments for initializing the GnoVault contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - GnoVaultConstructorArgs memory args - ) - VaultImmutables(args.keeper, args.vaultsRegistry) - VaultValidators( - args.depositDataRegistry, - args.validatorsRegistry, - args.validatorsWithdrawals, - args.validatorsConsolidations, - args.consolidationsChecker - ) - VaultEnterExit(args.exitingAssetsClaimDelay) - VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) - VaultMev(args.sharedMevEscrow) - VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) - { - _disableInitializers(); - } - - /// @inheritdoc IGnoVault - function initialize(bytes calldata params) external virtual override reinitializer(_version) { - // if admin is already set, it's an upgrade from version 2 to 3 - if (admin != address(0)) { - __GnoVault_upgrade(); - return; + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoVaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultValidators( + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker + ) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultMev(args.sharedMevEscrow) + VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) + { + _disableInitializers(); } - // initialize deployed vault - __GnoVault_init( - IGnoVaultFactory(msg.sender).vaultAdmin(), - IGnoVaultFactory(msg.sender).ownMevEscrow(), - abi.decode(params, (GnoVaultInitParams)) - ); - } + /// @inheritdoc IGnoVault + function initialize(bytes calldata params) external virtual override reinitializer(_version) { + // if admin is already set, it's an upgrade from version 2 to 3 + if (admin != address(0)) { + __GnoVault_upgrade(); + return; + } - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) - public - virtual - override(IVaultEnterExit, VaultEnterExit, VaultOsToken) - returns (uint256 positionTicket) - { - return super.enterExitQueue(shares, receiver); - } + // initialize deployed vault + __GnoVault_init( + IGnoVaultFactory(msg.sender).vaultAdmin(), + IGnoVaultFactory(msg.sender).ownMevEscrow(), + abi.decode(params, (GnoVaultInitParams)) + ); + } - /// @inheritdoc VaultVersion - function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { - return keccak256('GnoVault'); - } + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit, VaultOsToken) + returns (uint256 positionTicket) + { + return super.enterExitQueue(shares, receiver); + } - /// @inheritdoc IVaultVersion - function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { - return _version; - } + /// @inheritdoc VaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("GnoVault"); + } - /// @inheritdoc VaultState - function _processTotalAssetsDelta( - int256 assetsDelta - ) internal virtual override(VaultState, VaultGnoStaking) { - super._processTotalAssetsDelta(assetsDelta); - } + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } - /// @inheritdoc VaultValidators - function _checkCanWithdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) internal override { - if ( - !_isValidatorsManager( - validators, - bytes32(validatorsManagerNonce), - validatorsManagerSignature - ) && msg.sender != _osTokenConfig.redeemer() - ) { - revert Errors.AccessDenied(); + /// @inheritdoc VaultState + function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override(VaultState, VaultGnoStaking) { + super._processTotalAssetsDelta(assetsDelta); } - } - /** - * @dev Upgrades the GnoVault contract - */ - function __GnoVault_upgrade() internal { - __VaultState_upgrade(); - __VaultValidators_upgrade(); - __VaultGnoStaking_upgrade(); - } + /// @inheritdoc VaultValidators + function _checkCanWithdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + internal + override + { + if ( + !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) + && msg.sender != _osTokenConfig.redeemer() + ) { + revert Errors.AccessDenied(); + } + } + + /** + * @dev Upgrades the GnoVault contract + */ + function __GnoVault_upgrade() internal { + __VaultState_upgrade(); + __VaultValidators_upgrade(); + __VaultGnoStaking_upgrade(); + } - /** - * @dev Initializes the GnoVault contract - * @param admin The address of the admin of the Vault - * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. - * @param params The decoded parameters for initializing the GnoVault contract - */ - function __GnoVault_init( - address admin, - address ownMevEscrow, - GnoVaultInitParams memory params - ) internal onlyInitializing { - __VaultAdmin_init(admin, params.metadataIpfsHash); - // fee recipient is initially set to admin address - __VaultFee_init(admin, params.feePercent); - __VaultState_init(params.capacity); - __VaultValidators_init(); - __VaultMev_init(ownMevEscrow); - __VaultGnoStaking_init(); - } + /** + * @dev Initializes the GnoVault contract + * @param admin The address of the admin of the Vault + * @param ownMevEscrow The address of the MEV escrow owned by the Vault. Zero address if shared MEV escrow is used. + * @param params The decoded parameters for initializing the GnoVault contract + */ + function __GnoVault_init(address admin, address ownMevEscrow, GnoVaultInitParams memory params) + internal + onlyInitializing + { + __VaultAdmin_init(admin, params.metadataIpfsHash); + // fee recipient is initially set to admin address + __VaultFee_init(admin, params.feePercent); + __VaultState_init(params.capacity); + __VaultValidators_init(); + __VaultMev_init(ownMevEscrow); + __VaultGnoStaking_init(); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/gnosis/GnoVaultFactory.sol b/contracts/vaults/gnosis/GnoVaultFactory.sol index 8314625a..4b04a0d0 100644 --- a/contracts/vaults/gnosis/GnoVaultFactory.sol +++ b/contracts/vaults/gnosis/GnoVaultFactory.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {IGnoVaultFactory} from '../../interfaces/IGnoVaultFactory.sol'; -import {IGnoVault} from '../../interfaces/IGnoVault.sol'; -import {IVaultsRegistry} from '../../interfaces/IVaultsRegistry.sol'; -import {GnoOwnMevEscrow} from './mev/GnoOwnMevEscrow.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {IGnoVault} from "../../interfaces/IGnoVault.sol"; +import {IVaultsRegistry} from "../../interfaces/IVaultsRegistry.sol"; +import {GnoOwnMevEscrow} from "./mev/GnoOwnMevEscrow.sol"; /** * @title GnoVaultFactory @@ -16,72 +16,69 @@ import {GnoOwnMevEscrow} from './mev/GnoOwnMevEscrow.sol'; * @notice Factory for deploying Gnosis staking Vaults */ contract GnoVaultFactory is IGnoVaultFactory { - uint256 private constant _securityDeposit = 1e9; - - IVaultsRegistry internal immutable _vaultsRegistry; - - IERC20 internal immutable _gnoToken; - - /// @inheritdoc IGnoVaultFactory - address public immutable override implementation; - - /// @inheritdoc IGnoVaultFactory - address public override ownMevEscrow; - - /// @inheritdoc IGnoVaultFactory - address public override vaultAdmin; - - /** - * @dev Constructor - * @param _implementation The implementation address of Vault - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param gnoToken The address of the GNO token - */ - constructor(address _implementation, IVaultsRegistry vaultsRegistry, address gnoToken) { - implementation = _implementation; - _vaultsRegistry = vaultsRegistry; - _gnoToken = IERC20(gnoToken); - } - - /// @inheritdoc IGnoVaultFactory - function createVault( - bytes calldata params, - bool isOwnMevEscrow - ) external override returns (address vault) { - // transfer GNO security deposit to the factory - // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 - SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); - - // create vault - vault = address(new ERC1967Proxy(implementation, '')); - - // approve GNO token for the vault security deposit - _gnoToken.approve(vault, _securityDeposit); - - // create MEV escrow contract if needed - address _mevEscrow; - if (isOwnMevEscrow) { - _mevEscrow = address(new GnoOwnMevEscrow(vault)); - // set MEV escrow contract so that it can be initialized in the Vault - ownMevEscrow = _mevEscrow; + uint256 private constant _securityDeposit = 1e9; + + IVaultsRegistry internal immutable _vaultsRegistry; + + IERC20 internal immutable _gnoToken; + + /// @inheritdoc IGnoVaultFactory + address public immutable override implementation; + + /// @inheritdoc IGnoVaultFactory + address public override ownMevEscrow; + + /// @inheritdoc IGnoVaultFactory + address public override vaultAdmin; + + /** + * @dev Constructor + * @param _implementation The implementation address of Vault + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param gnoToken The address of the GNO token + */ + constructor(address _implementation, IVaultsRegistry vaultsRegistry, address gnoToken) { + implementation = _implementation; + _vaultsRegistry = vaultsRegistry; + _gnoToken = IERC20(gnoToken); } - // set admin so that it can be initialized in the Vault - vaultAdmin = msg.sender; + /// @inheritdoc IGnoVaultFactory + function createVault(bytes calldata params, bool isOwnMevEscrow) external override returns (address vault) { + // transfer GNO security deposit to the factory + // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); - // initialize Vault - IGnoVault(vault).initialize(params); + // create vault + vault = address(new ERC1967Proxy(implementation, "")); - // cleanup MEV escrow contract - if (isOwnMevEscrow) delete ownMevEscrow; + // approve GNO token for the vault security deposit + _gnoToken.approve(vault, _securityDeposit); - // cleanup admin - delete vaultAdmin; + // create MEV escrow contract if needed + address _mevEscrow; + if (isOwnMevEscrow) { + _mevEscrow = address(new GnoOwnMevEscrow(vault)); + // set MEV escrow contract so that it can be initialized in the Vault + ownMevEscrow = _mevEscrow; + } - // add vault to the registry - _vaultsRegistry.addVault(vault); + // set admin so that it can be initialized in the Vault + vaultAdmin = msg.sender; - // emit event - emit VaultCreated(msg.sender, vault, _mevEscrow, params); - } + // initialize Vault + IGnoVault(vault).initialize(params); + + // cleanup MEV escrow contract + if (isOwnMevEscrow) delete ownMevEscrow; + + // cleanup admin + delete vaultAdmin; + + // add vault to the registry + _vaultsRegistry.addVault(vault); + + // emit event + emit VaultCreated(msg.sender, vault, _mevEscrow, params); + } } diff --git a/contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol b/contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol index 8990555d..e01c9082 100644 --- a/contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol +++ b/contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {IOwnMevEscrow} from '../../../interfaces/IOwnMevEscrow.sol'; -import {Errors} from '../../../libraries/Errors.sol'; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {IOwnMevEscrow} from "../../../interfaces/IOwnMevEscrow.sol"; +import {Errors} from "../../../libraries/Errors.sol"; /** * @title GnoOwnMevEscrow @@ -12,37 +12,37 @@ import {Errors} from '../../../libraries/Errors.sol'; * @notice Accumulates received MEV. The escrow is owned by the Vault. */ contract GnoOwnMevEscrow is IOwnMevEscrow { - /// @inheritdoc IOwnMevEscrow - address payable public immutable override vault; - - /** - * @dev Constructor - * @param _vault The address of the Vault contract - */ - constructor(address _vault) { - // payable is not used but is required for the interface - vault = payable(_vault); - } - - /// @inheritdoc IOwnMevEscrow - function harvest() external returns (uint256) { - if (msg.sender != vault) revert Errors.HarvestFailed(); - - uint256 balance = address(this).balance; - if (balance != 0) { - // transfer all xDAI to the vault - Address.sendValue(vault, balance); - emit Harvested(balance); + /// @inheritdoc IOwnMevEscrow + address payable public immutable override vault; + + /** + * @dev Constructor + * @param _vault The address of the Vault contract + */ + constructor(address _vault) { + // payable is not used but is required for the interface + vault = payable(_vault); } - // always returns 0 as xDAI must be converted to GNO first - return 0; - } + /// @inheritdoc IOwnMevEscrow + function harvest() external returns (uint256) { + if (msg.sender != vault) revert Errors.HarvestFailed(); - /** - * @dev Function for receiving MEV - */ - receive() external payable { - emit MevReceived(msg.value); - } + uint256 balance = address(this).balance; + if (balance != 0) { + // transfer all xDAI to the vault + Address.sendValue(vault, balance); + emit Harvested(balance); + } + + // always returns 0 as xDAI must be converted to GNO first + return 0; + } + + /** + * @dev Function for receiving MEV + */ + receive() external payable { + emit MevReceived(msg.value); + } } diff --git a/contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol b/contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol index c064fd01..80f0ab0a 100644 --- a/contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol +++ b/contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {ISharedMevEscrow} from '../../../interfaces/ISharedMevEscrow.sol'; -import {IVaultsRegistry} from '../../../interfaces/IVaultsRegistry.sol'; -import {Errors} from '../../../libraries/Errors.sol'; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {ISharedMevEscrow} from "../../../interfaces/ISharedMevEscrow.sol"; +import {IVaultsRegistry} from "../../../interfaces/IVaultsRegistry.sol"; +import {Errors} from "../../../libraries/Errors.sol"; /** * @title GnoSharedMevEscrow @@ -13,29 +13,29 @@ import {Errors} from '../../../libraries/Errors.sol'; * @notice Accumulates received MEV. The rewards are shared by multiple Vaults. */ contract GnoSharedMevEscrow is ISharedMevEscrow { - IVaultsRegistry private immutable _vaultsRegistry; + IVaultsRegistry private immutable _vaultsRegistry; - /** - * @dev Constructor - * @param vaultsRegistry The address of the VaultsRegistry contract - */ - constructor(address vaultsRegistry) { - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - } + /** + * @dev Constructor + * @param vaultsRegistry The address of the VaultsRegistry contract + */ + constructor(address vaultsRegistry) { + _vaultsRegistry = IVaultsRegistry(vaultsRegistry); + } - /// @inheritdoc ISharedMevEscrow - function harvest(uint256 assets) external override { - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.HarvestFailed(); + /// @inheritdoc ISharedMevEscrow + function harvest(uint256 assets) external override { + if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.HarvestFailed(); - // transfer xDAI to the vault - Address.sendValue(payable(msg.sender), assets); - emit Harvested(msg.sender, assets); - } + // transfer xDAI to the vault + Address.sendValue(payable(msg.sender), assets); + emit Harvested(msg.sender, assets); + } - /** - * @dev Function for receiving MEV - */ - receive() external payable { - emit MevReceived(msg.value); - } + /** + * @dev Function for receiving MEV + */ + receive() external payable { + emit MevReceived(msg.value); + } } diff --git a/contracts/vaults/modules/VaultAdmin.sol b/contracts/vaults/modules/VaultAdmin.sol index 20443e73..47d91ca5 100644 --- a/contracts/vaults/modules/VaultAdmin.sol +++ b/contracts/vaults/modules/VaultAdmin.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IVaultAdmin} from '../../interfaces/IVaultAdmin.sol'; -import {Errors} from '../../libraries/Errors.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IVaultAdmin} from "../../interfaces/IVaultAdmin.sol"; +import {Errors} from "../../libraries/Errors.sol"; /** * @title VaultAdmin @@ -12,54 +12,51 @@ import {Errors} from '../../libraries/Errors.sol'; * @notice Defines the admin functionality for the Vault */ abstract contract VaultAdmin is Initializable, IVaultAdmin { - /// @inheritdoc IVaultAdmin - address public override admin; - - /// @inheritdoc IVaultAdmin - function setMetadata(string calldata metadataIpfsHash) external override { - _checkAdmin(); - emit MetadataUpdated(msg.sender, metadataIpfsHash); - } - - /// @inheritdoc IVaultAdmin - function setAdmin(address newAdmin) external override { - _checkAdmin(); - _setAdmin(newAdmin); - } - - /** - * @dev Internal method for checking whether the caller is admin - */ - function _checkAdmin() internal view { - if (msg.sender != admin) revert Errors.AccessDenied(); - } - - /** - * @dev Internal method for updating the admin - * @param newAdmin The address of the new admin - */ - function _setAdmin(address newAdmin) private { - if (newAdmin == address(0)) revert Errors.ZeroAddress(); - admin = newAdmin; - emit AdminUpdated(msg.sender, newAdmin); - } - - /** - * @dev Initializes the VaultAdmin contract - * @param _admin The address of the Vault admin - */ - function __VaultAdmin_init( - address _admin, - string memory metadataIpfsHash - ) internal onlyInitializing { - _setAdmin(_admin); - emit MetadataUpdated(msg.sender, metadataIpfsHash); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /// @inheritdoc IVaultAdmin + address public override admin; + + /// @inheritdoc IVaultAdmin + function setMetadata(string calldata metadataIpfsHash) external override { + _checkAdmin(); + emit MetadataUpdated(msg.sender, metadataIpfsHash); + } + + /// @inheritdoc IVaultAdmin + function setAdmin(address newAdmin) external override { + _checkAdmin(); + _setAdmin(newAdmin); + } + + /** + * @dev Internal method for checking whether the caller is admin + */ + function _checkAdmin() internal view { + if (msg.sender != admin) revert Errors.AccessDenied(); + } + + /** + * @dev Internal method for updating the admin + * @param newAdmin The address of the new admin + */ + function _setAdmin(address newAdmin) private { + if (newAdmin == address(0)) revert Errors.ZeroAddress(); + admin = newAdmin; + emit AdminUpdated(msg.sender, newAdmin); + } + + /** + * @dev Initializes the VaultAdmin contract + * @param _admin The address of the Vault admin + */ + function __VaultAdmin_init(address _admin, string memory metadataIpfsHash) internal onlyInitializing { + _setAdmin(_admin); + emit MetadataUpdated(msg.sender, metadataIpfsHash); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultBlocklist.sol b/contracts/vaults/modules/VaultBlocklist.sol index e748b1d5..889b6853 100644 --- a/contracts/vaults/modules/VaultBlocklist.sol +++ b/contracts/vaults/modules/VaultBlocklist.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IVaultBlocklist} from '../../interfaces/IVaultBlocklist.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IVaultBlocklist} from "../../interfaces/IVaultBlocklist.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; /** * @title VaultBlocklist @@ -13,57 +13,57 @@ import {VaultAdmin} from './VaultAdmin.sol'; * @notice Defines the functionality for blocking addresses for the Vault */ abstract contract VaultBlocklist is Initializable, VaultAdmin, IVaultBlocklist { - /// @inheritdoc IVaultBlocklist - address public override blocklistManager; + /// @inheritdoc IVaultBlocklist + address public override blocklistManager; - /// @inheritdoc IVaultBlocklist - mapping(address => bool) public override blockedAccounts; + /// @inheritdoc IVaultBlocklist + mapping(address => bool) public override blockedAccounts; - /// @inheritdoc IVaultBlocklist - function updateBlocklist(address account, bool isBlocked) public virtual override { - if (msg.sender != blocklistManager) revert Errors.AccessDenied(); - if (blockedAccounts[account] == isBlocked) return; + /// @inheritdoc IVaultBlocklist + function updateBlocklist(address account, bool isBlocked) public virtual override { + if (msg.sender != blocklistManager) revert Errors.AccessDenied(); + if (blockedAccounts[account] == isBlocked) return; - blockedAccounts[account] = isBlocked; - emit BlocklistUpdated(msg.sender, account, isBlocked); - } + blockedAccounts[account] = isBlocked; + emit BlocklistUpdated(msg.sender, account, isBlocked); + } - /// @inheritdoc IVaultBlocklist - function setBlocklistManager(address _blocklistManager) external override { - _checkAdmin(); - _setBlocklistManager(_blocklistManager); - } + /// @inheritdoc IVaultBlocklist + function setBlocklistManager(address _blocklistManager) external override { + _checkAdmin(); + _setBlocklistManager(_blocklistManager); + } - /** - * @notice Internal function for checking blocklist - * @param account The address of the account to check - */ - function _checkBlocklist(address account) internal view { - if (blockedAccounts[account]) revert Errors.AccessDenied(); - } + /** + * @notice Internal function for checking blocklist + * @param account The address of the account to check + */ + function _checkBlocklist(address account) internal view { + if (blockedAccounts[account]) revert Errors.AccessDenied(); + } - /** - * @dev Internal function for updating the blocklist manager externally or from the initializer - * @param _blocklistManager The address of the new blocklist manager - */ - function _setBlocklistManager(address _blocklistManager) private { - // update blocklist manager address - blocklistManager = _blocklistManager; - emit BlocklistManagerUpdated(msg.sender, _blocklistManager); - } + /** + * @dev Internal function for updating the blocklist manager externally or from the initializer + * @param _blocklistManager The address of the new blocklist manager + */ + function _setBlocklistManager(address _blocklistManager) private { + // update blocklist manager address + blocklistManager = _blocklistManager; + emit BlocklistManagerUpdated(msg.sender, _blocklistManager); + } - /** - * @dev Initializes the VaultBlocklist contract - * @param _blocklistManager The address of the blocklist manager - */ - function __VaultBlocklist_init(address _blocklistManager) internal onlyInitializing { - _setBlocklistManager(_blocklistManager); - } + /** + * @dev Initializes the VaultBlocklist contract + * @param _blocklistManager The address of the blocklist manager + */ + function __VaultBlocklist_init(address _blocklistManager) internal onlyInitializing { + _setBlocklistManager(_blocklistManager); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultEnterExit.sol b/contracts/vaults/modules/VaultEnterExit.sol index 20fc091b..d0a55929 100644 --- a/contracts/vaults/modules/VaultEnterExit.sol +++ b/contracts/vaults/modules/VaultEnterExit.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IVaultEnterExit} from '../../interfaces/IVaultEnterExit.sol'; -import {ExitQueue} from '../../libraries/ExitQueue.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultImmutables} from './VaultImmutables.sol'; -import {VaultState} from './VaultState.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {IVaultEnterExit} from "../../interfaces/IVaultEnterExit.sol"; +import {ExitQueue} from "../../libraries/ExitQueue.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; +import {VaultState} from "./VaultState.sol"; /** * @title VaultEnterExit @@ -17,203 +17,178 @@ import {VaultState} from './VaultState.sol'; * @notice Defines the functionality for entering and exiting the Vault */ abstract contract VaultEnterExit is VaultImmutables, Initializable, VaultState, IVaultEnterExit { - using ExitQueue for ExitQueue.History; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - uint256 private immutable _exitingAssetsClaimDelay; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param exitingAssetsClaimDelay The minimum delay after which the assets can be claimed after joining the exit queue - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(uint256 exitingAssetsClaimDelay) { - _exitingAssetsClaimDelay = exitingAssetsClaimDelay; - } - - /// @inheritdoc IVaultEnterExit - function getExitQueueIndex(uint256 positionTicket) external view override returns (int256) { - uint256 checkpointIdx = _exitQueue.getCheckpointIndex(positionTicket); - return checkpointIdx < _exitQueue.checkpoints.length ? int256(checkpointIdx) : -1; - } - - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) public virtual override returns (uint256 positionTicket) { - return _enterExitQueue(msg.sender, shares, receiver); - } - - /// @inheritdoc IVaultEnterExit - function calculateExitedAssets( - address receiver, - uint256 positionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) - public - view - override - returns (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) - { - uint256 exitingTickets = _exitRequests[ - keccak256(abi.encode(receiver, timestamp, positionTicket)) - ]; - if (exitingTickets == 0) return (0, 0, 0); - - // calculate exited tickets and assets - (exitedTickets, exitedAssets) = _exitQueue.calculateExitedAssets( - exitQueueIndex, - positionTicket, - exitingTickets - ); - leftTickets = exitingTickets - exitedTickets; - } - - /// @inheritdoc IVaultEnterExit - function claimExitedAssets( - uint256 positionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) external override { - // calculate exited tickets and assets - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = calculateExitedAssets( - msg.sender, - positionTicket, - timestamp, - exitQueueIndex - ); - if ( - block.timestamp < timestamp + _exitingAssetsClaimDelay || - exitedTickets == 0 || - exitedAssets == 0 - ) { - revert Errors.ExitRequestNotProcessed(); + using ExitQueue for ExitQueue.History; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + uint256 private immutable _exitingAssetsClaimDelay; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param exitingAssetsClaimDelay The minimum delay after which the assets can be claimed after joining the exit queue + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(uint256 exitingAssetsClaimDelay) { + _exitingAssetsClaimDelay = exitingAssetsClaimDelay; } - // update unclaimed assets - _unclaimedAssets -= SafeCast.toUint128(exitedAssets); - - // clean up current exit request - delete _exitRequests[keccak256(abi.encode(msg.sender, timestamp, positionTicket))]; - - // skip creating new position for the tickets rounding error - uint256 newPositionTicket; - if (leftTickets > 1) { - // update user's queue position - newPositionTicket = positionTicket + exitedTickets; - _exitRequests[keccak256(abi.encode(msg.sender, timestamp, newPositionTicket))] = leftTickets; + /// @inheritdoc IVaultEnterExit + function getExitQueueIndex(uint256 positionTicket) external view override returns (int256) { + uint256 checkpointIdx = _exitQueue.getCheckpointIndex(positionTicket); + return checkpointIdx < _exitQueue.checkpoints.length ? int256(checkpointIdx) : -1; } - // transfer assets to the receiver - _transferVaultAssets(msg.sender, exitedAssets); - emit ExitedAssetsClaimed(msg.sender, positionTicket, newPositionTicket, exitedAssets); - } - - /** - * @dev Internal function that must be used to process user deposits - * @param to The address to mint shares to - * @param assets The number of assets deposited - * @param referrer The address of the referrer. Set to zero address if not used. - * @return shares The total amount of shares minted - */ - function _deposit( - address to, - uint256 assets, - address referrer - ) internal virtual returns (uint256 shares) { - _checkHarvested(); - if (to == address(0)) revert Errors.ZeroAddress(); - if (assets == 0) revert Errors.InvalidAssets(); - - uint256 totalAssetsAfter; - unchecked { - // cannot overflow as it is capped with underlying asset total supply - totalAssetsAfter = _totalAssets + assets; + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override + returns (uint256 positionTicket) + { + return _enterExitQueue(msg.sender, shares, receiver); } - if (totalAssetsAfter > capacity()) revert Errors.CapacityExceeded(); - - // calculate amount of shares to mint - shares = _convertToShares(assets, Math.Rounding.Ceil); - - // update state - _totalAssets = SafeCast.toUint128(totalAssetsAfter); - _mintShares(to, shares); - - emit Deposited(msg.sender, to, assets, shares, referrer); - } - - /** - * @dev Internal function for sending user shares to the exit queue - * @param user The address of the user - * @param shares The number of shares to send to exit queue - * @param receiver The address that will receive the assets - * @return positionTicket The position ticket in the exit queue. Returns max uint256 if no ticket is created. - */ - function _enterExitQueue( - address user, - uint256 shares, - address receiver - ) internal virtual returns (uint256 positionTicket) { - if (shares == 0) revert Errors.InvalidShares(); - if (receiver == address(0)) revert Errors.ZeroAddress(); - if (!_isCollateralized()) { - // calculate amount of assets to burn - uint256 assets = convertToAssets(shares); - if (assets == 0) revert Errors.InvalidAssets(); - - // update total assets - _totalAssets -= SafeCast.toUint128(assets); - - // burn owner shares - _burnShares(user, shares); - - // transfer assets to the receiver - _transferVaultAssets(receiver, assets); - - emit Redeemed(user, receiver, assets, shares); - - // no ticket is created, return max value - return type(uint256).max; - } - - // SLOAD to memory - uint256 queuedShares = _queuedShares; - // calculate position ticket - positionTicket = _exitQueue.getLatestTotalTickets() + _totalExitingTickets + queuedShares; + /// @inheritdoc IVaultEnterExit + function calculateExitedAssets(address receiver, uint256 positionTicket, uint256 timestamp, uint256 exitQueueIndex) + public + view + override + returns (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) + { + uint256 exitingTickets = _exitRequests[keccak256(abi.encode(receiver, timestamp, positionTicket))]; + if (exitingTickets == 0) return (0, 0, 0); + + // calculate exited tickets and assets + (exitedTickets, exitedAssets) = _exitQueue.calculateExitedAssets(exitQueueIndex, positionTicket, exitingTickets); + leftTickets = exitingTickets - exitedTickets; + } - // add to the exit requests - _exitRequests[keccak256(abi.encode(receiver, block.timestamp, positionTicket))] = shares; + /// @inheritdoc IVaultEnterExit + function claimExitedAssets(uint256 positionTicket, uint256 timestamp, uint256 exitQueueIndex) external override { + // calculate exited tickets and assets + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = + calculateExitedAssets(msg.sender, positionTicket, timestamp, exitQueueIndex); + if (block.timestamp < timestamp + _exitingAssetsClaimDelay || exitedTickets == 0 || exitedAssets == 0) { + revert Errors.ExitRequestNotProcessed(); + } + + // update unclaimed assets + _unclaimedAssets -= SafeCast.toUint128(exitedAssets); + + // clean up current exit request + delete _exitRequests[keccak256(abi.encode(msg.sender, timestamp, positionTicket))]; + + // skip creating new position for the tickets rounding error + uint256 newPositionTicket; + if (leftTickets > 1) { + // update user's queue position + newPositionTicket = positionTicket + exitedTickets; + _exitRequests[keccak256(abi.encode(msg.sender, timestamp, newPositionTicket))] = leftTickets; + } + + // transfer assets to the receiver + _transferVaultAssets(msg.sender, exitedAssets); + emit ExitedAssetsClaimed(msg.sender, positionTicket, newPositionTicket, exitedAssets); + } - // reverts if owner does not have enough shares - _balances[user] -= shares; + /** + * @dev Internal function that must be used to process user deposits + * @param to The address to mint shares to + * @param assets The number of assets deposited + * @param referrer The address of the referrer. Set to zero address if not used. + * @return shares The total amount of shares minted + */ + function _deposit(address to, uint256 assets, address referrer) internal virtual returns (uint256 shares) { + _checkHarvested(); + if (to == address(0)) revert Errors.ZeroAddress(); + if (assets == 0) revert Errors.InvalidAssets(); + + uint256 totalAssetsAfter; + unchecked { + // cannot overflow as it is capped with underlying asset total supply + totalAssetsAfter = _totalAssets + assets; + } + if (totalAssetsAfter > capacity()) revert Errors.CapacityExceeded(); + + // calculate amount of shares to mint + shares = _convertToShares(assets, Math.Rounding.Ceil); + + // update state + _totalAssets = SafeCast.toUint128(totalAssetsAfter); + _mintShares(to, shares); + + emit Deposited(msg.sender, to, assets, shares, referrer); + } - unchecked { - // cannot overflow as it is capped with _totalShares - _queuedShares = SafeCast.toUint128(queuedShares + shares); + /** + * @dev Internal function for sending user shares to the exit queue + * @param user The address of the user + * @param shares The number of shares to send to exit queue + * @param receiver The address that will receive the assets + * @return positionTicket The position ticket in the exit queue. Returns max uint256 if no ticket is created. + */ + function _enterExitQueue(address user, uint256 shares, address receiver) + internal + virtual + returns (uint256 positionTicket) + { + if (shares == 0) revert Errors.InvalidShares(); + if (receiver == address(0)) revert Errors.ZeroAddress(); + if (!_isCollateralized()) { + // calculate amount of assets to burn + uint256 assets = convertToAssets(shares); + if (assets == 0) revert Errors.InvalidAssets(); + + // update total assets + _totalAssets -= SafeCast.toUint128(assets); + + // burn owner shares + _burnShares(user, shares); + + // transfer assets to the receiver + _transferVaultAssets(receiver, assets); + + emit Redeemed(user, receiver, assets, shares); + + // no ticket is created, return max value + return type(uint256).max; + } + + // SLOAD to memory + uint256 queuedShares = _queuedShares; + + // calculate position ticket + positionTicket = _exitQueue.getLatestTotalTickets() + _totalExitingTickets + queuedShares; + + // add to the exit requests + _exitRequests[keccak256(abi.encode(receiver, block.timestamp, positionTicket))] = shares; + + // reverts if owner does not have enough shares + _balances[user] -= shares; + + unchecked { + // cannot overflow as it is capped with _totalShares + _queuedShares = SafeCast.toUint128(queuedShares + shares); + } + + emit ExitQueueEntered(user, receiver, positionTicket, shares); } - emit ExitQueueEntered(user, receiver, positionTicket, shares); - } - - /** - * @dev Internal function for transferring assets from the Vault to the receiver - * @dev IMPORTANT: because control is transferred to the receiver, care must be - * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: - * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern - * @param receiver The address that will receive the assets - * @param assets The number of assets to transfer - */ - function _transferVaultAssets(address receiver, uint256 assets) internal virtual; - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev Internal function for transferring assets from the Vault to the receiver + * @dev IMPORTANT: because control is transferred to the receiver, care must be + * taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern: + * https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern + * @param receiver The address that will receive the assets + * @param assets The number of assets to transfer + */ + function _transferVaultAssets(address receiver, uint256 assets) internal virtual; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultEthStaking.sol b/contracts/vaults/modules/VaultEthStaking.sol index 47483136..361f99d8 100644 --- a/contracts/vaults/modules/VaultEthStaking.sol +++ b/contracts/vaults/modules/VaultEthStaking.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {IEthValidatorsRegistry} from '../../interfaces/IEthValidatorsRegistry.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {IVaultEthStaking} from '../../interfaces/IVaultEthStaking.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; -import {VaultValidators} from './VaultValidators.sol'; -import {VaultState} from './VaultState.sol'; -import {VaultEnterExit} from './VaultEnterExit.sol'; -import {VaultMev} from './VaultMev.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {IEthValidatorsRegistry} from "../../interfaces/IEthValidatorsRegistry.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {IVaultEthStaking} from "../../interfaces/IVaultEthStaking.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {ValidatorUtils} from "../../libraries/ValidatorUtils.sol"; +import {VaultValidators} from "./VaultValidators.sol"; +import {VaultState} from "./VaultState.sol"; +import {VaultEnterExit} from "./VaultEnterExit.sol"; +import {VaultMev} from "./VaultMev.sol"; /** * @title VaultEthStaking @@ -20,98 +20,90 @@ import {VaultMev} from './VaultMev.sol'; * @notice Defines the Ethereum staking functionality for the Vault */ abstract contract VaultEthStaking is - Initializable, - VaultState, - VaultValidators, - VaultEnterExit, - VaultMev, - IVaultEthStaking + Initializable, + VaultState, + VaultValidators, + VaultEnterExit, + VaultMev, + IVaultEthStaking { - uint256 private constant _securityDeposit = 1e9; + uint256 private constant _securityDeposit = 1e9; - /// @inheritdoc IVaultEthStaking - function deposit( - address receiver, - address referrer - ) public payable virtual override returns (uint256 shares) { - return _deposit(receiver, msg.value, referrer); - } + /// @inheritdoc IVaultEthStaking + function deposit(address receiver, address referrer) public payable virtual override returns (uint256 shares) { + return _deposit(receiver, msg.value, referrer); + } - /// @inheritdoc IVaultEthStaking - function updateStateAndDeposit( - address receiver, - address referrer, - IKeeperRewards.HarvestParams calldata harvestParams - ) public payable virtual override returns (uint256 shares) { - updateState(harvestParams); - return deposit(receiver, referrer); - } + /// @inheritdoc IVaultEthStaking + function updateStateAndDeposit( + address receiver, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) public payable virtual override returns (uint256 shares) { + updateState(harvestParams); + return deposit(receiver, referrer); + } - /** - * @dev Function for depositing using fallback function - */ - receive() external payable virtual { - _deposit(msg.sender, msg.value, address(0)); - } + /** + * @dev Function for depositing using fallback function + */ + receive() external payable virtual { + _deposit(msg.sender, msg.value, address(0)); + } - /// @inheritdoc IVaultEthStaking - function receiveFromMevEscrow() external payable override { - if (msg.sender != mevEscrow()) revert Errors.AccessDenied(); - } + /// @inheritdoc IVaultEthStaking + function receiveFromMevEscrow() external payable override { + if (msg.sender != mevEscrow()) revert Errors.AccessDenied(); + } - /// @inheritdoc VaultValidators - function _registerValidators( - ValidatorUtils.ValidatorDeposit[] memory deposits - ) internal virtual override { - uint256 totalDeposits = deposits.length; - uint256 availableAssets = withdrawableAssets(); - ValidatorUtils.ValidatorDeposit memory depositData; - for (uint256 i = 0; i < totalDeposits; ) { - depositData = deposits[i]; - // deposit to the validators registry - IEthValidatorsRegistry(_validatorsRegistry).deposit{value: depositData.depositAmount}( - depositData.publicKey, - depositData.withdrawalCredentials, - depositData.signature, - depositData.depositDataRoot - ); + /// @inheritdoc VaultValidators + function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual override { + uint256 totalDeposits = deposits.length; + uint256 availableAssets = withdrawableAssets(); + ValidatorUtils.ValidatorDeposit memory depositData; + for (uint256 i = 0; i < totalDeposits;) { + depositData = deposits[i]; + // deposit to the validators registry + IEthValidatorsRegistry(_validatorsRegistry).deposit{value: depositData.depositAmount}( + depositData.publicKey, + depositData.withdrawalCredentials, + depositData.signature, + depositData.depositDataRoot + ); - // will revert if not enough assets - availableAssets -= depositData.depositAmount; + // will revert if not enough assets + availableAssets -= depositData.depositAmount; - unchecked { - // cannot realistically overflow - ++i; - } + unchecked { + // cannot realistically overflow + ++i; + } + } } - } - /// @inheritdoc VaultState - function _vaultAssets() internal view virtual override returns (uint256) { - return address(this).balance; - } + /// @inheritdoc VaultState + function _vaultAssets() internal view virtual override returns (uint256) { + return address(this).balance; + } - /// @inheritdoc VaultEnterExit - function _transferVaultAssets( - address receiver, - uint256 assets - ) internal virtual override nonReentrant { - return Address.sendValue(payable(receiver), assets); - } + /// @inheritdoc VaultEnterExit + function _transferVaultAssets(address receiver, uint256 assets) internal virtual override nonReentrant { + return Address.sendValue(payable(receiver), assets); + } - /** - * @dev Initializes the VaultEthStaking contract - */ - function __VaultEthStaking_init() internal onlyInitializing { - // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 - if (msg.value < _securityDeposit) revert Errors.InvalidSecurityDeposit(); - _deposit(address(this), msg.value, address(0)); - } + /** + * @dev Initializes the VaultEthStaking contract + */ + function __VaultEthStaking_init() internal onlyInitializing { + // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 + if (msg.value < _securityDeposit) revert Errors.InvalidSecurityDeposit(); + _deposit(address(this), msg.value, address(0)); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultFee.sol b/contracts/vaults/modules/VaultFee.sol index 0d28586f..fd6015fd 100644 --- a/contracts/vaults/modules/VaultFee.sol +++ b/contracts/vaults/modules/VaultFee.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IVaultFee} from '../../interfaces/IVaultFee.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; -import {VaultImmutables} from './VaultImmutables.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IVaultFee} from "../../interfaces/IVaultFee.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; /** * @title VaultFee @@ -14,85 +14,85 @@ import {VaultImmutables} from './VaultImmutables.sol'; * @notice Defines the fee functionality for the Vault */ abstract contract VaultFee is VaultImmutables, Initializable, VaultAdmin, IVaultFee { - uint256 internal constant _maxFeePercent = 10_000; // @dev 100.00 % - uint256 private constant _feeUpdateDelay = 7 days; - - /// @inheritdoc IVaultFee - address public override feeRecipient; - - /// @inheritdoc IVaultFee - uint16 public override feePercent; - - uint64 private _lastUpdateTimestamp; - - /// @inheritdoc IVaultFee - function setFeeRecipient(address _feeRecipient) external override { - _checkAdmin(); - _setFeeRecipient(_feeRecipient); - } - - /// @inheritdoc IVaultFee - function setFeePercent(uint16 _feePercent) external override { - _checkAdmin(); - _setFeePercent(_feePercent, false); - } - - /** - * @dev Internal function for updating the fee recipient externally or from the initializer - * @param _feeRecipient The address of the new fee recipient - */ - function _setFeeRecipient(address _feeRecipient) private { - _checkHarvested(); - if (_feeRecipient == address(0)) revert Errors.InvalidFeeRecipient(); - - // update fee recipient address - feeRecipient = _feeRecipient; - emit FeeRecipientUpdated(msg.sender, _feeRecipient); - } - - /** - * @dev Internal function for updating the fee percent - * @param _feePercent The new fee percent - * @param isVaultCreation Flag indicating whether the fee percent is set during the vault creation - */ - function _setFeePercent(uint16 _feePercent, bool isVaultCreation) private { - _checkHarvested(); - if (_feePercent > _maxFeePercent) revert Errors.InvalidFeePercent(); - - if (!isVaultCreation) { - if (_lastUpdateTimestamp + _feeUpdateDelay > block.timestamp) { - revert Errors.TooEarlyUpdate(); - } - - // check that the fee percent can be increase only by 20% at a time - // if the current fee is 0, then it can cannot exceed 1% initially - uint256 currentFeePercent = feePercent; - uint256 maxFeePercent = currentFeePercent > 0 ? (currentFeePercent * 120) / 100 : 100; - if (maxFeePercent < _feePercent) { - revert Errors.InvalidFeePercent(); - } + uint256 internal constant _maxFeePercent = 10_000; // @dev 100.00 % + uint256 private constant _feeUpdateDelay = 7 days; + + /// @inheritdoc IVaultFee + address public override feeRecipient; + + /// @inheritdoc IVaultFee + uint16 public override feePercent; + + uint64 private _lastUpdateTimestamp; + + /// @inheritdoc IVaultFee + function setFeeRecipient(address _feeRecipient) external override { + _checkAdmin(); + _setFeeRecipient(_feeRecipient); + } + + /// @inheritdoc IVaultFee + function setFeePercent(uint16 _feePercent) external override { + _checkAdmin(); + _setFeePercent(_feePercent, false); + } + + /** + * @dev Internal function for updating the fee recipient externally or from the initializer + * @param _feeRecipient The address of the new fee recipient + */ + function _setFeeRecipient(address _feeRecipient) private { + _checkHarvested(); + if (_feeRecipient == address(0)) revert Errors.InvalidFeeRecipient(); + + // update fee recipient address + feeRecipient = _feeRecipient; + emit FeeRecipientUpdated(msg.sender, _feeRecipient); + } + + /** + * @dev Internal function for updating the fee percent + * @param _feePercent The new fee percent + * @param isVaultCreation Flag indicating whether the fee percent is set during the vault creation + */ + function _setFeePercent(uint16 _feePercent, bool isVaultCreation) private { + _checkHarvested(); + if (_feePercent > _maxFeePercent) revert Errors.InvalidFeePercent(); + + if (!isVaultCreation) { + if (_lastUpdateTimestamp + _feeUpdateDelay > block.timestamp) { + revert Errors.TooEarlyUpdate(); + } + + // check that the fee percent can be increase only by 20% at a time + // if the current fee is 0, then it can cannot exceed 1% initially + uint256 currentFeePercent = feePercent; + uint256 maxFeePercent = currentFeePercent > 0 ? (currentFeePercent * 120) / 100 : 100; + if (maxFeePercent < _feePercent) { + revert Errors.InvalidFeePercent(); + } + } + + // update fee percent + feePercent = _feePercent; + _lastUpdateTimestamp = uint64(block.timestamp); + emit FeePercentUpdated(msg.sender, _feePercent); + } + + /** + * @dev Initializes the VaultFee contract + * @param _feeRecipient The address of the fee recipient + * @param _feePercent The fee percent that is charged by the Vault + */ + function __VaultFee_init(address _feeRecipient, uint16 _feePercent) internal onlyInitializing { + _setFeeRecipient(_feeRecipient); + _setFeePercent(_feePercent, true); } - // update fee percent - feePercent = _feePercent; - _lastUpdateTimestamp = uint64(block.timestamp); - emit FeePercentUpdated(msg.sender, _feePercent); - } - - /** - * @dev Initializes the VaultFee contract - * @param _feeRecipient The address of the fee recipient - * @param _feePercent The fee percent that is charged by the Vault - */ - function __VaultFee_init(address _feeRecipient, uint16 _feePercent) internal onlyInitializing { - _setFeeRecipient(_feeRecipient); - _setFeePercent(_feePercent, true); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultGnoStaking.sol b/contracts/vaults/modules/VaultGnoStaking.sol index 84aacd6e..3ecd137e 100644 --- a/contracts/vaults/modules/VaultGnoStaking.sol +++ b/contracts/vaults/modules/VaultGnoStaking.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoValidatorsRegistry} from '../../interfaces/IGnoValidatorsRegistry.sol'; -import {IVaultGnoStaking} from '../../interfaces/IVaultGnoStaking.sol'; -import {IGnoDaiDistributor} from '../../interfaces/IGnoDaiDistributor.sol'; -import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; -import {VaultState} from './VaultState.sol'; -import {VaultValidators} from './VaultValidators.sol'; -import {VaultEnterExit} from './VaultEnterExit.sol'; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoValidatorsRegistry} from "../../interfaces/IGnoValidatorsRegistry.sol"; +import {IVaultGnoStaking} from "../../interfaces/IVaultGnoStaking.sol"; +import {IGnoDaiDistributor} from "../../interfaces/IGnoDaiDistributor.sol"; +import {ValidatorUtils} from "../../libraries/ValidatorUtils.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; +import {VaultState} from "./VaultState.sol"; +import {VaultValidators} from "./VaultValidators.sol"; +import {VaultEnterExit} from "./VaultEnterExit.sol"; /** * @title VaultGnoStaking @@ -20,141 +20,137 @@ import {VaultEnterExit} from './VaultEnterExit.sol'; * @notice Defines the Gnosis staking functionality for the Vault */ abstract contract VaultGnoStaking is - Initializable, - VaultAdmin, - VaultState, - VaultValidators, - VaultEnterExit, - IVaultGnoStaking + Initializable, + VaultAdmin, + VaultState, + VaultValidators, + VaultEnterExit, + IVaultGnoStaking { - uint256 private constant _securityDeposit = 1e9; - - IERC20 internal immutable _gnoToken; - IGnoDaiDistributor private immutable _gnoDaiDistributor; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param gnoToken The address of the GNO token - * @param gnoDaiDistributor The address of the xDAI distributor contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address gnoToken, address gnoDaiDistributor) { - _gnoToken = IERC20(gnoToken); - _gnoDaiDistributor = IGnoDaiDistributor(gnoDaiDistributor); - } - - /// @inheritdoc IVaultGnoStaking - function deposit( - uint256 assets, - address receiver, - address referrer - ) public virtual override nonReentrant returns (uint256 shares) { - // withdraw GNO tokens from the user - SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), assets); - shares = _deposit(receiver, assets, referrer); - } - - /// @inheritdoc VaultState - function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override { - super._processTotalAssetsDelta(assetsDelta); - - uint256 balance = address(this).balance; - if (balance < 0.1 ether) return; - - _gnoDaiDistributor.distributeSDai{value: balance}(); - } - - /** - * @dev Function for receiving xDAI - */ - receive() external payable {} - - /// @inheritdoc VaultValidators - function _registerValidators( - ValidatorUtils.ValidatorDeposit[] memory deposits - ) internal virtual override { - // pull withdrawals from the deposit contract - _pullWithdrawals(); - - uint256 totalDeposits = deposits.length; - uint256 availableAssets = withdrawableAssets(); - ValidatorUtils.ValidatorDeposit memory depositData; - for (uint256 i = 0; i < totalDeposits; ) { - depositData = deposits[i]; - - // divide by 32 to convert mGNO to GNO - depositData.depositAmount /= 32; - - // deposit GNO tokens to the validators registry - IGnoValidatorsRegistry(_validatorsRegistry).deposit( - depositData.publicKey, - depositData.withdrawalCredentials, - depositData.signature, - depositData.depositDataRoot, - depositData.depositAmount - ); - - // will revert if not enough assets - availableAssets -= depositData.depositAmount; - - unchecked { - // cannot realistically overflow - ++i; - } + uint256 private constant _securityDeposit = 1e9; + + IERC20 internal immutable _gnoToken; + IGnoDaiDistributor private immutable _gnoDaiDistributor; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param gnoToken The address of the GNO token + * @param gnoDaiDistributor The address of the xDAI distributor contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address gnoToken, address gnoDaiDistributor) { + _gnoToken = IERC20(gnoToken); + _gnoDaiDistributor = IGnoDaiDistributor(gnoDaiDistributor); } - } - - /// @inheritdoc VaultState - function _vaultAssets() internal view virtual override returns (uint256) { - return - _gnoToken.balanceOf(address(this)) + - IGnoValidatorsRegistry(_validatorsRegistry).withdrawableAmount(address(this)); - } - - /// @inheritdoc VaultEnterExit - function _transferVaultAssets( - address receiver, - uint256 assets - ) internal virtual override nonReentrant { - if (assets > _gnoToken.balanceOf(address(this))) { - _pullWithdrawals(); + + /// @inheritdoc IVaultGnoStaking + function deposit(uint256 assets, address receiver, address referrer) + public + virtual + override + nonReentrant + returns (uint256 shares) + { + // withdraw GNO tokens from the user + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), assets); + shares = _deposit(receiver, assets, referrer); + } + + /// @inheritdoc VaultState + function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override { + super._processTotalAssetsDelta(assetsDelta); + + uint256 balance = address(this).balance; + if (balance < 0.1 ether) return; + + _gnoDaiDistributor.distributeSDai{value: balance}(); } - SafeERC20.safeTransfer(_gnoToken, receiver, assets); - } - - /** - * @dev Pulls assets from withdrawal contract - */ - function _pullWithdrawals() internal virtual { - IGnoValidatorsRegistry(_validatorsRegistry).claimWithdrawal(address(this)); - } - - /** - * @dev Upgrades the VaultGnoStaking contract - */ - function __VaultGnoStaking_upgrade() internal onlyInitializing { - // approve transferring GNO for validators registration - _gnoToken.approve(_validatorsRegistry, type(uint256).max); - } - - /** - * @dev Initializes the VaultGnoStaking contract - */ - function __VaultGnoStaking_init() internal onlyInitializing { - // approve transferring GNO for validators registration - _gnoToken.approve(_validatorsRegistry, type(uint256).max); - - _deposit(address(this), _securityDeposit, address(0)); - // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 - SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + + /** + * @dev Function for receiving xDAI + */ + receive() external payable {} + + /// @inheritdoc VaultValidators + function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual override { + // pull withdrawals from the deposit contract + _pullWithdrawals(); + + uint256 totalDeposits = deposits.length; + uint256 availableAssets = withdrawableAssets(); + ValidatorUtils.ValidatorDeposit memory depositData; + for (uint256 i = 0; i < totalDeposits;) { + depositData = deposits[i]; + + // divide by 32 to convert mGNO to GNO + depositData.depositAmount /= 32; + + // deposit GNO tokens to the validators registry + IGnoValidatorsRegistry(_validatorsRegistry).deposit( + depositData.publicKey, + depositData.withdrawalCredentials, + depositData.signature, + depositData.depositDataRoot, + depositData.depositAmount + ); + + // will revert if not enough assets + availableAssets -= depositData.depositAmount; + + unchecked { + // cannot realistically overflow + ++i; + } + } + } + + /// @inheritdoc VaultState + function _vaultAssets() internal view virtual override returns (uint256) { + return _gnoToken.balanceOf(address(this)) + + IGnoValidatorsRegistry(_validatorsRegistry).withdrawableAmount(address(this)); + } + + /// @inheritdoc VaultEnterExit + function _transferVaultAssets(address receiver, uint256 assets) internal virtual override nonReentrant { + if (assets > _gnoToken.balanceOf(address(this))) { + _pullWithdrawals(); + } + SafeERC20.safeTransfer(_gnoToken, receiver, assets); + } + + /** + * @dev Pulls assets from withdrawal contract + */ + function _pullWithdrawals() internal virtual { + IGnoValidatorsRegistry(_validatorsRegistry).claimWithdrawal(address(this)); + } + + /** + * @dev Upgrades the VaultGnoStaking contract + */ + function __VaultGnoStaking_upgrade() internal onlyInitializing { + // approve transferring GNO for validators registration + _gnoToken.approve(_validatorsRegistry, type(uint256).max); + } + + /** + * @dev Initializes the VaultGnoStaking contract + */ + function __VaultGnoStaking_init() internal onlyInitializing { + // approve transferring GNO for validators registration + _gnoToken.approve(_validatorsRegistry, type(uint256).max); + + _deposit(address(this), _securityDeposit, address(0)); + // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultImmutables.sol b/contracts/vaults/modules/VaultImmutables.sol index 848475bf..17a3ad3c 100644 --- a/contracts/vaults/modules/VaultImmutables.sol +++ b/contracts/vaults/modules/VaultImmutables.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.22; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {Errors} from '../../libraries/Errors.sol'; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {Errors} from "../../libraries/Errors.sol"; /** * @title VaultImmutables @@ -11,44 +11,44 @@ import {Errors} from '../../libraries/Errors.sol'; * @notice Defines the Vault common immutable variables */ abstract contract VaultImmutables { - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address internal immutable _keeper; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address internal immutable _vaultsRegistry; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address keeper, address vaultsRegistry) { - _keeper = keeper; - _vaultsRegistry = vaultsRegistry; - } - - /** - * @dev Internal method for checking whether the vault is harvested - */ - function _checkHarvested() internal view { - if (IKeeperRewards(_keeper).isHarvestRequired(address(this))) revert Errors.NotHarvested(); - } - - /** - * @dev Internal method for checking whether the vault is collateralized - */ - function _checkCollateralized() internal view { - if (!_isCollateralized()) revert Errors.NotCollateralized(); - } - - /** - * @dev Returns whether the vault is collateralized - * @return true if the vault is collateralized - */ - function _isCollateralized() internal view returns (bool) { - return IKeeperRewards(_keeper).isCollateralized(address(this)); - } + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address internal immutable _keeper; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address internal immutable _vaultsRegistry; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address keeper, address vaultsRegistry) { + _keeper = keeper; + _vaultsRegistry = vaultsRegistry; + } + + /** + * @dev Internal method for checking whether the vault is harvested + */ + function _checkHarvested() internal view { + if (IKeeperRewards(_keeper).isHarvestRequired(address(this))) revert Errors.NotHarvested(); + } + + /** + * @dev Internal method for checking whether the vault is collateralized + */ + function _checkCollateralized() internal view { + if (!_isCollateralized()) revert Errors.NotCollateralized(); + } + + /** + * @dev Returns whether the vault is collateralized + * @return true if the vault is collateralized + */ + function _isCollateralized() internal view returns (bool) { + return IKeeperRewards(_keeper).isCollateralized(address(this)); + } } diff --git a/contracts/vaults/modules/VaultMev.sol b/contracts/vaults/modules/VaultMev.sol index aaac33c7..35343b52 100644 --- a/contracts/vaults/modules/VaultMev.sol +++ b/contracts/vaults/modules/VaultMev.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {ISharedMevEscrow} from '../../interfaces/ISharedMevEscrow.sol'; -import {IOwnMevEscrow} from '../../interfaces/IOwnMevEscrow.sol'; -import {IVaultMev} from '../../interfaces/IVaultMev.sol'; -import {VaultState} from './VaultState.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {ISharedMevEscrow} from "../../interfaces/ISharedMevEscrow.sol"; +import {IOwnMevEscrow} from "../../interfaces/IOwnMevEscrow.sol"; +import {IVaultMev} from "../../interfaces/IVaultMev.sol"; +import {VaultState} from "./VaultState.sol"; /** * @title VaultMev @@ -15,64 +15,66 @@ import {VaultState} from './VaultState.sol'; * @notice Defines the Vaults' MEV functionality */ abstract contract VaultMev is Initializable, VaultState, IVaultMev { - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _sharedMevEscrow; - address private _ownMevEscrow; + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _sharedMevEscrow; + address private _ownMevEscrow; - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param sharedMevEscrow The address of the shared MEV escrow - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address sharedMevEscrow) { - _sharedMevEscrow = sharedMevEscrow; - } + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param sharedMevEscrow The address of the shared MEV escrow + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address sharedMevEscrow) { + _sharedMevEscrow = sharedMevEscrow; + } - /// @inheritdoc IVaultMev - function mevEscrow() public view override returns (address) { - // SLOAD to memory - address ownMevEscrow = _ownMevEscrow; - return ownMevEscrow != address(0) ? ownMevEscrow : _sharedMevEscrow; - } + /// @inheritdoc IVaultMev + function mevEscrow() public view override returns (address) { + // SLOAD to memory + address ownMevEscrow = _ownMevEscrow; + return ownMevEscrow != address(0) ? ownMevEscrow : _sharedMevEscrow; + } - /// @inheritdoc VaultState - function _harvestAssets( - IKeeperRewards.HarvestParams calldata harvestParams - ) internal override returns (int256, bool) { - (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested) = IKeeperRewards(_keeper) - .harvest(harvestParams); + /// @inheritdoc VaultState + function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) + internal + override + returns (int256, bool) + { + (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested) = + IKeeperRewards(_keeper).harvest(harvestParams); - // harvest execution rewards only when consensus rewards were harvested - if (!harvested) return (totalAssetsDelta, harvested); + // harvest execution rewards only when consensus rewards were harvested + if (!harvested) return (totalAssetsDelta, harvested); - // SLOAD to memory - address _mevEscrow = mevEscrow(); - if (_mevEscrow == _sharedMevEscrow) { - if (unlockedMevDelta > 0) { - // withdraw assets from shared escrow only in case reward is positive - ISharedMevEscrow(_mevEscrow).harvest(unlockedMevDelta); - } - return (totalAssetsDelta, harvested); - } + // SLOAD to memory + address _mevEscrow = mevEscrow(); + if (_mevEscrow == _sharedMevEscrow) { + if (unlockedMevDelta > 0) { + // withdraw assets from shared escrow only in case reward is positive + ISharedMevEscrow(_mevEscrow).harvest(unlockedMevDelta); + } + return (totalAssetsDelta, harvested); + } - // execution rewards are always equal to what was accumulated in own MEV escrow - return (totalAssetsDelta + int256(IOwnMevEscrow(_mevEscrow).harvest()), harvested); - } + // execution rewards are always equal to what was accumulated in own MEV escrow + return (totalAssetsDelta + int256(IOwnMevEscrow(_mevEscrow).harvest()), harvested); + } - /** - * @dev Initializes the VaultMev contract - * @param ownMevEscrow The address of the own MEV escrow contract - */ - function __VaultMev_init(address ownMevEscrow) internal onlyInitializing { - if (ownMevEscrow != address(0)) _ownMevEscrow = ownMevEscrow; - } + /** + * @dev Initializes the VaultMev contract + * @param ownMevEscrow The address of the own MEV escrow contract + */ + function __VaultMev_init(address ownMevEscrow) internal onlyInitializing { + if (ownMevEscrow != address(0)) _ownMevEscrow = ownMevEscrow; + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultOsToken.sol b/contracts/vaults/modules/VaultOsToken.sol index 2bc30b78..0edb983e 100644 --- a/contracts/vaults/modules/VaultOsToken.sol +++ b/contracts/vaults/modules/VaultOsToken.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.22; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {IOsTokenVaultController} from '../../interfaces/IOsTokenVaultController.sol'; -import {IOsTokenConfig} from '../../interfaces/IOsTokenConfig.sol'; -import {IVaultOsToken} from '../../interfaces/IVaultOsToken.sol'; -import {IOsTokenVaultEscrow} from '../../interfaces/IOsTokenVaultEscrow.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultImmutables} from './VaultImmutables.sol'; -import {VaultEnterExit, IVaultEnterExit} from './VaultEnterExit.sol'; -import {VaultState} from './VaultState.sol'; -import {OsTokenUtils} from '../../libraries/OsTokenUtils.sol'; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {IOsTokenVaultController} from "../../interfaces/IOsTokenVaultController.sol"; +import {IOsTokenConfig} from "../../interfaces/IOsTokenConfig.sol"; +import {IVaultOsToken} from "../../interfaces/IVaultOsToken.sol"; +import {IOsTokenVaultEscrow} from "../../interfaces/IOsTokenVaultEscrow.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; +import {VaultEnterExit, IVaultEnterExit} from "./VaultEnterExit.sol"; +import {VaultState} from "./VaultState.sol"; +import {OsTokenUtils} from "../../libraries/OsTokenUtils.sol"; /** * @title VaultOsToken @@ -20,329 +20,297 @@ import {OsTokenUtils} from '../../libraries/OsTokenUtils.sol'; * @notice Defines the functionality for minting OsToken */ abstract contract VaultOsToken is VaultImmutables, VaultState, VaultEnterExit, IVaultOsToken { - uint256 private constant _maxPercent = 1e18; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IOsTokenVaultController private immutable _osTokenVaultController; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IOsTokenConfig internal immutable _osTokenConfig; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IOsTokenVaultEscrow private immutable _osTokenVaultEscrow; - - mapping(address => OsTokenPosition) private _positions; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param osTokenVaultController The address of the OsTokenVaultController contract - * @param osTokenConfig The address of the OsTokenConfig contract - * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address osTokenVaultController, address osTokenConfig, address osTokenVaultEscrow) { - _osTokenVaultController = IOsTokenVaultController(osTokenVaultController); - _osTokenConfig = IOsTokenConfig(osTokenConfig); - _osTokenVaultEscrow = IOsTokenVaultEscrow(osTokenVaultEscrow); - } - - /// @inheritdoc IVaultOsToken - function osTokenPositions(address user) public view override returns (uint128 shares) { - OsTokenPosition memory position = _positions[user]; - if (position.shares != 0) _syncPositionFee(position); - return position.shares; - } - - /// @inheritdoc IVaultOsToken - function mintOsToken( - address receiver, - uint256 osTokenShares, - address referrer - ) public virtual override returns (uint256 assets) { - return _mintOsToken(msg.sender, receiver, osTokenShares, referrer); - } - - /// @inheritdoc IVaultOsToken - function burnOsToken(uint128 osTokenShares) external override returns (uint256 assets) { - // burn osToken shares - assets = _osTokenVaultController.burnShares(msg.sender, osTokenShares); - - // fetch user position - OsTokenPosition memory position = _positions[msg.sender]; - if (position.shares == 0) revert Errors.InvalidPosition(); - _syncPositionFee(position); - - // update osToken position - position.shares -= osTokenShares; - _positions[msg.sender] = position; - - // emit event - emit OsTokenBurned(msg.sender, assets, osTokenShares); - } - - /// @inheritdoc IVaultOsToken - function liquidateOsToken( - uint256 osTokenShares, - address owner, - address receiver - ) external override { - (uint256 burnedShares, uint256 receivedAssets) = _redeemOsToken( - owner, - receiver, - osTokenShares, - true - ); - emit OsTokenLiquidated( - msg.sender, - owner, - receiver, - osTokenShares, - burnedShares, - receivedAssets - ); - } - - /// @inheritdoc IVaultOsToken - function redeemOsToken(uint256 osTokenShares, address owner, address receiver) external override { - if (msg.sender != _osTokenConfig.redeemer()) revert Errors.AccessDenied(); - (uint256 burnedShares, uint256 receivedAssets) = _redeemOsToken( - owner, - receiver, - osTokenShares, - false - ); - emit OsTokenRedeemed(msg.sender, owner, receiver, osTokenShares, burnedShares, receivedAssets); - } - - /// @inheritdoc IVaultOsToken - function transferOsTokenPositionToEscrow( - uint256 osTokenShares - ) external override returns (uint256 positionTicket) { - // check whether vault assets are up to date - _checkHarvested(); - - // fetch user osToken position - OsTokenPosition memory position = _positions[msg.sender]; - if (position.shares == 0) revert Errors.InvalidPosition(); - - // sync accumulated fee - _syncPositionFee(position); - if (position.shares < osTokenShares) revert Errors.InvalidShares(); - - // calculate shares to enter the exit queue - uint256 exitShares = _balances[msg.sender]; - if (position.shares != osTokenShares) { - // calculate exit shares - exitShares = Math.mulDiv(exitShares, osTokenShares, position.shares); - // update osToken position - unchecked { - // cannot underflow because position.shares >= osTokenShares - position.shares -= SafeCast.toUint128(osTokenShares); - } - _positions[msg.sender] = position; - } else { - // all the assets are sent to the exit queue, remove position - delete _positions[msg.sender]; + uint256 private constant _maxPercent = 1e18; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IOsTokenVaultController private immutable _osTokenVaultController; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IOsTokenConfig internal immutable _osTokenConfig; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IOsTokenVaultEscrow private immutable _osTokenVaultEscrow; + + mapping(address => OsTokenPosition) private _positions; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address osTokenVaultController, address osTokenConfig, address osTokenVaultEscrow) { + _osTokenVaultController = IOsTokenVaultController(osTokenVaultController); + _osTokenConfig = IOsTokenConfig(osTokenConfig); + _osTokenVaultEscrow = IOsTokenVaultEscrow(osTokenVaultEscrow); + } + + /// @inheritdoc IVaultOsToken + function osTokenPositions(address user) public view override returns (uint128 shares) { + OsTokenPosition memory position = _positions[user]; + if (position.shares != 0) _syncPositionFee(position); + return position.shares; + } + + /// @inheritdoc IVaultOsToken + function mintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + virtual + override + returns (uint256 assets) + { + return _mintOsToken(msg.sender, receiver, osTokenShares, referrer); + } + + /// @inheritdoc IVaultOsToken + function burnOsToken(uint128 osTokenShares) external override returns (uint256 assets) { + // burn osToken shares + assets = _osTokenVaultController.burnShares(msg.sender, osTokenShares); + + // fetch user position + OsTokenPosition memory position = _positions[msg.sender]; + if (position.shares == 0) revert Errors.InvalidPosition(); + _syncPositionFee(position); + + // update osToken position + position.shares -= osTokenShares; + _positions[msg.sender] = position; + + // emit event + emit OsTokenBurned(msg.sender, assets, osTokenShares); + } + + /// @inheritdoc IVaultOsToken + function liquidateOsToken(uint256 osTokenShares, address owner, address receiver) external override { + (uint256 burnedShares, uint256 receivedAssets) = _redeemOsToken(owner, receiver, osTokenShares, true); + emit OsTokenLiquidated(msg.sender, owner, receiver, osTokenShares, burnedShares, receivedAssets); + } + + /// @inheritdoc IVaultOsToken + function redeemOsToken(uint256 osTokenShares, address owner, address receiver) external override { + if (msg.sender != _osTokenConfig.redeemer()) revert Errors.AccessDenied(); + (uint256 burnedShares, uint256 receivedAssets) = _redeemOsToken(owner, receiver, osTokenShares, false); + emit OsTokenRedeemed(msg.sender, owner, receiver, osTokenShares, burnedShares, receivedAssets); } - // enter the exit queue - positionTicket = super.enterExitQueue(exitShares, address(_osTokenVaultEscrow)); - - // transfer to escrow - _osTokenVaultEscrow.register( - msg.sender, - positionTicket, - osTokenShares, - position.cumulativeFeePerShare - ); - } - - /// @inheritdoc IVaultEnterExit - function enterExitQueue( - uint256 shares, - address receiver - ) public virtual override(IVaultEnterExit, VaultEnterExit) returns (uint256 positionTicket) { - positionTicket = super.enterExitQueue(shares, receiver); - _checkOsTokenPosition(msg.sender); - } - - /** - * @dev Internal function for minting osToken shares - * @param owner The owner of the osToken position - * @param receiver The receiver of the osToken shares - * @param osTokenShares The amount of osToken shares to mint - * @param referrer The address of the referrer - * @return assets The amount of assets minted - */ - function _mintOsToken( - address owner, - address receiver, - uint256 osTokenShares, - address referrer - ) internal returns (uint256 assets) { - _checkCollateralized(); - _checkHarvested(); - - // fetch user position - OsTokenPosition memory position = _positions[owner]; - if (position.shares != 0) { - _syncPositionFee(position); - } else { - position.cumulativeFeePerShare = SafeCast.toUint128( - _osTokenVaultController.cumulativeFeePerShare() - ); + /// @inheritdoc IVaultOsToken + function transferOsTokenPositionToEscrow(uint256 osTokenShares) + external + override + returns (uint256 positionTicket) + { + // check whether vault assets are up to date + _checkHarvested(); + + // fetch user osToken position + OsTokenPosition memory position = _positions[msg.sender]; + if (position.shares == 0) revert Errors.InvalidPosition(); + + // sync accumulated fee + _syncPositionFee(position); + if (position.shares < osTokenShares) revert Errors.InvalidShares(); + + // calculate shares to enter the exit queue + uint256 exitShares = _balances[msg.sender]; + if (position.shares != osTokenShares) { + // calculate exit shares + exitShares = Math.mulDiv(exitShares, osTokenShares, position.shares); + // update osToken position + unchecked { + // cannot underflow because position.shares >= osTokenShares + position.shares -= SafeCast.toUint128(osTokenShares); + } + _positions[msg.sender] = position; + } else { + // all the assets are sent to the exit queue, remove position + delete _positions[msg.sender]; + } + + // enter the exit queue + positionTicket = super.enterExitQueue(exitShares, address(_osTokenVaultEscrow)); + + // transfer to escrow + _osTokenVaultEscrow.register(msg.sender, positionTicket, osTokenShares, position.cumulativeFeePerShare); } - // calculate max osToken shares that user can mint - uint256 userMaxOsTokenShares = _calcMaxOsTokenShares(convertToAssets(_balances[owner])); - if (osTokenShares == type(uint256).max) { - if (userMaxOsTokenShares <= position.shares) { - return 0; - } - // calculate max OsToken shares that can be minted - unchecked { - // cannot underflow because position.shares < userMaxOsTokenShares - osTokenShares = userMaxOsTokenShares - position.shares; - } + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit) + returns (uint256 positionTicket) + { + positionTicket = super.enterExitQueue(shares, receiver); + _checkOsTokenPosition(msg.sender); } - // mint osToken shares to the receiver - assets = _osTokenVaultController.mintShares(receiver, osTokenShares); + /** + * @dev Internal function for minting osToken shares + * @param owner The owner of the osToken position + * @param receiver The receiver of the osToken shares + * @param osTokenShares The amount of osToken shares to mint + * @param referrer The address of the referrer + * @return assets The amount of assets minted + */ + function _mintOsToken(address owner, address receiver, uint256 osTokenShares, address referrer) + internal + returns (uint256 assets) + { + _checkCollateralized(); + _checkHarvested(); + + // fetch user position + OsTokenPosition memory position = _positions[owner]; + if (position.shares != 0) { + _syncPositionFee(position); + } else { + position.cumulativeFeePerShare = SafeCast.toUint128(_osTokenVaultController.cumulativeFeePerShare()); + } + + // calculate max osToken shares that user can mint + uint256 userMaxOsTokenShares = _calcMaxOsTokenShares(convertToAssets(_balances[owner])); + if (osTokenShares == type(uint256).max) { + if (userMaxOsTokenShares <= position.shares) { + return 0; + } + // calculate max OsToken shares that can be minted + unchecked { + // cannot underflow because position.shares < userMaxOsTokenShares + osTokenShares = userMaxOsTokenShares - position.shares; + } + } + + // mint osToken shares to the receiver + assets = _osTokenVaultController.mintShares(receiver, osTokenShares); + + // add minted shares to the position + position.shares += SafeCast.toUint128(osTokenShares); + + // calculate and validate LTV + if (userMaxOsTokenShares < position.shares) { + revert Errors.LowLtv(); + } + + // update state + _positions[owner] = position; + + // emit event + emit OsTokenMinted(owner, receiver, assets, osTokenShares, referrer); + } + + /** + * @dev Internal function for redeeming and liquidating osToken shares + * @param owner The minter of the osToken shares + * @param receiver The receiver of the assets + * @param osTokenShares The amount of osToken shares to redeem or liquidate + * @param isLiquidation Whether the liquidation or redemption is being performed + * @return burnedShares The amount of shares burned + * @return receivedAssets The amount of assets received + */ + function _redeemOsToken(address owner, address receiver, uint256 osTokenShares, bool isLiquidation) + private + returns (uint256 burnedShares, uint256 receivedAssets) + { + if (receiver == address(0)) revert Errors.ZeroAddress(); + _checkHarvested(); + + // update osToken state for gas efficiency + _osTokenVaultController.updateState(); + + // fetch user position + OsTokenPosition memory position = _positions[owner]; + if (position.shares == 0) revert Errors.InvalidPosition(); + _syncPositionFee(position); + + // calculate received assets + receivedAssets = OsTokenUtils.calculateReceivedAssets( + _osTokenConfig, + _osTokenVaultController, + OsTokenUtils.RedemptionData({ + mintedAssets: _osTokenVaultController.convertToAssets(position.shares), + depositedAssets: convertToAssets(_balances[owner]), + redeemedOsTokenShares: osTokenShares, + availableAssets: withdrawableAssets(), + isLiquidation: isLiquidation + }) + ); + + // reduce osToken supply + _osTokenVaultController.burnShares(msg.sender, osTokenShares); + + // update osToken position + position.shares -= SafeCast.toUint128(osTokenShares); + _positions[owner] = position; - // add minted shares to the position - position.shares += SafeCast.toUint128(osTokenShares); + burnedShares = convertToShares(receivedAssets); - // calculate and validate LTV - if (userMaxOsTokenShares < position.shares) { - revert Errors.LowLtv(); + // update total assets + unchecked { + _totalAssets -= SafeCast.toUint128(receivedAssets); + } + + // burn owner shares + _burnShares(owner, burnedShares); + + // transfer assets to the receiver + _transferVaultAssets(receiver, receivedAssets); } - // update state - _positions[owner] = position; - - // emit event - emit OsTokenMinted(owner, receiver, assets, osTokenShares, referrer); - } - - /** - * @dev Internal function for redeeming and liquidating osToken shares - * @param owner The minter of the osToken shares - * @param receiver The receiver of the assets - * @param osTokenShares The amount of osToken shares to redeem or liquidate - * @param isLiquidation Whether the liquidation or redemption is being performed - * @return burnedShares The amount of shares burned - * @return receivedAssets The amount of assets received - */ - function _redeemOsToken( - address owner, - address receiver, - uint256 osTokenShares, - bool isLiquidation - ) private returns (uint256 burnedShares, uint256 receivedAssets) { - if (receiver == address(0)) revert Errors.ZeroAddress(); - _checkHarvested(); - - // update osToken state for gas efficiency - _osTokenVaultController.updateState(); - - // fetch user position - OsTokenPosition memory position = _positions[owner]; - if (position.shares == 0) revert Errors.InvalidPosition(); - _syncPositionFee(position); - - // calculate received assets - receivedAssets = OsTokenUtils.calculateReceivedAssets( - _osTokenConfig, - _osTokenVaultController, - OsTokenUtils.RedemptionData({ - mintedAssets: _osTokenVaultController.convertToAssets(position.shares), - depositedAssets: convertToAssets(_balances[owner]), - redeemedOsTokenShares: osTokenShares, - availableAssets: withdrawableAssets(), - isLiquidation: isLiquidation - }) - ); - - // reduce osToken supply - _osTokenVaultController.burnShares(msg.sender, osTokenShares); - - // update osToken position - position.shares -= SafeCast.toUint128(osTokenShares); - _positions[owner] = position; - - burnedShares = convertToShares(receivedAssets); - - // update total assets - unchecked { - _totalAssets -= SafeCast.toUint128(receivedAssets); + /** + * @dev Internal function for syncing the osToken fee + * @param position The position to sync the fee for + */ + function _syncPositionFee(OsTokenPosition memory position) private view { + // fetch current cumulative fee per share + uint256 cumulativeFeePerShare = _osTokenVaultController.cumulativeFeePerShare(); + + // check whether fee is already up to date + if (cumulativeFeePerShare == position.cumulativeFeePerShare) return; + + // add treasury fee to the position + position.shares = + SafeCast.toUint128(Math.mulDiv(position.shares, cumulativeFeePerShare, position.cumulativeFeePerShare)); + position.cumulativeFeePerShare = SafeCast.toUint128(cumulativeFeePerShare); } - // burn owner shares - _burnShares(owner, burnedShares); - - // transfer assets to the receiver - _transferVaultAssets(receiver, receivedAssets); - } - - /** - * @dev Internal function for syncing the osToken fee - * @param position The position to sync the fee for - */ - function _syncPositionFee(OsTokenPosition memory position) private view { - // fetch current cumulative fee per share - uint256 cumulativeFeePerShare = _osTokenVaultController.cumulativeFeePerShare(); - - // check whether fee is already up to date - if (cumulativeFeePerShare == position.cumulativeFeePerShare) return; - - // add treasury fee to the position - position.shares = SafeCast.toUint128( - Math.mulDiv(position.shares, cumulativeFeePerShare, position.cumulativeFeePerShare) - ); - position.cumulativeFeePerShare = SafeCast.toUint128(cumulativeFeePerShare); - } - - /** - * @notice Internal function for checking position validity. Reverts if it is invalid. - * @param user The address of the user - */ - function _checkOsTokenPosition(address user) internal view { - // fetch user position - OsTokenPosition memory position = _positions[user]; - if (position.shares == 0) return; - - // check whether vault assets are up to date - _checkHarvested(); - - // sync fee - _syncPositionFee(position); - - // calculate and validate position LTV - if (_calcMaxOsTokenShares(convertToAssets(_balances[user])) < position.shares) { - revert Errors.LowLtv(); + /** + * @notice Internal function for checking position validity. Reverts if it is invalid. + * @param user The address of the user + */ + function _checkOsTokenPosition(address user) internal view { + // fetch user position + OsTokenPosition memory position = _positions[user]; + if (position.shares == 0) return; + + // check whether vault assets are up to date + _checkHarvested(); + + // sync fee + _syncPositionFee(position); + + // calculate and validate position LTV + if (_calcMaxOsTokenShares(convertToAssets(_balances[user])) < position.shares) { + revert Errors.LowLtv(); + } } - } - - /** - * @dev Internal function for calculating the maximum amount of osToken shares that can be minted - * @param assets The amount of assets to convert to osToken shares - * @return maxOsTokenShares The maximum amount of osToken shares that can be minted - */ - function _calcMaxOsTokenShares(uint256 assets) internal view returns (uint256) { - uint256 maxOsTokenAssets = Math.mulDiv( - assets, - _osTokenConfig.getConfig(address(this)).ltvPercent, - _maxPercent - ); - return _osTokenVaultController.convertToShares(maxOsTokenAssets); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + + /** + * @dev Internal function for calculating the maximum amount of osToken shares that can be minted + * @param assets The amount of assets to convert to osToken shares + * @return maxOsTokenShares The maximum amount of osToken shares that can be minted + */ + function _calcMaxOsTokenShares(uint256 assets) internal view returns (uint256) { + uint256 maxOsTokenAssets = Math.mulDiv(assets, _osTokenConfig.getConfig(address(this)).ltvPercent, _maxPercent); + return _osTokenVaultController.convertToShares(maxOsTokenAssets); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultState.sol b/contracts/vaults/modules/VaultState.sol index 6c11be9a..4ea64edc 100644 --- a/contracts/vaults/modules/VaultState.sol +++ b/contracts/vaults/modules/VaultState.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Math} from '@openzeppelin/contracts/utils/math/Math.sol'; -import {IVaultState} from '../../interfaces/IVaultState.sol'; -import {IKeeperRewards} from '../../interfaces/IKeeperRewards.sol'; -import {ExitQueue} from '../../libraries/ExitQueue.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultImmutables} from './VaultImmutables.sol'; -import {VaultFee} from './VaultFee.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {IVaultState} from "../../interfaces/IVaultState.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {ExitQueue} from "../../libraries/ExitQueue.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; +import {VaultFee} from "./VaultFee.sol"; /** * @title VaultState @@ -18,346 +18,330 @@ import {VaultFee} from './VaultFee.sol'; * @notice Defines Vault's state manipulation */ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVaultState { - using ExitQueue for ExitQueue.History; - - uint128 internal _totalShares; - uint128 internal _totalAssets; - - uint128 internal _queuedShares; - uint128 internal _unclaimedAssets; - ExitQueue.History internal _exitQueue; - - mapping(bytes32 => uint256) internal _exitRequests; - mapping(address => uint256) internal _balances; - - uint256 private _capacity; - - uint128 internal _totalExitingAssets; // deprecated - uint128 internal _totalExitingTickets; // deprecated - uint256 internal _totalExitedTickets; // deprecated - - /// @inheritdoc IVaultState - function totalShares() external view override returns (uint256) { - return _totalShares; - } - - /// @inheritdoc IVaultState - function totalAssets() external view override returns (uint256) { - return _totalAssets; - } - - /// @inheritdoc IVaultState - function getExitQueueData() - external - view - override - returns ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) - { - return ( - _queuedShares, - _unclaimedAssets, - _totalExitingTickets, - _totalExitingAssets, - _exitQueue.getLatestTotalTickets() - ); - } - - /// @inheritdoc IVaultState - function getShares(address account) external view override returns (uint256) { - return _balances[account]; - } - - /// @inheritdoc IVaultState - function convertToShares(uint256 assets) public view override returns (uint256 shares) { - return _convertToShares(assets, Math.Rounding.Floor); - } - - /// @inheritdoc IVaultState - function convertToAssets(uint256 shares) public view override returns (uint256 assets) { - uint256 totalShares_ = _totalShares; - return (totalShares_ == 0) ? shares : Math.mulDiv(shares, _totalAssets, totalShares_); - } - - /// @inheritdoc IVaultState - function capacity() public view override returns (uint256) { - // SLOAD to memory - uint256 capacity_ = _capacity; - - // if capacity is not set, it is unlimited - return capacity_ == 0 ? type(uint256).max : capacity_; - } - - /// @inheritdoc IVaultState - function withdrawableAssets() public view override returns (uint256) { - uint256 vaultAssets = _vaultAssets(); - unchecked { - // calculate assets that are reserved by users who queued for exit - // cannot overflow as it is capped with underlying asset total supply - uint256 reservedAssets = convertToAssets(_queuedShares) + - _totalExitingAssets + - _unclaimedAssets; - return vaultAssets > reservedAssets ? vaultAssets - reservedAssets : 0; + using ExitQueue for ExitQueue.History; + + uint128 internal _totalShares; + uint128 internal _totalAssets; + + uint128 internal _queuedShares; + uint128 internal _unclaimedAssets; + ExitQueue.History internal _exitQueue; + + mapping(bytes32 => uint256) internal _exitRequests; + mapping(address => uint256) internal _balances; + + uint256 private _capacity; + + uint128 internal _totalExitingAssets; // deprecated + uint128 internal _totalExitingTickets; // deprecated + uint256 internal _totalExitedTickets; // deprecated + + /// @inheritdoc IVaultState + function totalShares() external view override returns (uint256) { + return _totalShares; + } + + /// @inheritdoc IVaultState + function totalAssets() external view override returns (uint256) { + return _totalAssets; } - } - - /// @inheritdoc IVaultState - function isStateUpdateRequired() external view override returns (bool) { - return IKeeperRewards(_keeper).isHarvestRequired(address(this)); - } - - /// @inheritdoc IVaultState - function updateState( - IKeeperRewards.HarvestParams calldata harvestParams - ) public virtual override { - // process total assets delta since last update - (int256 totalAssetsDelta, bool harvested) = _harvestAssets(harvestParams); - - // process total assets delta if it has changed - _processTotalAssetsDelta(totalAssetsDelta); - - // update exit queue every time new update is harvested - if (harvested) _updateExitQueue(); - } - - /** - * @dev Internal function for processing rewards and penalties - * @param totalAssetsDelta The number of assets earned or lost - */ - function _processTotalAssetsDelta(int256 totalAssetsDelta) internal virtual { - // skip processing if there is no change in assets - if (totalAssetsDelta == 0) return; - - // SLOAD to memory - uint256 newTotalAssets = _totalAssets; - if (totalAssetsDelta < 0) { - uint256 penalty = uint256(-totalAssetsDelta); - - // SLOAD to memory - uint256 totalExitingAssets = _totalExitingAssets; - if (totalExitingAssets > 0) { - // apply penalty to exiting assets - uint256 exitingAssetsPenalty = Math.mulDiv( - penalty, - totalExitingAssets, - totalExitingAssets + newTotalAssets + + /// @inheritdoc IVaultState + function getExitQueueData() + external + view + override + returns ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) + { + return ( + _queuedShares, + _unclaimedAssets, + _totalExitingTickets, + _totalExitingAssets, + _exitQueue.getLatestTotalTickets() ); + } + + /// @inheritdoc IVaultState + function getShares(address account) external view override returns (uint256) { + return _balances[account]; + } + + /// @inheritdoc IVaultState + function convertToShares(uint256 assets) public view override returns (uint256 shares) { + return _convertToShares(assets, Math.Rounding.Floor); + } - // apply penalty to total exiting assets + /// @inheritdoc IVaultState + function convertToAssets(uint256 shares) public view override returns (uint256 assets) { + uint256 totalShares_ = _totalShares; + return (totalShares_ == 0) ? shares : Math.mulDiv(shares, _totalAssets, totalShares_); + } + + /// @inheritdoc IVaultState + function capacity() public view override returns (uint256) { + // SLOAD to memory + uint256 capacity_ = _capacity; + + // if capacity is not set, it is unlimited + return capacity_ == 0 ? type(uint256).max : capacity_; + } + + /// @inheritdoc IVaultState + function withdrawableAssets() public view override returns (uint256) { + uint256 vaultAssets = _vaultAssets(); unchecked { - // cannot underflow as exitingAssetsPenalty <= penalty - penalty -= exitingAssetsPenalty; - // cannot underflow as exitingAssetsPenalty <= totalExitingAssets - _totalExitingAssets = SafeCast.toUint128(totalExitingAssets - exitingAssetsPenalty); + // calculate assets that are reserved by users who queued for exit + // cannot overflow as it is capped with underlying asset total supply + uint256 reservedAssets = convertToAssets(_queuedShares) + _totalExitingAssets + _unclaimedAssets; + return vaultAssets > reservedAssets ? vaultAssets - reservedAssets : 0; } - emit ExitingAssetsPenalized(exitingAssetsPenalty); - } - - // subtract penalty from total assets (excludes exiting assets) - if (penalty > 0) { - _totalAssets = SafeCast.toUint128(newTotalAssets - penalty); - } - return; } - // convert assets delta as it is positive - uint256 profitAssets = uint256(totalAssetsDelta); - newTotalAssets += profitAssets; - - // update state - _totalAssets = SafeCast.toUint128(newTotalAssets); - - // calculate admin fee recipient assets - uint256 feeRecipientAssets = Math.mulDiv(profitAssets, feePercent, _maxFeePercent); - if (feeRecipientAssets == 0) return; - - // SLOAD to memory - uint256 totalShares_ = _totalShares; - - // calculate fee recipient's shares - uint256 feeRecipientShares; - if (totalShares_ == 0) { - feeRecipientShares = feeRecipientAssets; - } else { - unchecked { - feeRecipientShares = Math.mulDiv( - feeRecipientAssets, - totalShares_, - newTotalAssets - feeRecipientAssets - ); - } + /// @inheritdoc IVaultState + function isStateUpdateRequired() external view override returns (bool) { + return IKeeperRewards(_keeper).isHarvestRequired(address(this)); } - // SLOAD to memory - address _feeRecipient = feeRecipient; - // mint shares to the fee recipient - _mintShares(_feeRecipient, feeRecipientShares); - emit FeeSharesMinted(_feeRecipient, feeRecipientShares, feeRecipientAssets); - } - - /** - * @dev Internal function that must be used to process exit queue - * @dev Make sure that sufficient time passed between exit queue updates (at least 1 day). - * Currently it's restricted by the keeper's harvest interval - * @return burnedShares The total amount of burned shares - */ - function _updateExitQueue() internal virtual returns (uint256 burnedShares) { - // calculate assets that can be used to process the exit requests - uint256 availableAssets = _vaultAssets() - _unclaimedAssets; - if (availableAssets == 0) return 0; - - // SLOAD to memory - uint256 totalExitingAssets = _totalExitingAssets; - if (totalExitingAssets > 0) { - // wait for all the exiting assets from v2 to be processed - if (availableAssets < totalExitingAssets) return 0; - - // SLOAD to memory - uint256 totalExitingTickets = _totalExitingTickets; - - // push checkpoint so that exited assets could be claimed - _exitQueue.push(totalExitingTickets, totalExitingAssets); - emit CheckpointCreated(totalExitingTickets, totalExitingAssets); - - unchecked { - // cannot underflow as _totalExitingAssets <= availableAssets - availableAssets -= totalExitingAssets; - } - - // update state - _unclaimedAssets += SafeCast.toUint128(totalExitingAssets); - _totalExitingTickets = 0; - _totalExitingAssets = 0; + /// @inheritdoc IVaultState + function updateState(IKeeperRewards.HarvestParams calldata harvestParams) public virtual override { + // process total assets delta since last update + (int256 totalAssetsDelta, bool harvested) = _harvestAssets(harvestParams); + + // process total assets delta if it has changed + _processTotalAssetsDelta(totalAssetsDelta); + + // update exit queue every time new update is harvested + if (harvested) _updateExitQueue(); } - // SLOAD to memory - uint256 queuedShares = _queuedShares; - if (queuedShares == 0 || availableAssets == 0) return 0; - - // calculate the amount of assets that can be exited - uint256 exitedAssets = Math.min(availableAssets, convertToAssets(queuedShares)); - if (exitedAssets == 0) return 0; - - // calculate the amount of shares that can be burned - burnedShares = convertToShares(exitedAssets); - if (burnedShares == 0) return 0; - - // update queued shares and unclaimed assets - _queuedShares = SafeCast.toUint128(queuedShares - burnedShares); - _unclaimedAssets += SafeCast.toUint128(exitedAssets); - - // push checkpoint so that exited assets could be claimed - _exitQueue.push(burnedShares, exitedAssets); - emit CheckpointCreated(burnedShares, exitedAssets); - - // update state - _totalShares -= SafeCast.toUint128(burnedShares); - _totalAssets -= SafeCast.toUint128(exitedAssets); - } - - /** - * @dev Internal function for minting shares - * @param owner The address of the owner to mint shares to - * @param shares The number of shares to mint - */ - function _mintShares(address owner, uint256 shares) internal virtual { - // update total shares - _totalShares += SafeCast.toUint128(shares); - - // mint shares - unchecked { - // cannot overflow because the sum of all user - // balances can't exceed the max uint256 value - _balances[owner] += shares; + /** + * @dev Internal function for processing rewards and penalties + * @param totalAssetsDelta The number of assets earned or lost + */ + function _processTotalAssetsDelta(int256 totalAssetsDelta) internal virtual { + // skip processing if there is no change in assets + if (totalAssetsDelta == 0) return; + + // SLOAD to memory + uint256 newTotalAssets = _totalAssets; + if (totalAssetsDelta < 0) { + uint256 penalty = uint256(-totalAssetsDelta); + + // SLOAD to memory + uint256 totalExitingAssets = _totalExitingAssets; + if (totalExitingAssets > 0) { + // apply penalty to exiting assets + uint256 exitingAssetsPenalty = + Math.mulDiv(penalty, totalExitingAssets, totalExitingAssets + newTotalAssets); + + // apply penalty to total exiting assets + unchecked { + // cannot underflow as exitingAssetsPenalty <= penalty + penalty -= exitingAssetsPenalty; + // cannot underflow as exitingAssetsPenalty <= totalExitingAssets + _totalExitingAssets = SafeCast.toUint128(totalExitingAssets - exitingAssetsPenalty); + } + emit ExitingAssetsPenalized(exitingAssetsPenalty); + } + + // subtract penalty from total assets (excludes exiting assets) + if (penalty > 0) { + _totalAssets = SafeCast.toUint128(newTotalAssets - penalty); + } + return; + } + + // convert assets delta as it is positive + uint256 profitAssets = uint256(totalAssetsDelta); + newTotalAssets += profitAssets; + + // update state + _totalAssets = SafeCast.toUint128(newTotalAssets); + + // calculate admin fee recipient assets + uint256 feeRecipientAssets = Math.mulDiv(profitAssets, feePercent, _maxFeePercent); + if (feeRecipientAssets == 0) return; + + // SLOAD to memory + uint256 totalShares_ = _totalShares; + + // calculate fee recipient's shares + uint256 feeRecipientShares; + if (totalShares_ == 0) { + feeRecipientShares = feeRecipientAssets; + } else { + unchecked { + feeRecipientShares = Math.mulDiv(feeRecipientAssets, totalShares_, newTotalAssets - feeRecipientAssets); + } + } + + // SLOAD to memory + address _feeRecipient = feeRecipient; + // mint shares to the fee recipient + _mintShares(_feeRecipient, feeRecipientShares); + emit FeeSharesMinted(_feeRecipient, feeRecipientShares, feeRecipientAssets); } - } - - /** - * @dev Internal function for burning shares - * @param owner The address of the owner to burn shares for - * @param shares The number of shares to burn - */ - function _burnShares(address owner, uint256 shares) internal virtual { - // burn shares - _balances[owner] -= shares; - - // update total shares - unchecked { - // cannot underflow because the sum of all shares can't exceed the _totalShares - _totalShares -= SafeCast.toUint128(shares); + + /** + * @dev Internal function that must be used to process exit queue + * @dev Make sure that sufficient time passed between exit queue updates (at least 1 day). + * Currently it's restricted by the keeper's harvest interval + * @return burnedShares The total amount of burned shares + */ + function _updateExitQueue() internal virtual returns (uint256 burnedShares) { + // calculate assets that can be used to process the exit requests + uint256 availableAssets = _vaultAssets() - _unclaimedAssets; + if (availableAssets == 0) return 0; + + // SLOAD to memory + uint256 totalExitingAssets = _totalExitingAssets; + if (totalExitingAssets > 0) { + // wait for all the exiting assets from v2 to be processed + if (availableAssets < totalExitingAssets) return 0; + + // SLOAD to memory + uint256 totalExitingTickets = _totalExitingTickets; + + // push checkpoint so that exited assets could be claimed + _exitQueue.push(totalExitingTickets, totalExitingAssets); + emit CheckpointCreated(totalExitingTickets, totalExitingAssets); + + unchecked { + // cannot underflow as _totalExitingAssets <= availableAssets + availableAssets -= totalExitingAssets; + } + + // update state + _unclaimedAssets += SafeCast.toUint128(totalExitingAssets); + _totalExitingTickets = 0; + _totalExitingAssets = 0; + } + + // SLOAD to memory + uint256 queuedShares = _queuedShares; + if (queuedShares == 0 || availableAssets == 0) return 0; + + // calculate the amount of assets that can be exited + uint256 exitedAssets = Math.min(availableAssets, convertToAssets(queuedShares)); + if (exitedAssets == 0) return 0; + + // calculate the amount of shares that can be burned + burnedShares = convertToShares(exitedAssets); + if (burnedShares == 0) return 0; + + // update queued shares and unclaimed assets + _queuedShares = SafeCast.toUint128(queuedShares - burnedShares); + _unclaimedAssets += SafeCast.toUint128(exitedAssets); + + // push checkpoint so that exited assets could be claimed + _exitQueue.push(burnedShares, exitedAssets); + emit CheckpointCreated(burnedShares, exitedAssets); + + // update state + _totalShares -= SafeCast.toUint128(burnedShares); + _totalAssets -= SafeCast.toUint128(exitedAssets); } - } - - /** - * @dev Internal conversion function (from assets to shares) with support for rounding direction. - */ - function _convertToShares( - uint256 assets, - Math.Rounding rounding - ) internal view returns (uint256 shares) { - uint256 totalShares_ = _totalShares; - // Will revert if assets > 0, totalShares > 0 and _totalAssets = 0. - // That corresponds to a case where any asset would represent an infinite amount of shares. - return - (assets == 0 || totalShares_ == 0) - ? assets - : Math.mulDiv(assets, totalShares_, _totalAssets, rounding); - } - - /** - * @dev Internal function for harvesting Vaults' new assets - * @return The total assets delta after harvest - * @return `true` when the rewards were harvested, `false` otherwise - */ - function _harvestAssets( - IKeeperRewards.HarvestParams calldata harvestParams - ) internal virtual returns (int256, bool); - - /** - * @dev Internal function for retrieving the total assets stored in the Vault. - * NB! Assets can be forcibly sent to the vault, the returned value must be used with caution - * @return The total amount of assets stored in the Vault - */ - function _vaultAssets() internal view virtual returns (uint256); - - /** - * @dev Initializes the VaultState contract - * @param capacity_ The amount after which the Vault stops accepting deposits - */ - function __VaultState_init(uint256 capacity_) internal onlyInitializing { - if (capacity_ == 0) revert Errors.InvalidCapacity(); - // skip setting capacity if it is unlimited - if (capacity_ != type(uint256).max) _capacity = capacity_; - } - - /** - * @dev Upgrades the VaultState contract - */ - function __VaultState_upgrade() internal onlyInitializing { - // SLOAD to memory - uint256 totalExitedTickets = _totalExitedTickets; - uint256 exitQueueTicket = _exitQueue.getLatestTotalTickets(); - if (exitQueueTicket < totalExitedTickets) { - uint256 exitedTickets; - unchecked { - // cannot underflow as latestTicket >= exitQueueTicket - exitedTickets = totalExitedTickets - exitQueueTicket; - } - _exitQueue.push(exitedTickets, 0); - emit CheckpointCreated(exitedTickets, 0); + + /** + * @dev Internal function for minting shares + * @param owner The address of the owner to mint shares to + * @param shares The number of shares to mint + */ + function _mintShares(address owner, uint256 shares) internal virtual { + // update total shares + _totalShares += SafeCast.toUint128(shares); + + // mint shares + unchecked { + // cannot overflow because the sum of all user + // balances can't exceed the max uint256 value + _balances[owner] += shares; + } } - _totalExitedTickets = 0; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[48] private __gap; + + /** + * @dev Internal function for burning shares + * @param owner The address of the owner to burn shares for + * @param shares The number of shares to burn + */ + function _burnShares(address owner, uint256 shares) internal virtual { + // burn shares + _balances[owner] -= shares; + + // update total shares + unchecked { + // cannot underflow because the sum of all shares can't exceed the _totalShares + _totalShares -= SafeCast.toUint128(shares); + } + } + + /** + * @dev Internal conversion function (from assets to shares) with support for rounding direction. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) internal view returns (uint256 shares) { + uint256 totalShares_ = _totalShares; + // Will revert if assets > 0, totalShares > 0 and _totalAssets = 0. + // That corresponds to a case where any asset would represent an infinite amount of shares. + return (assets == 0 || totalShares_ == 0) ? assets : Math.mulDiv(assets, totalShares_, _totalAssets, rounding); + } + + /** + * @dev Internal function for harvesting Vaults' new assets + * @return The total assets delta after harvest + * @return `true` when the rewards were harvested, `false` otherwise + */ + function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) + internal + virtual + returns (int256, bool); + + /** + * @dev Internal function for retrieving the total assets stored in the Vault. + * NB! Assets can be forcibly sent to the vault, the returned value must be used with caution + * @return The total amount of assets stored in the Vault + */ + function _vaultAssets() internal view virtual returns (uint256); + + /** + * @dev Initializes the VaultState contract + * @param capacity_ The amount after which the Vault stops accepting deposits + */ + function __VaultState_init(uint256 capacity_) internal onlyInitializing { + if (capacity_ == 0) revert Errors.InvalidCapacity(); + // skip setting capacity if it is unlimited + if (capacity_ != type(uint256).max) _capacity = capacity_; + } + + /** + * @dev Upgrades the VaultState contract + */ + function __VaultState_upgrade() internal onlyInitializing { + // SLOAD to memory + uint256 totalExitedTickets = _totalExitedTickets; + uint256 exitQueueTicket = _exitQueue.getLatestTotalTickets(); + if (exitQueueTicket < totalExitedTickets) { + uint256 exitedTickets; + unchecked { + // cannot underflow as latestTicket >= exitQueueTicket + exitedTickets = totalExitedTickets - exitQueueTicket; + } + _exitQueue.push(exitedTickets, 0); + emit CheckpointCreated(exitedTickets, 0); + } + _totalExitedTickets = 0; + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[48] private __gap; } diff --git a/contracts/vaults/modules/VaultToken.sol b/contracts/vaults/modules/VaultToken.sol index e607a103..6f41e3b1 100644 --- a/contracts/vaults/modules/VaultToken.sol +++ b/contracts/vaults/modules/VaultToken.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IVaultToken} from '../../interfaces/IVaultToken.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {ERC20Upgradeable} from '../../base/ERC20Upgradeable.sol'; -import {VaultState} from './VaultState.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IVaultToken} from "../../interfaces/IVaultToken.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; +import {VaultState} from "./VaultState.sol"; /** * @title VaultToken @@ -15,63 +15,63 @@ import {VaultState} from './VaultState.sol'; * @notice Defines the token functionality for the Vault */ abstract contract VaultToken is Initializable, ERC20Upgradeable, VaultState, IVaultToken { - /// @inheritdoc IERC20 - function totalSupply() external view override returns (uint256) { - return _totalShares; - } + /// @inheritdoc IERC20 + function totalSupply() external view override returns (uint256) { + return _totalShares; + } - /// @inheritdoc IERC20 - function balanceOf(address account) external view returns (uint256) { - return _balances[account]; - } + /// @inheritdoc IERC20 + function balanceOf(address account) external view returns (uint256) { + return _balances[account]; + } - /// @inheritdoc VaultState - function _mintShares(address owner, uint256 shares) internal virtual override { - super._mintShares(owner, shares); - emit Transfer(address(0), owner, shares); - } + /// @inheritdoc VaultState + function _mintShares(address owner, uint256 shares) internal virtual override { + super._mintShares(owner, shares); + emit Transfer(address(0), owner, shares); + } - /// @inheritdoc VaultState - function _burnShares(address owner, uint256 shares) internal virtual override { - super._burnShares(owner, shares); - emit Transfer(owner, address(0), shares); - } + /// @inheritdoc VaultState + function _burnShares(address owner, uint256 shares) internal virtual override { + super._burnShares(owner, shares); + emit Transfer(owner, address(0), shares); + } - /// @inheritdoc VaultState - function _updateExitQueue() internal virtual override returns (uint256 burnedShares) { - burnedShares = super._updateExitQueue(); - if (burnedShares != 0) emit Transfer(address(this), address(0), burnedShares); - } + /// @inheritdoc VaultState + function _updateExitQueue() internal virtual override returns (uint256 burnedShares) { + burnedShares = super._updateExitQueue(); + if (burnedShares != 0) emit Transfer(address(this), address(0), burnedShares); + } - /// @inheritdoc ERC20Upgradeable - function _transfer(address from, address to, uint256 amount) internal virtual override { - if (from == address(0) || to == address(0)) revert Errors.ZeroAddress(); - _balances[from] -= amount; + /// @inheritdoc ERC20Upgradeable + function _transfer(address from, address to, uint256 amount) internal virtual override { + if (from == address(0) || to == address(0)) revert Errors.ZeroAddress(); + _balances[from] -= amount; - // Cannot overflow because the sum of all user - // balances can't exceed the max uint256 value - unchecked { - _balances[to] += amount; + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value + unchecked { + _balances[to] += amount; + } + emit Transfer(from, to, amount); } - emit Transfer(from, to, amount); - } - /** - * @dev Initializes the VaultToken contract - * @param _name The name of the ERC20 token - * @param _symbol The symbol of the ERC20 token - */ - function __VaultToken_init(string memory _name, string memory _symbol) internal onlyInitializing { - if (bytes(_name).length > 30 || bytes(_symbol).length > 10) revert Errors.InvalidTokenMeta(); + /** + * @dev Initializes the VaultToken contract + * @param _name The name of the ERC20 token + * @param _symbol The symbol of the ERC20 token + */ + function __VaultToken_init(string memory _name, string memory _symbol) internal onlyInitializing { + if (bytes(_name).length > 30 || bytes(_symbol).length > 10) revert Errors.InvalidTokenMeta(); - // initialize ERC20Permit - __ERC20Upgradeable_init(_name, _symbol); - } + // initialize ERC20Permit + __ERC20Upgradeable_init(_name, _symbol); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultValidators.sol b/contracts/vaults/modules/VaultValidators.sol index 07cfad67..0336f9fe 100644 --- a/contracts/vaults/modules/VaultValidators.sol +++ b/contracts/vaults/modules/VaultValidators.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; -import {IKeeperValidators} from '../../interfaces/IKeeperValidators.sol'; -import {IVaultValidators} from '../../interfaces/IVaultValidators.sol'; -import {IConsolidationsChecker} from '../../interfaces/IConsolidationsChecker.sol'; -import {IDepositDataRegistry} from '../../interfaces/IDepositDataRegistry.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {ValidatorUtils} from '../../libraries/ValidatorUtils.sol'; -import {EIP712Utils} from '../../libraries/EIP712Utils.sol'; -import {VaultImmutables} from './VaultImmutables.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; -import {VaultState} from './VaultState.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import {IKeeperValidators} from "../../interfaces/IKeeperValidators.sol"; +import {IVaultValidators} from "../../interfaces/IVaultValidators.sol"; +import {IConsolidationsChecker} from "../../interfaces/IConsolidationsChecker.sol"; +import {IDepositDataRegistry} from "../../interfaces/IDepositDataRegistry.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {ValidatorUtils} from "../../libraries/ValidatorUtils.sol"; +import {EIP712Utils} from "../../libraries/EIP712Utils.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; +import {VaultState} from "./VaultState.sol"; /** * @title VaultValidators @@ -21,293 +21,270 @@ import {VaultState} from './VaultState.sol'; * @notice Defines the validators functionality for the Vault */ abstract contract VaultValidators is - VaultImmutables, - Initializable, - ReentrancyGuardUpgradeable, - VaultAdmin, - VaultState, - IVaultValidators + VaultImmutables, + Initializable, + ReentrancyGuardUpgradeable, + VaultAdmin, + VaultState, + IVaultValidators { - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _depositDataRegistry; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - uint256 private immutable _initialChainId; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address internal immutable _validatorsRegistry; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _validatorsWithdrawals; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _validatorsConsolidations; - - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _consolidationsChecker; - - /// deprecated. Deposit data management is moved to DepositDataRegistry contract - bytes32 private __deprecated__validatorsRoot; - - /// deprecated. Deposit data management is moved to DepositDataRegistry contract - uint256 private __deprecated__validatorIndex; - - address private _validatorsManager; - - bytes32 private _initialDomainSeparator; - - /// @inheritdoc IVaultValidators - mapping(bytes32 publicKeyHash => bool isRegistered) public override v2Validators; - - /// @inheritdoc IVaultValidators - uint256 public override validatorsManagerNonce; - - /** - * @dev Constructor - * @dev Since the immutable variable value is stored in the bytecode, - * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param depositDataRegistry The address of the deposit data registry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for verifying consolidation approvals - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address depositDataRegistry, - address validatorsRegistry, - address validatorsWithdrawals, - address validatorsConsolidations, - address consolidationsChecker - ) { - _initialChainId = block.chainid; - _depositDataRegistry = depositDataRegistry; - _validatorsRegistry = validatorsRegistry; - _validatorsWithdrawals = validatorsWithdrawals; - _validatorsConsolidations = validatorsConsolidations; - _consolidationsChecker = consolidationsChecker; - } - - /// @inheritdoc IVaultValidators - function validatorsManager() public view override returns (address) { - // SLOAD to memory - address validatorsManager_ = _validatorsManager; - // if validatorsManager is not set, use DepositDataRegistry contract address - return validatorsManager_ == address(0) ? _depositDataRegistry : validatorsManager_; - } - - /// @inheritdoc IVaultValidators - function registerValidators( - IKeeperValidators.ApprovalParams calldata keeperParams, - bytes calldata validatorsManagerSignature - ) external override { - // check whether oracles have approve validators registration - IKeeperValidators(_keeper).approveValidators(keeperParams); - - // check vault is up to date - _checkHarvested(); - - // check access - if ( - !_isValidatorsManager( - keeperParams.validators, - keeperParams.validatorsRegistryRoot, - validatorsManagerSignature - ) + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _depositDataRegistry; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + uint256 private immutable _initialChainId; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address internal immutable _validatorsRegistry; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _validatorsWithdrawals; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _validatorsConsolidations; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _consolidationsChecker; + + /// deprecated. Deposit data management is moved to DepositDataRegistry contract + bytes32 private __deprecated__validatorsRoot; + + /// deprecated. Deposit data management is moved to DepositDataRegistry contract + uint256 private __deprecated__validatorIndex; + + address private _validatorsManager; + + bytes32 private _initialDomainSeparator; + + /// @inheritdoc IVaultValidators + mapping(bytes32 publicKeyHash => bool isRegistered) public override v2Validators; + + /// @inheritdoc IVaultValidators + uint256 public override validatorsManagerNonce; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param depositDataRegistry The address of the deposit data registry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for verifying consolidation approvals + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor( + address depositDataRegistry, + address validatorsRegistry, + address validatorsWithdrawals, + address validatorsConsolidations, + address consolidationsChecker ) { - revert Errors.AccessDenied(); + _initialChainId = block.chainid; + _depositDataRegistry = depositDataRegistry; + _validatorsRegistry = validatorsRegistry; + _validatorsWithdrawals = validatorsWithdrawals; + _validatorsConsolidations = validatorsConsolidations; + _consolidationsChecker = consolidationsChecker; } - // get validator deposits - ValidatorUtils.ValidatorDeposit[] memory validatorDeposits = ValidatorUtils - .getValidatorDeposits(v2Validators, keeperParams.validators, false); - - // register validators - _registerValidators(validatorDeposits); - } - - /// @inheritdoc IVaultValidators - function fundValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) external override { - // check vault is up to date - _checkHarvested(); - - // check access - if ( - !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) - ) { - revert Errors.AccessDenied(); + /// @inheritdoc IVaultValidators + function validatorsManager() public view override returns (address) { + // SLOAD to memory + address validatorsManager_ = _validatorsManager; + // if validatorsManager is not set, use DepositDataRegistry contract address + return validatorsManager_ == address(0) ? _depositDataRegistry : validatorsManager_; } - // get validator deposits - ValidatorUtils.ValidatorDeposit[] memory validatorDeposits = ValidatorUtils - .getValidatorDeposits(v2Validators, validators, true); - - // top up validators - _registerValidators(validatorDeposits); - } - - /// @inheritdoc IVaultValidators - function withdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) external payable override nonReentrant { - _checkCollateralized(); - _checkCanWithdrawValidators(validators, validatorsManagerSignature); - ValidatorUtils.withdrawValidators(validators, _validatorsWithdrawals); - } - - /// @inheritdoc IVaultValidators - function consolidateValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature, - bytes calldata oracleSignatures - ) external payable override nonReentrant { - _checkCollateralized(); - if ( - !_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature) - ) { - revert Errors.AccessDenied(); + /// @inheritdoc IVaultValidators + function registerValidators( + IKeeperValidators.ApprovalParams calldata keeperParams, + bytes calldata validatorsManagerSignature + ) external override { + // check whether oracles have approve validators registration + IKeeperValidators(_keeper).approveValidators(keeperParams); + + // check vault is up to date + _checkHarvested(); + + // check access + if ( + !_isValidatorsManager( + keeperParams.validators, keeperParams.validatorsRegistryRoot, validatorsManagerSignature + ) + ) { + revert Errors.AccessDenied(); + } + + // get validator deposits + ValidatorUtils.ValidatorDeposit[] memory validatorDeposits = + ValidatorUtils.getValidatorDeposits(v2Validators, keeperParams.validators, false); + + // register validators + _registerValidators(validatorDeposits); } - // Check for oracle approval if signatures provided - bool consolidationsApproved = false; - if (oracleSignatures.length > 0) { - // Check whether oracles have approved validators consolidation - IConsolidationsChecker(_consolidationsChecker).verifySignatures( - address(this), - validators, - oracleSignatures - ); - consolidationsApproved = true; + /// @inheritdoc IVaultValidators + function fundValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) external override { + // check vault is up to date + _checkHarvested(); + + // check access + if (!_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature)) { + revert Errors.AccessDenied(); + } + + // get validator deposits + ValidatorUtils.ValidatorDeposit[] memory validatorDeposits = + ValidatorUtils.getValidatorDeposits(v2Validators, validators, true); + + // top up validators + _registerValidators(validatorDeposits); } - ValidatorUtils.consolidateValidators( - v2Validators, - validators, - consolidationsApproved, - _validatorsConsolidations - ); - } - - /// @inheritdoc IVaultValidators - function setValidatorsManager(address validatorsManager_) external override { - _checkAdmin(); - // update validatorsManager address - _validatorsManager = validatorsManager_; - emit ValidatorsManagerUpdated(msg.sender, validatorsManager_); - } - - /** - * @dev Internal function for registering validators - * @param deposits The validators registration data - */ - function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual; - - /** - * @dev Internal function for checking whether the caller can withdraw validators - * @param validators The concatenated validators data - * @param validatorsManagerSignature The optional signature from the validators manager - */ - function _checkCanWithdrawValidators( - bytes calldata validators, - bytes calldata validatorsManagerSignature - ) internal virtual; - - /** - * @dev Internal function for checking whether the caller is the validators manager. - * If the valid signature is provided, update the nonce. - * @param validators The concatenated validators data - * @param nonce The nonce of the signature - * @param validatorsManagerSignature The optional signature from the validators manager - * @return true if the caller is the validators manager - */ - function _isValidatorsManager( - bytes calldata validators, - bytes32 nonce, - bytes calldata validatorsManagerSignature - ) internal returns (bool) { - // SLOAD to memory - address validatorsManager_ = validatorsManager(); - if (validatorsManager_ == address(0) || validators.length == 0) { - return false; + /// @inheritdoc IVaultValidators + function withdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + external + payable + override + nonReentrant + { + _checkCollateralized(); + _checkCanWithdrawValidators(validators, validatorsManagerSignature); + ValidatorUtils.withdrawValidators(validators, _validatorsWithdrawals); } - if (validatorsManagerSignature.length == 0) { - // if no signature is provided, check if the caller is the validators manager - return msg.sender == validatorsManager_; + /// @inheritdoc IVaultValidators + function consolidateValidators( + bytes calldata validators, + bytes calldata validatorsManagerSignature, + bytes calldata oracleSignatures + ) external payable override nonReentrant { + _checkCollateralized(); + if (!_isValidatorsManager(validators, bytes32(validatorsManagerNonce), validatorsManagerSignature)) { + revert Errors.AccessDenied(); + } + + // Check for oracle approval if signatures provided + bool consolidationsApproved = false; + if (oracleSignatures.length > 0) { + // Check whether oracles have approved validators consolidation + IConsolidationsChecker(_consolidationsChecker).verifySignatures(address(this), validators, oracleSignatures); + consolidationsApproved = true; + } + + ValidatorUtils.consolidateValidators( + v2Validators, validators, consolidationsApproved, _validatorsConsolidations + ); } - // check signature - bytes32 domainSeparator = block.chainid == _initialChainId - ? _initialDomainSeparator - : _computeVaultValidatorsDomain(); - bool isValidSignature = ValidatorUtils.isValidManagerSignature( - nonce, - domainSeparator, - validatorsManager_, - validators, - validatorsManagerSignature - ); - - // update signature nonce - if (isValidSignature) { - unchecked { - // cannot realistically overflow - validatorsManagerNonce += 1; - } + /// @inheritdoc IVaultValidators + function setValidatorsManager(address validatorsManager_) external override { + _checkAdmin(); + // update validatorsManager address + _validatorsManager = validatorsManager_; + emit ValidatorsManagerUpdated(msg.sender, validatorsManager_); } - return isValidSignature; - } - - /** - * @notice Computes the hash of the EIP712 typed data - * @dev This function is used to compute the hash of the EIP712 typed data - * @return The hash of the EIP712 typed data - */ - function _computeVaultValidatorsDomain() private view returns (bytes32) { - return EIP712Utils.computeDomainSeparator('VaultValidators', address(this)); - } - - /** - * @dev Upgrades the VaultValidators contract - */ - function __VaultValidators_upgrade() internal onlyInitializing { - __ReentrancyGuard_init(); - // initialize domain separator - bytes32 newInitialDomainSeparator = _computeVaultValidatorsDomain(); - if (newInitialDomainSeparator != _initialDomainSeparator) { - _initialDomainSeparator = newInitialDomainSeparator; + /** + * @dev Internal function for registering validators + * @param deposits The validators registration data + */ + function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual; + + /** + * @dev Internal function for checking whether the caller can withdraw validators + * @param validators The concatenated validators data + * @param validatorsManagerSignature The optional signature from the validators manager + */ + function _checkCanWithdrawValidators(bytes calldata validators, bytes calldata validatorsManagerSignature) + internal + virtual; + + /** + * @dev Internal function for checking whether the caller is the validators manager. + * If the valid signature is provided, update the nonce. + * @param validators The concatenated validators data + * @param nonce The nonce of the signature + * @param validatorsManagerSignature The optional signature from the validators manager + * @return true if the caller is the validators manager + */ + function _isValidatorsManager(bytes calldata validators, bytes32 nonce, bytes calldata validatorsManagerSignature) + internal + returns (bool) + { + // SLOAD to memory + address validatorsManager_ = validatorsManager(); + if (validatorsManager_ == address(0) || validators.length == 0) { + return false; + } + + if (validatorsManagerSignature.length == 0) { + // if no signature is provided, check if the caller is the validators manager + return msg.sender == validatorsManager_; + } + + // check signature + bytes32 domainSeparator = + block.chainid == _initialChainId ? _initialDomainSeparator : _computeVaultValidatorsDomain(); + bool isValidSignature = ValidatorUtils.isValidManagerSignature( + nonce, domainSeparator, validatorsManager_, validators, validatorsManagerSignature + ); + + // update signature nonce + if (isValidSignature) { + unchecked { + // cannot realistically overflow + validatorsManagerNonce += 1; + } + } + + return isValidSignature; } - // migrate deposit data variables to DepositDataRegistry contract - if (__deprecated__validatorsRoot != bytes32(0)) { - IDepositDataRegistry(_depositDataRegistry).migrate( - __deprecated__validatorsRoot, - __deprecated__validatorIndex, - _validatorsManager - ); - delete __deprecated__validatorIndex; - delete __deprecated__validatorsRoot; - delete _validatorsManager; + /** + * @notice Computes the hash of the EIP712 typed data + * @dev This function is used to compute the hash of the EIP712 typed data + * @return The hash of the EIP712 typed data + */ + function _computeVaultValidatorsDomain() private view returns (bytes32) { + return EIP712Utils.computeDomainSeparator("VaultValidators", address(this)); } - } - - /** - * @dev Initializes the VaultValidators contract - */ - function __VaultValidators_init() internal onlyInitializing { - __ReentrancyGuard_init(); - _initialDomainSeparator = _computeVaultValidatorsDomain(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[47] private __gap; + + /** + * @dev Upgrades the VaultValidators contract + */ + function __VaultValidators_upgrade() internal onlyInitializing { + __ReentrancyGuard_init(); + // initialize domain separator + bytes32 newInitialDomainSeparator = _computeVaultValidatorsDomain(); + if (newInitialDomainSeparator != _initialDomainSeparator) { + _initialDomainSeparator = newInitialDomainSeparator; + } + + // migrate deposit data variables to DepositDataRegistry contract + if (__deprecated__validatorsRoot != bytes32(0)) { + IDepositDataRegistry(_depositDataRegistry).migrate( + __deprecated__validatorsRoot, __deprecated__validatorIndex, _validatorsManager + ); + delete __deprecated__validatorIndex; + delete __deprecated__validatorsRoot; + delete _validatorsManager; + } + } + + /** + * @dev Initializes the VaultValidators contract + */ + function __VaultValidators_init() internal onlyInitializing { + __ReentrancyGuard_init(); + _initialDomainSeparator = _computeVaultValidatorsDomain(); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[47] private __gap; } diff --git a/contracts/vaults/modules/VaultVersion.sol b/contracts/vaults/modules/VaultVersion.sol index ae2bd329..7fcac106 100644 --- a/contracts/vaults/modules/VaultVersion.sol +++ b/contracts/vaults/modules/VaultVersion.sol @@ -2,66 +2,56 @@ pragma solidity ^0.8.22; -import {UUPSUpgradeable} from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {ERC1967Utils} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol'; -import {IVaultsRegistry} from '../../interfaces/IVaultsRegistry.sol'; -import {IVaultVersion} from '../../interfaces/IVaultVersion.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; -import {VaultImmutables} from './VaultImmutables.sol'; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import {IVaultsRegistry} from "../../interfaces/IVaultsRegistry.sol"; +import {IVaultVersion} from "../../interfaces/IVaultVersion.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; /** * @title VaultVersion * @author StakeWise * @notice Defines the versioning functionality for the Vault */ -abstract contract VaultVersion is - VaultImmutables, - Initializable, - UUPSUpgradeable, - VaultAdmin, - IVaultVersion -{ - bytes4 private constant _initSelector = bytes4(keccak256('initialize(bytes)')); +abstract contract VaultVersion is VaultImmutables, Initializable, UUPSUpgradeable, VaultAdmin, IVaultVersion { + bytes4 private constant _initSelector = bytes4(keccak256("initialize(bytes)")); - /// @inheritdoc IVaultVersion - function implementation() external view override returns (address) { - return ERC1967Utils.getImplementation(); - } + /// @inheritdoc IVaultVersion + function implementation() external view override returns (address) { + return ERC1967Utils.getImplementation(); + } - /// @inheritdoc UUPSUpgradeable - function upgradeToAndCall( - address newImplementation, - bytes memory data - ) public payable override onlyProxy { - super.upgradeToAndCall(newImplementation, abi.encodeWithSelector(_initSelector, data)); - } + /// @inheritdoc UUPSUpgradeable + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override onlyProxy { + super.upgradeToAndCall(newImplementation, abi.encodeWithSelector(_initSelector, data)); + } - /// @inheritdoc UUPSUpgradeable - function _authorizeUpgrade(address newImplementation) internal view override { - _checkAdmin(); - if ( - newImplementation == address(0) || - ERC1967Utils.getImplementation() == newImplementation || // cannot reinit the same implementation - IVaultVersion(newImplementation).vaultId() != vaultId() || // vault must be of the same type - IVaultVersion(newImplementation).version() != version() + 1 || // vault cannot skip versions between - !IVaultsRegistry(_vaultsRegistry).vaultImpls(newImplementation) // new implementation must be registered - ) { - revert Errors.UpgradeFailed(); + /// @inheritdoc UUPSUpgradeable + function _authorizeUpgrade(address newImplementation) internal view override { + _checkAdmin(); + if ( + newImplementation == address(0) || ERC1967Utils.getImplementation() == newImplementation // cannot reinit the same implementation + || IVaultVersion(newImplementation).vaultId() != vaultId() // vault must be of the same type + || IVaultVersion(newImplementation).version() != version() + 1 // vault cannot skip versions between + || !IVaultsRegistry(_vaultsRegistry).vaultImpls(newImplementation) // new implementation must be registered + ) { + revert Errors.UpgradeFailed(); + } } - } - /// @inheritdoc IVaultVersion - function vaultId() public pure virtual override returns (bytes32); + /// @inheritdoc IVaultVersion + function vaultId() public pure virtual override returns (bytes32); - /// @inheritdoc IVaultVersion - function version() public pure virtual override returns (uint8); + /// @inheritdoc IVaultVersion + function version() public pure virtual override returns (uint8); - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/contracts/vaults/modules/VaultWhitelist.sol b/contracts/vaults/modules/VaultWhitelist.sol index 2382dac8..eacfc2c5 100644 --- a/contracts/vaults/modules/VaultWhitelist.sol +++ b/contracts/vaults/modules/VaultWhitelist.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IVaultWhitelist} from '../../interfaces/IVaultWhitelist.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {VaultAdmin} from './VaultAdmin.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IVaultWhitelist} from "../../interfaces/IVaultWhitelist.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; /** * @title VaultWhitelist @@ -13,56 +13,56 @@ import {VaultAdmin} from './VaultAdmin.sol'; * @notice Defines the whitelisting functionality for the Vault */ abstract contract VaultWhitelist is Initializable, VaultAdmin, IVaultWhitelist { - /// @inheritdoc IVaultWhitelist - address public override whitelister; + /// @inheritdoc IVaultWhitelist + address public override whitelister; - /// @inheritdoc IVaultWhitelist - mapping(address => bool) public override whitelistedAccounts; + /// @inheritdoc IVaultWhitelist + mapping(address => bool) public override whitelistedAccounts; - /// @inheritdoc IVaultWhitelist - function updateWhitelist(address account, bool approved) external override { - if (msg.sender != whitelister) revert Errors.AccessDenied(); - if (whitelistedAccounts[account] == approved) return; - whitelistedAccounts[account] = approved; - emit WhitelistUpdated(msg.sender, account, approved); - } + /// @inheritdoc IVaultWhitelist + function updateWhitelist(address account, bool approved) external override { + if (msg.sender != whitelister) revert Errors.AccessDenied(); + if (whitelistedAccounts[account] == approved) return; + whitelistedAccounts[account] = approved; + emit WhitelistUpdated(msg.sender, account, approved); + } - /// @inheritdoc IVaultWhitelist - function setWhitelister(address _whitelister) external override { - _checkAdmin(); - _setWhitelister(_whitelister); - } + /// @inheritdoc IVaultWhitelist + function setWhitelister(address _whitelister) external override { + _checkAdmin(); + _setWhitelister(_whitelister); + } - /** - * @notice Internal function for checking whether account is in the whitelist - * @param account The address of the account to check - */ - function _checkWhitelist(address account) internal view { - if (!whitelistedAccounts[account]) revert Errors.AccessDenied(); - } + /** + * @notice Internal function for checking whether account is in the whitelist + * @param account The address of the account to check + */ + function _checkWhitelist(address account) internal view { + if (!whitelistedAccounts[account]) revert Errors.AccessDenied(); + } - /** - * @dev Internal function for updating the whitelister externally or from the initializer - * @param _whitelister The address of the new whitelister - */ - function _setWhitelister(address _whitelister) private { - // update whitelister address - whitelister = _whitelister; - emit WhitelisterUpdated(msg.sender, _whitelister); - } + /** + * @dev Internal function for updating the whitelister externally or from the initializer + * @param _whitelister The address of the new whitelister + */ + function _setWhitelister(address _whitelister) private { + // update whitelister address + whitelister = _whitelister; + emit WhitelisterUpdated(msg.sender, _whitelister); + } - /** - * @dev Initializes the VaultWhitelist contract - * @param _whitelister The address of the whitelister - */ - function __VaultWhitelist_init(address _whitelister) internal onlyInitializing { - _setWhitelister(_whitelister); - } + /** + * @dev Initializes the VaultWhitelist contract + * @param _whitelister The address of the whitelister + */ + function __VaultWhitelist_init(address _whitelister) internal onlyInitializing { + _setWhitelister(_whitelister); + } - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; } diff --git a/script/Network.sol b/script/Network.sol index 1a1f5636..9286b21c 100644 --- a/script/Network.sol +++ b/script/Network.sol @@ -7,166 +7,148 @@ pragma solidity ^0.8.22; * @notice Solidity library containing constants for the StakeWise protocol */ library Network { - uint256 internal constant MAINNET = 1; - uint256 internal constant HOODI = 560048; - uint256 internal constant CHIADO = 10200; - uint256 internal constant GNOSIS = 100; + uint256 internal constant MAINNET = 1; + uint256 internal constant HOODI = 560048; + uint256 internal constant CHIADO = 10200; + uint256 internal constant GNOSIS = 100; - uint64 internal constant PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY = 1 days; - // disable delay for private vaults as stakers are KYC'd - uint64 internal constant PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY = 0; - address internal constant VALIDATORS_WITHDRAWALS = 0x00000961Ef480Eb55e80D19ad83579A64c007002; - address internal constant VALIDATORS_CONSOLIDATIONS = 0x0000BBdDc7CE488642fb579F8B00f3a590007251; + uint64 internal constant PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY = 1 days; + // disable delay for private vaults as stakers are KYC'd + uint64 internal constant PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY = 0; + address internal constant VALIDATORS_WITHDRAWALS = 0x00000961Ef480Eb55e80D19ad83579A64c007002; + address internal constant VALIDATORS_CONSOLIDATIONS = 0x0000BBdDc7CE488642fb579F8B00f3a590007251; - // MAINNET - address internal constant MAINNET_KEEPER = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; - address internal constant MAINNET_VAULTS_REGISTRY = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; - address internal constant MAINNET_VALIDATORS_REGISTRY = - 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address internal constant MAINNET_OS_TOKEN_VAULT_CONTROLLER = - 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; - address internal constant MAINNET_OS_TOKEN_CONFIG = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; - address internal constant MAINNET_OS_TOKEN_VAULT_ESCROW = - 0x09e84205DF7c68907e619D07aFD90143c5763605; - address internal constant MAINNET_SHARED_MEV_ESCROW = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; - address internal constant MAINNET_DEPOSIT_DATA_REGISTRY = - 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; - address internal constant MAINNET_LEGACY_POOL_ESCROW = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; - address internal constant MAINNET_LEGACY_REWARD_TOKEN = - 0x20BC832ca081b91433ff6c17f85701B6e92486c5; + // MAINNET + address internal constant MAINNET_KEEPER = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; + address internal constant MAINNET_VAULTS_REGISTRY = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; + address internal constant MAINNET_VALIDATORS_REGISTRY = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + address internal constant MAINNET_OS_TOKEN_VAULT_CONTROLLER = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; + address internal constant MAINNET_OS_TOKEN_CONFIG = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; + address internal constant MAINNET_OS_TOKEN_VAULT_ESCROW = 0x09e84205DF7c68907e619D07aFD90143c5763605; + address internal constant MAINNET_SHARED_MEV_ESCROW = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; + address internal constant MAINNET_DEPOSIT_DATA_REGISTRY = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; + address internal constant MAINNET_LEGACY_POOL_ESCROW = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; + address internal constant MAINNET_LEGACY_REWARD_TOKEN = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; - // HOODI - address internal constant HOODI_KEEPER = 0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f; - address internal constant HOODI_VAULTS_REGISTRY = 0xf16fea93D3253A401C3f73B0De890C6586740B25; - address internal constant HOODI_VALIDATORS_REGISTRY = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address internal constant HOODI_OS_TOKEN_VAULT_CONTROLLER = - 0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1; - address internal constant HOODI_OS_TOKEN_CONFIG = 0x5b817621EBE00622b9a71b53c942b392751c8197; - address internal constant HOODI_OS_TOKEN_VAULT_ESCROW = - 0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B; - address internal constant HOODI_SHARED_MEV_ESCROW = 0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd; - address internal constant HOODI_DEPOSIT_DATA_REGISTRY = - 0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487; - address internal constant HOODI_LEGACY_POOL_ESCROW = 0x291Fa5849215847081B475450cBE5De46CfD4fAE; - address internal constant HOODI_LEGACY_REWARD_TOKEN = 0x75c57bd50A3EB7291Da3429956D3566E0153A38f; + // HOODI + address internal constant HOODI_KEEPER = 0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f; + address internal constant HOODI_VAULTS_REGISTRY = 0xf16fea93D3253A401C3f73B0De890C6586740B25; + address internal constant HOODI_VALIDATORS_REGISTRY = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + address internal constant HOODI_OS_TOKEN_VAULT_CONTROLLER = 0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1; + address internal constant HOODI_OS_TOKEN_CONFIG = 0x5b817621EBE00622b9a71b53c942b392751c8197; + address internal constant HOODI_OS_TOKEN_VAULT_ESCROW = 0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B; + address internal constant HOODI_SHARED_MEV_ESCROW = 0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd; + address internal constant HOODI_DEPOSIT_DATA_REGISTRY = 0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487; + address internal constant HOODI_LEGACY_POOL_ESCROW = 0x291Fa5849215847081B475450cBE5De46CfD4fAE; + address internal constant HOODI_LEGACY_REWARD_TOKEN = 0x75c57bd50A3EB7291Da3429956D3566E0153A38f; - // GNOSIS - address internal constant GNOSIS_KEEPER = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; - address internal constant GNOSIS_VAULTS_REGISTRY = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; - address internal constant GNOSIS_VALIDATORS_REGISTRY = 0x0B98057eA310F4d31F2a452B414647007d1645d9; - address internal constant GNOSIS_OS_TOKEN_VAULT_CONTROLLER = - 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; - address internal constant GNOSIS_OS_TOKEN_CONFIG = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; - address internal constant GNOSIS_OS_TOKEN_VAULT_ESCROW = - 0x28F325dD287a5984B754d34CfCA38af3A8429e71; - address internal constant GNOSIS_SHARED_MEV_ESCROW = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; - address internal constant GNOSIS_DEPOSIT_DATA_REGISTRY = - 0x58e16621B5c0786D6667D2d54E28A20940269E16; - address internal constant GNOSIS_LEGACY_POOL_ESCROW = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; - address internal constant GNOSIS_LEGACY_REWARD_TOKEN = 0x6aC78efae880282396a335CA2F79863A1e6831D4; + // GNOSIS + address internal constant GNOSIS_KEEPER = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; + address internal constant GNOSIS_VAULTS_REGISTRY = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; + address internal constant GNOSIS_VALIDATORS_REGISTRY = 0x0B98057eA310F4d31F2a452B414647007d1645d9; + address internal constant GNOSIS_OS_TOKEN_VAULT_CONTROLLER = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; + address internal constant GNOSIS_OS_TOKEN_CONFIG = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; + address internal constant GNOSIS_OS_TOKEN_VAULT_ESCROW = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; + address internal constant GNOSIS_SHARED_MEV_ESCROW = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; + address internal constant GNOSIS_DEPOSIT_DATA_REGISTRY = 0x58e16621B5c0786D6667D2d54E28A20940269E16; + address internal constant GNOSIS_LEGACY_POOL_ESCROW = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; + address internal constant GNOSIS_LEGACY_REWARD_TOKEN = 0x6aC78efae880282396a335CA2F79863A1e6831D4; - // CHIADO - address internal constant CHIADO_KEEPER = 0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988; - address internal constant CHIADO_VAULTS_REGISTRY = 0x8750594B33516232e751C8B9C350a660cD5f1BB8; - address internal constant CHIADO_VALIDATORS_REGISTRY = 0xb97036A26259B7147018913bD58a774cf91acf25; - address internal constant CHIADO_OS_TOKEN_VAULT_CONTROLLER = - 0x5518052f2d898f062ee59964004A560F24E2eE7d; - address internal constant CHIADO_OS_TOKEN_CONFIG = 0x6D5957e075fd93b3B9F36Da93d7462F14387706d; - address internal constant CHIADO_OS_TOKEN_VAULT_ESCROW = - 0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7; - address internal constant CHIADO_SHARED_MEV_ESCROW = 0x453056f0bc4631abB15eEC656139f88067668E3E; - address internal constant CHIADO_DEPOSIT_DATA_REGISTRY = - 0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D; - address internal constant CHIADO_LEGACY_POOL_ESCROW = 0x928F9a91E674C886Cae0c377670109aBeF7e19d6; - address internal constant CHIADO_LEGACY_REWARD_TOKEN = 0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4; + // CHIADO + address internal constant CHIADO_KEEPER = 0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988; + address internal constant CHIADO_VAULTS_REGISTRY = 0x8750594B33516232e751C8B9C350a660cD5f1BB8; + address internal constant CHIADO_VALIDATORS_REGISTRY = 0xb97036A26259B7147018913bD58a774cf91acf25; + address internal constant CHIADO_OS_TOKEN_VAULT_CONTROLLER = 0x5518052f2d898f062ee59964004A560F24E2eE7d; + address internal constant CHIADO_OS_TOKEN_CONFIG = 0x6D5957e075fd93b3B9F36Da93d7462F14387706d; + address internal constant CHIADO_OS_TOKEN_VAULT_ESCROW = 0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7; + address internal constant CHIADO_SHARED_MEV_ESCROW = 0x453056f0bc4631abB15eEC656139f88067668E3E; + address internal constant CHIADO_DEPOSIT_DATA_REGISTRY = 0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D; + address internal constant CHIADO_LEGACY_POOL_ESCROW = 0x928F9a91E674C886Cae0c377670109aBeF7e19d6; + address internal constant CHIADO_LEGACY_REWARD_TOKEN = 0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4; - struct Constants { - address keeper; - address vaultsRegistry; - address validatorsRegistry; - address validatorsWithdrawals; - address validatorsConsolidations; - address osTokenVaultController; - address osTokenConfig; - address osTokenVaultEscrow; - address sharedMevEscrow; - address depositDataRegistry; - address legacyPoolEscrow; - address legacyRewardToken; - uint64 exitedAssetsClaimDelay; - } + struct Constants { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address sharedMevEscrow; + address depositDataRegistry; + address legacyPoolEscrow; + address legacyRewardToken; + uint64 exitedAssetsClaimDelay; + } - function getNetworkConstants(uint256 chainId) internal pure returns (Constants memory) { - if (chainId == MAINNET) { - return - Constants({ - keeper: MAINNET_KEEPER, - vaultsRegistry: MAINNET_VAULTS_REGISTRY, - validatorsRegistry: MAINNET_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: MAINNET_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: MAINNET_OS_TOKEN_CONFIG, - osTokenVaultEscrow: MAINNET_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: MAINNET_SHARED_MEV_ESCROW, - depositDataRegistry: MAINNET_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: MAINNET_LEGACY_POOL_ESCROW, - legacyRewardToken: MAINNET_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); - } else if (chainId == HOODI) { - return - Constants({ - keeper: HOODI_KEEPER, - vaultsRegistry: HOODI_VAULTS_REGISTRY, - validatorsRegistry: HOODI_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: HOODI_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: HOODI_OS_TOKEN_CONFIG, - osTokenVaultEscrow: HOODI_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: HOODI_SHARED_MEV_ESCROW, - depositDataRegistry: HOODI_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: HOODI_LEGACY_POOL_ESCROW, - legacyRewardToken: HOODI_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); - } else if (chainId == GNOSIS) { - return - Constants({ - keeper: GNOSIS_KEEPER, - vaultsRegistry: GNOSIS_VAULTS_REGISTRY, - validatorsRegistry: GNOSIS_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: GNOSIS_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: GNOSIS_OS_TOKEN_CONFIG, - osTokenVaultEscrow: GNOSIS_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: GNOSIS_SHARED_MEV_ESCROW, - depositDataRegistry: GNOSIS_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: GNOSIS_LEGACY_POOL_ESCROW, - legacyRewardToken: GNOSIS_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); - } else if (chainId == CHIADO) { - return - Constants({ - keeper: CHIADO_KEEPER, - vaultsRegistry: CHIADO_VAULTS_REGISTRY, - validatorsRegistry: CHIADO_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: CHIADO_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: CHIADO_OS_TOKEN_CONFIG, - osTokenVaultEscrow: CHIADO_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: CHIADO_SHARED_MEV_ESCROW, - depositDataRegistry: CHIADO_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: CHIADO_LEGACY_POOL_ESCROW, - legacyRewardToken: CHIADO_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); - } else { - revert('Unsupported chain ID'); + function getNetworkConstants(uint256 chainId) internal pure returns (Constants memory) { + if (chainId == MAINNET) { + return Constants({ + keeper: MAINNET_KEEPER, + vaultsRegistry: MAINNET_VAULTS_REGISTRY, + validatorsRegistry: MAINNET_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: MAINNET_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: MAINNET_OS_TOKEN_CONFIG, + osTokenVaultEscrow: MAINNET_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: MAINNET_SHARED_MEV_ESCROW, + depositDataRegistry: MAINNET_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: MAINNET_LEGACY_POOL_ESCROW, + legacyRewardToken: MAINNET_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else if (chainId == HOODI) { + return Constants({ + keeper: HOODI_KEEPER, + vaultsRegistry: HOODI_VAULTS_REGISTRY, + validatorsRegistry: HOODI_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: HOODI_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: HOODI_OS_TOKEN_CONFIG, + osTokenVaultEscrow: HOODI_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: HOODI_SHARED_MEV_ESCROW, + depositDataRegistry: HOODI_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: HOODI_LEGACY_POOL_ESCROW, + legacyRewardToken: HOODI_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else if (chainId == GNOSIS) { + return Constants({ + keeper: GNOSIS_KEEPER, + vaultsRegistry: GNOSIS_VAULTS_REGISTRY, + validatorsRegistry: GNOSIS_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: GNOSIS_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: GNOSIS_OS_TOKEN_CONFIG, + osTokenVaultEscrow: GNOSIS_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: GNOSIS_SHARED_MEV_ESCROW, + depositDataRegistry: GNOSIS_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: GNOSIS_LEGACY_POOL_ESCROW, + legacyRewardToken: GNOSIS_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else if (chainId == CHIADO) { + return Constants({ + keeper: CHIADO_KEEPER, + vaultsRegistry: CHIADO_VAULTS_REGISTRY, + validatorsRegistry: CHIADO_VALIDATORS_REGISTRY, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + osTokenVaultController: CHIADO_OS_TOKEN_VAULT_CONTROLLER, + osTokenConfig: CHIADO_OS_TOKEN_CONFIG, + osTokenVaultEscrow: CHIADO_OS_TOKEN_VAULT_ESCROW, + sharedMevEscrow: CHIADO_SHARED_MEV_ESCROW, + depositDataRegistry: CHIADO_DEPOSIT_DATA_REGISTRY, + legacyPoolEscrow: CHIADO_LEGACY_POOL_ESCROW, + legacyRewardToken: CHIADO_LEGACY_REWARD_TOKEN, + exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } else { + revert("Unsupported chain ID"); + } } - } } diff --git a/script/UpgradeEthNetwork.s.sol b/script/UpgradeEthNetwork.s.sol index 6a4ca4d6..cf4f6d7a 100644 --- a/script/UpgradeEthNetwork.s.sol +++ b/script/UpgradeEthNetwork.s.sol @@ -1,176 +1,157 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; -import {Script} from 'forge-std/Script.sol'; -import {console} from 'forge-std/console.sol'; -import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; -import {IVaultsRegistry} from '../contracts/interfaces/IVaultsRegistry.sol'; -import {IVaultVersion} from '../contracts/interfaces/IVaultVersion.sol'; -import {ConsolidationsChecker} from '../contracts/validators/ConsolidationsChecker.sol'; -import {EthBlocklistErc20Vault} from '../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; -import {EthBlocklistVault} from '../contracts/vaults/ethereum/EthBlocklistVault.sol'; -import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; -import {EthGenesisVault} from '../contracts/vaults/ethereum/EthGenesisVault.sol'; -import {EthPrivErc20Vault} from '../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; -import {EthPrivVault} from '../contracts/vaults/ethereum/EthPrivVault.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {EthVaultFactory} from '../contracts/vaults/ethereum/EthVaultFactory.sol'; -import {Network} from './Network.sol'; +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; +import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; +import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; +import {ConsolidationsChecker} from "../contracts/validators/ConsolidationsChecker.sol"; +import {EthBlocklistErc20Vault} from "../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol"; +import {EthBlocklistVault} from "../contracts/vaults/ethereum/EthBlocklistVault.sol"; +import {EthErc20Vault} from "../contracts/vaults/ethereum/EthErc20Vault.sol"; +import {EthGenesisVault} from "../contracts/vaults/ethereum/EthGenesisVault.sol"; +import {EthPrivErc20Vault} from "../contracts/vaults/ethereum/EthPrivErc20Vault.sol"; +import {EthPrivVault} from "../contracts/vaults/ethereum/EthPrivVault.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthVaultFactory} from "../contracts/vaults/ethereum/EthVaultFactory.sol"; +import {Network} from "./Network.sol"; contract UpgradeEthNetwork is Script { - Network.Constants public constants; - address public consolidationsChecker; - address[] public vaultImpls; - address[] public vaultFactories; - - function run() external { - vm.startBroadcast(vm.envUint('PRIVATE_KEY')); - console.log('Deploying from: ', msg.sender); - - constants = Network.getNetworkConstants(block.chainid); - - // Deploy consolidations checker - consolidationsChecker = address(new ConsolidationsChecker(constants.keeper)); - - _deployImplementations(); - _deployFactories(); - - vm.stopBroadcast(); - } - - function _deployImplementations() internal { - // constructors for implementations - IEthVault.EthVaultConstructorArgs memory vaultArgs = _getEthVaultConstructorArgs(); - IEthErc20Vault.EthErc20VaultConstructorArgs - memory erc20VaultArgs = _getEthErc20VaultConstructorArgs(); - - // deploy genesis vault - vaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; - erc20VaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; - - EthGenesisVault ethGenesisVault = new EthGenesisVault( - vaultArgs, - constants.legacyPoolEscrow, - constants.legacyRewardToken - ); - - // deploy normal vaults - EthVault ethVault = new EthVault(vaultArgs); - EthErc20Vault ethErc20Vault = new EthErc20Vault(erc20VaultArgs); - - // deploy blocklist vaults - EthBlocklistVault ethBlocklistVault = new EthBlocklistVault(vaultArgs); - EthBlocklistErc20Vault ethBlocklistErc20Vault = new EthBlocklistErc20Vault(erc20VaultArgs); - - // deploy private vaults - // update exited assets claim delay for private vaults - vaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; - erc20VaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; - EthPrivVault ethPrivVault = new EthPrivVault(vaultArgs); - EthPrivErc20Vault ethPrivErc20Vault = new EthPrivErc20Vault(erc20VaultArgs); - - vaultImpls.push(address(ethGenesisVault)); - vaultImpls.push(address(ethVault)); - vaultImpls.push(address(ethErc20Vault)); - vaultImpls.push(address(ethBlocklistVault)); - vaultImpls.push(address(ethBlocklistErc20Vault)); - vaultImpls.push(address(ethPrivVault)); - vaultImpls.push(address(ethPrivErc20Vault)); - } - - function _deployFactories() internal { - for (uint256 i = 0; i < vaultImpls.length; i++) { - address vaultImpl = vaultImpls[i]; - if (IVaultVersion(vaultImpl).vaultId() == keccak256('EthGenesisVault')) { - continue; - } - EthVaultFactory factory = new EthVaultFactory( - vaultImpl, - IVaultsRegistry(constants.vaultsRegistry) - ); - vaultFactories.push(address(factory)); + Network.Constants public constants; + address public consolidationsChecker; + address[] public vaultImpls; + address[] public vaultFactories; + + function run() external { + vm.startBroadcast(vm.envUint("PRIVATE_KEY")); + console.log("Deploying from: ", msg.sender); + + constants = Network.getNetworkConstants(block.chainid); + + // Deploy consolidations checker + consolidationsChecker = address(new ConsolidationsChecker(constants.keeper)); + + _deployImplementations(); + _deployFactories(); + + vm.stopBroadcast(); + } + + function _deployImplementations() internal { + // constructors for implementations + IEthVault.EthVaultConstructorArgs memory vaultArgs = _getEthVaultConstructorArgs(); + IEthErc20Vault.EthErc20VaultConstructorArgs memory erc20VaultArgs = _getEthErc20VaultConstructorArgs(); + + // deploy genesis vault + vaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + + EthGenesisVault ethGenesisVault = + new EthGenesisVault(vaultArgs, constants.legacyPoolEscrow, constants.legacyRewardToken); + + // deploy normal vaults + EthVault ethVault = new EthVault(vaultArgs); + EthErc20Vault ethErc20Vault = new EthErc20Vault(erc20VaultArgs); + + // deploy blocklist vaults + EthBlocklistVault ethBlocklistVault = new EthBlocklistVault(vaultArgs); + EthBlocklistErc20Vault ethBlocklistErc20Vault = new EthBlocklistErc20Vault(erc20VaultArgs); + + // deploy private vaults + // update exited assets claim delay for private vaults + vaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + EthPrivVault ethPrivVault = new EthPrivVault(vaultArgs); + EthPrivErc20Vault ethPrivErc20Vault = new EthPrivErc20Vault(erc20VaultArgs); + + vaultImpls.push(address(ethGenesisVault)); + vaultImpls.push(address(ethVault)); + vaultImpls.push(address(ethErc20Vault)); + vaultImpls.push(address(ethBlocklistVault)); + vaultImpls.push(address(ethBlocklistErc20Vault)); + vaultImpls.push(address(ethPrivVault)); + vaultImpls.push(address(ethPrivErc20Vault)); + } + + function _deployFactories() internal { + for (uint256 i = 0; i < vaultImpls.length; i++) { + address vaultImpl = vaultImpls[i]; + if (IVaultVersion(vaultImpl).vaultId() == keccak256("EthGenesisVault")) { + continue; + } + EthVaultFactory factory = new EthVaultFactory(vaultImpl, IVaultsRegistry(constants.vaultsRegistry)); + vaultFactories.push(address(factory)); + } } - } - - function _getEthVaultConstructorArgs() - internal - view - returns (IEthVault.EthVaultConstructorArgs memory) - { - return - IEthVault.EthVaultConstructorArgs({ - keeper: constants.keeper, - vaultsRegistry: constants.vaultsRegistry, - validatorsRegistry: constants.validatorsRegistry, - validatorsWithdrawals: constants.validatorsWithdrawals, - validatorsConsolidations: constants.validatorsConsolidations, - consolidationsChecker: consolidationsChecker, - osTokenVaultController: constants.osTokenVaultController, - osTokenConfig: constants.osTokenConfig, - osTokenVaultEscrow: constants.osTokenVaultEscrow, - sharedMevEscrow: constants.sharedMevEscrow, - depositDataRegistry: constants.depositDataRegistry, - exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay - }); - } - - function _getEthErc20VaultConstructorArgs() - internal - view - returns (IEthErc20Vault.EthErc20VaultConstructorArgs memory) - { - return - IEthErc20Vault.EthErc20VaultConstructorArgs({ - keeper: constants.keeper, - vaultsRegistry: constants.vaultsRegistry, - validatorsRegistry: constants.validatorsRegistry, - validatorsWithdrawals: constants.validatorsWithdrawals, - validatorsConsolidations: constants.validatorsConsolidations, - consolidationsChecker: consolidationsChecker, - osTokenVaultController: constants.osTokenVaultController, - osTokenConfig: constants.osTokenConfig, - osTokenVaultEscrow: constants.osTokenVaultEscrow, - sharedMevEscrow: constants.sharedMevEscrow, - depositDataRegistry: constants.depositDataRegistry, - exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay - }); - } - - function _generateGovernorTxJson() internal { - string[] memory objects = new string[](vaultImpls.length + vaultFactories.length); - for (uint256 i = 0; i < vaultImpls.length; i++) { - string memory object = Strings.toString(i); - vm.serializeAddress(object, 'to', constants.vaultsRegistry); - vm.serializeString(object, 'operation', '0'); - vm.serializeBytes( - object, - 'data', - abi.encodeWithSelector( - IVaultsRegistry(constants.vaultsRegistry).addVaultImpl.selector, - vaultImpls[i] - ) - ); - objects[i] = vm.serializeString(object, 'value', '0.0'); + + function _getEthVaultConstructorArgs() internal view returns (IEthVault.EthVaultConstructorArgs memory) { + return IEthVault.EthVaultConstructorArgs({ + keeper: constants.keeper, + vaultsRegistry: constants.vaultsRegistry, + validatorsRegistry: constants.validatorsRegistry, + validatorsWithdrawals: constants.validatorsWithdrawals, + validatorsConsolidations: constants.validatorsConsolidations, + consolidationsChecker: consolidationsChecker, + osTokenVaultController: constants.osTokenVaultController, + osTokenConfig: constants.osTokenConfig, + osTokenVaultEscrow: constants.osTokenVaultEscrow, + sharedMevEscrow: constants.sharedMevEscrow, + depositDataRegistry: constants.depositDataRegistry, + exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay + }); + } + + function _getEthErc20VaultConstructorArgs() + internal + view + returns (IEthErc20Vault.EthErc20VaultConstructorArgs memory) + { + return IEthErc20Vault.EthErc20VaultConstructorArgs({ + keeper: constants.keeper, + vaultsRegistry: constants.vaultsRegistry, + validatorsRegistry: constants.validatorsRegistry, + validatorsWithdrawals: constants.validatorsWithdrawals, + validatorsConsolidations: constants.validatorsConsolidations, + consolidationsChecker: consolidationsChecker, + osTokenVaultController: constants.osTokenVaultController, + osTokenConfig: constants.osTokenConfig, + osTokenVaultEscrow: constants.osTokenVaultEscrow, + sharedMevEscrow: constants.sharedMevEscrow, + depositDataRegistry: constants.depositDataRegistry, + exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay + }); } - for (uint256 i = 0; i < vaultFactories.length; i++) { - string memory object = Strings.toString(vaultImpls.length + i); - vm.serializeAddress(object, 'to', constants.vaultsRegistry); - vm.serializeString(object, 'operation', '0'); - vm.serializeBytes( - object, - 'data', - abi.encodeWithSelector( - IVaultsRegistry(constants.vaultsRegistry).addFactory.selector, - vaultFactories[i] - ) - ); - objects[vaultImpls.length + i] = vm.serializeString(object, 'value', '0.0'); + function _generateGovernorTxJson() internal { + string[] memory objects = new string[](vaultImpls.length + vaultFactories.length); + for (uint256 i = 0; i < vaultImpls.length; i++) { + string memory object = Strings.toString(i); + vm.serializeAddress(object, "to", constants.vaultsRegistry); + vm.serializeString(object, "operation", "0"); + vm.serializeBytes( + object, + "data", + abi.encodeWithSelector(IVaultsRegistry(constants.vaultsRegistry).addVaultImpl.selector, vaultImpls[i]) + ); + objects[i] = vm.serializeString(object, "value", "0.0"); + } + + for (uint256 i = 0; i < vaultFactories.length; i++) { + string memory object = Strings.toString(vaultImpls.length + i); + vm.serializeAddress(object, "to", constants.vaultsRegistry); + vm.serializeString(object, "operation", "0"); + vm.serializeBytes( + object, + "data", + abi.encodeWithSelector(IVaultsRegistry(constants.vaultsRegistry).addFactory.selector, vaultFactories[i]) + ); + objects[vaultImpls.length + i] = vm.serializeString(object, "value", "0.0"); + } + string memory json = "json"; + string memory output = vm.serializeString(json, "transactions", objects); + vm.writeJson(output, "./output/example.json"); } - string memory json = 'json'; - string memory output = vm.serializeString(json, 'transactions', objects); - vm.writeJson(output, './output/example.json'); - } } diff --git a/slither.config.json b/slither.config.json new file mode 100644 index 00000000..42c230a5 --- /dev/null +++ b/slither.config.json @@ -0,0 +1,6 @@ +{ + "filter_paths": "lib|mocks|test", + "exclude_informational": true, + "exclude_low": true, + "exclude_medium": true +} diff --git a/snapshots/ConsolidationsCheckerTest.json b/snapshots/ConsolidationsCheckerTest.json new file mode 100644 index 00000000..d0c75124 --- /dev/null +++ b/snapshots/ConsolidationsCheckerTest.json @@ -0,0 +1,12 @@ +{ + "ConsolidationsCheckerTest_test_verifySignatures_differentValidatorData": "14287", + "ConsolidationsCheckerTest_test_verifySignatures_differentVault": "14178", + "ConsolidationsCheckerTest_test_verifySignatures_emptySignatures": "14926", + "ConsolidationsCheckerTest_test_verifySignatures_exactMinimumSignatures": "29006", + "ConsolidationsCheckerTest_test_verifySignatures_moreThanMinimumSignatures": "29019", + "ConsolidationsCheckerTest_test_verifySignatures_nonOracleSigner": "26426", + "ConsolidationsCheckerTest_test_verifySignatures_repeatedSigner": "23008", + "ConsolidationsCheckerTest_test_verifySignatures_success": "29008", + "ConsolidationsCheckerTest_test_verifySignatures_tooFewSignatures": "10954", + "ConsolidationsCheckerTest_test_verifySignatures_unsortedSignatures": "23004" +} \ No newline at end of file diff --git a/snapshots/DepositDataRegistryTest.json b/snapshots/DepositDataRegistryTest.json new file mode 100644 index 00000000..372ec10f --- /dev/null +++ b/snapshots/DepositDataRegistryTest.json @@ -0,0 +1,9 @@ +{ + "DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator": "272901", + "DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator": "295827", + "DepositDataRegistryTest_test_registerValidators_successWith0x01Validators": "314466", + "DepositDataRegistryTest_test_registerValidators_successWith0x02Validators": "338559", + "DepositDataRegistryTest_test_setDepositDataManager_succeeds": "64228", + "DepositDataRegistryTest_test_setDepositDataRoot_succeeds": "65149", + "DepositDataRegistryTest_test_updateVaultState_succeeds": "124118" +} \ No newline at end of file diff --git a/snapshots/EthBlocklistErc20VaultTest.json b/snapshots/EthBlocklistErc20VaultTest.json new file mode 100644 index 00000000..ed706cf0 --- /dev/null +++ b/snapshots/EthBlocklistErc20VaultTest.json @@ -0,0 +1,8 @@ +{ + "EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "89859", + "EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "84237", + "EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161438", + "EthBlocklistErc20VaultTest_test_deploysCorrectly": "623706", + "EthBlocklistErc20VaultTest_test_transfer": "61633", + "EthBlocklistErc20VaultTest_test_upgradesCorrectly": "73633" +} \ No newline at end of file diff --git a/snapshots/EthBlocklistVaultTest.json b/snapshots/EthBlocklistVaultTest.json new file mode 100644 index 00000000..1d84cad3 --- /dev/null +++ b/snapshots/EthBlocklistVaultTest.json @@ -0,0 +1,7 @@ +{ + "EthBlocklistVaultTest_test_canDepositAsNonBlockedUser": "87906", + "EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "82295", + "EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161420", + "EthBlocklistVaultTest_test_deploysCorrectly": "548654", + "EthBlocklistVaultTest_test_upgradesCorrectly": "72962" +} \ No newline at end of file diff --git a/snapshots/EthErc20VaultTest.json b/snapshots/EthErc20VaultTest.json new file mode 100644 index 00000000..bf03275c --- /dev/null +++ b/snapshots/EthErc20VaultTest.json @@ -0,0 +1,16 @@ +{ + "EthErc20VaultTest_test_canTransferFromSharesWithHighLtv": "89925", + "EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96456", + "EthErc20VaultTest_test_deploysCorrectly": "453478", + "EthErc20VaultTest_test_depositAndMintOsToken": "199052", + "EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer": "75386", + "EthErc20VaultTest_test_deposit_emitsTransfer": "78848", + "EthErc20VaultTest_test_enterExitQueue_emitsTransfer": "89780", + "EthErc20VaultTest_test_redeem_emitsEvent": "58220", + "EthErc20VaultTest_test_updateExitQueue_emitsTransfer": "172131", + "EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken": "223176", + "EthErc20VaultTest_test_upgradesCorrectly": "73506", + "EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "74987", + "EthErc20VaultTest_test_withdrawValidator_unknown": "56828", + "EthErc20VaultTest_test_withdrawValidator_validatorsManager": "69759" +} \ No newline at end of file diff --git a/snapshots/EthFoxVaultTest.json b/snapshots/EthFoxVaultTest.json new file mode 100644 index 00000000..5e947770 --- /dev/null +++ b/snapshots/EthFoxVaultTest.json @@ -0,0 +1,8 @@ +{ + "EthFoxVaultTest_test_canDepositAsNonBlockedUser": "85500", + "EthFoxVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "79867", + "EthFoxVaultTest_test_ejectUser": "101192", + "EthFoxVaultTest_test_ejectUserWithNoShares": "58862", + "EthFoxVaultTest_test_withdrawValidator_unknown": "51498", + "EthFoxVaultTest_test_withdrawValidator_validatorsManager": "69605" +} \ No newline at end of file diff --git a/snapshots/EthGenesisVaultTest.json b/snapshots/EthGenesisVaultTest.json new file mode 100644 index 00000000..80f07348 --- /dev/null +++ b/snapshots/EthGenesisVaultTest.json @@ -0,0 +1,8 @@ +{ + "EthGenesisVaultTest_test_claimsPoolEscrowAssets": "77684", + "EthGenesisVaultTest_test_fallback_acceptsEtherFromPoolEscrow": "33277", + "EthGenesisVaultTest_test_fallback_acceptsEtherFromUser": "75475", + "EthGenesisVaultTest_test_migrate_works": "199287", + "EthGenesisVaultTest_test_upgradesCorrectly": "5106070", + "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "761161" +} \ No newline at end of file diff --git a/snapshots/EthOsTokenVaultEscrowTest.json b/snapshots/EthOsTokenVaultEscrowTest.json new file mode 100644 index 00000000..4e5ceb26 --- /dev/null +++ b/snapshots/EthOsTokenVaultEscrowTest.json @@ -0,0 +1,35 @@ +{ + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_insufficientShares": "66982", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_minimalAmount": "88563", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_noProcessedAssets": "91451", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_nonExistentPosition": "50879", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_notOwner": "65015", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_withFeeAccrual": "97458", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_claimExitedAssets": "73940", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_exitRequestNotProcessed": "45228", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_invalidPosition": "33255", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_partialClaim": "89137", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_success": "68617", + "EthOsTokenVaultEscrowTest_test_register_accessDenied": "29199", + "EthOsTokenVaultEscrowTest_test_register_directCall": "79100", + "EthOsTokenVaultEscrowTest_test_register_fullFlow": "163681", + "EthOsTokenVaultEscrowTest_test_register_invalidShares": "29242", + "EthOsTokenVaultEscrowTest_test_register_zeroAddress": "28886", + "EthOsTokenVaultEscrowTest_test_setAuthenticator_onlyOwner": "30174", + "EthOsTokenVaultEscrowTest_test_setAuthenticator_success": "31014", + "EthOsTokenVaultEscrowTest_test_setAuthenticator_valueNotChanged": "27509", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_high": "27548", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_low": "25626", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_max": "27337", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_zero": "25470", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_onlyOwner": "30318", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_success": "36745", + "OsTokenLiquidationTest_test_liquidateOsToken_invalidHealthFactor": "45969", + "OsTokenLiquidationTest_test_liquidateOsToken_invalidPosition": "41078", + "OsTokenLiquidationTest_test_liquidateOsToken_invalidReceivedAssets": "41999", + "OsTokenLiquidationTest_test_liquidateOsToken_partialLiquidation": "88124", + "OsTokenLiquidationTest_test_liquidateOsToken_success": "92795", + "OsTokenLiquidationTest_test_liquidateOsToken_zeroAddress": "24032", + "OsTokenLiquidationTest_test_redeemOsToken_notRedeemer": "27478", + "OsTokenLiquidationTest_test_redeemOsToken_success": "114222" +} \ No newline at end of file diff --git a/snapshots/EthPrivErc20VaultTest.json b/snapshots/EthPrivErc20VaultTest.json new file mode 100644 index 00000000..7af30373 --- /dev/null +++ b/snapshots/EthPrivErc20VaultTest.json @@ -0,0 +1,9 @@ +{ + "EthPrivErc20VaultTest_test_canDepositAndMintOsTokenAsWhitelistedUser": "201938", + "EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "81342", + "EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "77628", + "EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161538", + "EthPrivErc20VaultTest_test_deploysCorrectly": "623640", + "EthPrivErc20VaultTest_test_transfer": "59649", + "EthPrivErc20VaultTest_test_upgradesCorrectly": "73654" +} \ No newline at end of file diff --git a/snapshots/EthPrivVaultTest.json b/snapshots/EthPrivVaultTest.json new file mode 100644 index 00000000..cfce8501 --- /dev/null +++ b/snapshots/EthPrivVaultTest.json @@ -0,0 +1,11 @@ +{ + "EthPrivVaultTest_test_canDepositAsWhitelistedUser": "79378", + "EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "75792", + "EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161520", + "EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser": "131935", + "EthPrivVaultTest_test_deploysCorrectly": "548676", + "EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser": "200374", + "EthPrivVaultTest_test_setWhitelister": "36458", + "EthPrivVaultTest_test_updateWhitelist": "54543", + "EthPrivVaultTest_test_upgradesCorrectly": "73077" +} \ No newline at end of file diff --git a/snapshots/EthRewardSplitterTest.json b/snapshots/EthRewardSplitterTest.json new file mode 100644 index 00000000..81eec665 --- /dev/null +++ b/snapshots/EthRewardSplitterTest.json @@ -0,0 +1,14 @@ +{ + "EthRewardSplitter_claimExitedAssetsOnBehalf": "633820", + "EthRewardSplitter_claimVaultTokens": "664642", + "EthRewardSplitter_decreaseShares": "74619", + "EthRewardSplitter_enterExitQueue": "149228", + "EthRewardSplitter_enterExitQueueMaxWithdrawal": "126886", + "EthRewardSplitter_enterExitQueueOnBehalf": "844484", + "EthRewardSplitter_increaseShares": "73136", + "EthRewardSplitter_receiveEth": "31194", + "EthRewardSplitter_setClaimOnBehalf": "65579", + "EthRewardSplitter_syncRewards": "75668", + "EthRewardSplitter_syncRewardsDetailed": "73168", + "EthRewardSplitter_updateVaultState": "130309" +} \ No newline at end of file diff --git a/snapshots/EthVaultTest.json b/snapshots/EthVaultTest.json new file mode 100644 index 00000000..13232b15 --- /dev/null +++ b/snapshots/EthVaultTest.json @@ -0,0 +1,11 @@ +{ + "EthVaultTest_test_deploysCorrectly": "378482", + "EthVaultTest_test_depositAndMintOsToken": "197331", + "EthVaultTest_test_exitQueue_works": "94643", + "EthVaultTest_test_fallbackDeposit": "73062", + "EthVaultTest_test_updateStateAndDepositAndMintOsToken": "221431", + "EthVaultTest_test_upgradesCorrectly": "72923", + "EthVaultTest_test_withdrawValidator_osTokenRedeemer": "75020", + "EthVaultTest_test_withdrawValidator_unknown": "56861", + "EthVaultTest_test_withdrawValidator_validatorsManager": "69781" +} \ No newline at end of file diff --git a/snapshots/GnoBlocklistErc20VaultTest.json b/snapshots/GnoBlocklistErc20VaultTest.json new file mode 100644 index 00000000..097507e6 --- /dev/null +++ b/snapshots/GnoBlocklistErc20VaultTest.json @@ -0,0 +1,7 @@ +{ + "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "162425", + "GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161480", + "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "779115", + "GnoBlocklistErc20VaultTest_test_transfer": "61633", + "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "113240" +} \ No newline at end of file diff --git a/snapshots/GnoBlocklistVaultTest.json b/snapshots/GnoBlocklistVaultTest.json new file mode 100644 index 00000000..bd85373a --- /dev/null +++ b/snapshots/GnoBlocklistVaultTest.json @@ -0,0 +1,6 @@ +{ + "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "160483", + "GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161462", + "GnoBlocklistVaultTest_test_deploysCorrectly": "527708", + "GnoBlocklistVaultTest_test_upgradesCorrectly": "112603" +} \ No newline at end of file diff --git a/snapshots/GnoErc20VaultTest.json b/snapshots/GnoErc20VaultTest.json new file mode 100644 index 00000000..ac838de3 --- /dev/null +++ b/snapshots/GnoErc20VaultTest.json @@ -0,0 +1,12 @@ +{ + "GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv": "89970", + "GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96507", + "GnoErc20VaultTest_test_deploysCorrectly": "578930", + "GnoErc20VaultTest_test_deposit_emitsTransfer": "100622", + "GnoErc20VaultTest_test_enterExitQueue_emitsTransfer": "89780", + "GnoErc20VaultTest_test_redeem_emitsEvent": "76993", + "GnoErc20VaultTest_test_upgradesCorrectly": "113185", + "VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "75009", + "VaultGnoErc20VaultTest_test_withdrawValidator_unknown": "56850", + "VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager": "69781" +} \ No newline at end of file diff --git a/snapshots/GnoGenesisVaultTest.json b/snapshots/GnoGenesisVaultTest.json new file mode 100644 index 00000000..6a0d3126 --- /dev/null +++ b/snapshots/GnoGenesisVaultTest.json @@ -0,0 +1,5 @@ +{ + "GnoGenesisVaultTest_test_migrate_works": "201750", + "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "823811", + "GnoGenesisVaultTest_test_upgradesCorrectly": "5465764" +} \ No newline at end of file diff --git a/snapshots/GnoOsTokenVaultEscrowTest.json b/snapshots/GnoOsTokenVaultEscrowTest.json new file mode 100644 index 00000000..b615ecdb --- /dev/null +++ b/snapshots/GnoOsTokenVaultEscrowTest.json @@ -0,0 +1,5 @@ +{ + "GnoOsTokenVaultEscrowTest_test_transferAssets_claim": "118340", + "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "719392", + "GnoOsTokenVaultEscrowTest_test_transferAssets_transfer": "163157" +} \ No newline at end of file diff --git a/snapshots/GnoOwnMevEscrowTest.json b/snapshots/GnoOwnMevEscrowTest.json new file mode 100644 index 00000000..fce238f3 --- /dev/null +++ b/snapshots/GnoOwnMevEscrowTest.json @@ -0,0 +1,3 @@ +{ + "GnoOwnMevEscrowTest_test_ownMevEscrowDeploymentGas": "220288" +} \ No newline at end of file diff --git a/snapshots/GnoPrivErc20VaultTest.json b/snapshots/GnoPrivErc20VaultTest.json new file mode 100644 index 00000000..77ac25a4 --- /dev/null +++ b/snapshots/GnoPrivErc20VaultTest.json @@ -0,0 +1,7 @@ +{ + "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "158354", + "GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161413", + "GnoPrivErc20VaultTest_test_deploysCorrectly": "779049", + "GnoPrivErc20VaultTest_test_transfer": "59649", + "GnoPrivErc20VaultTest_test_upgradesCorrectly": "113200" +} \ No newline at end of file diff --git a/snapshots/GnoPrivVaultTest.json b/snapshots/GnoPrivVaultTest.json new file mode 100644 index 00000000..ea24def8 --- /dev/null +++ b/snapshots/GnoPrivVaultTest.json @@ -0,0 +1,8 @@ +{ + "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "156499", + "GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161350", + "GnoPrivVaultTest_test_deploysCorrectly": "527730", + "GnoPrivVaultTest_test_setWhitelister": "36458", + "GnoPrivVaultTest_test_updateWhitelist": "54521", + "GnoPrivVaultTest_test_upgradesCorrectly": "112717" +} \ No newline at end of file diff --git a/snapshots/GnoRewardSplitterTest.json b/snapshots/GnoRewardSplitterTest.json new file mode 100644 index 00000000..583525c8 --- /dev/null +++ b/snapshots/GnoRewardSplitterTest.json @@ -0,0 +1,14 @@ +{ + "GnoRewardSplitter_claimExitedAssets": "90142", + "GnoRewardSplitter_claimExitedAssetsOnBehalf": "666102", + "GnoRewardSplitter_claimVaultTokens": "723475", + "GnoRewardSplitter_decreaseShares": "76505", + "GnoRewardSplitter_enterExitQueue": "150585", + "GnoRewardSplitter_enterExitQueueMaxWithdrawal": "126886", + "GnoRewardSplitter_enterExitQueueOnBehalf": "940186", + "GnoRewardSplitter_increaseShares": "68658", + "GnoRewardSplitter_setClaimOnBehalf": "65601", + "GnoRewardSplitter_syncRewards": "75668", + "GnoRewardSplitter_syncRewardsDetailed": "73168", + "GnoRewardSplitter_updateVaultState": "151524" +} \ No newline at end of file diff --git a/snapshots/GnoSharedMevEscrowTest.json b/snapshots/GnoSharedMevEscrowTest.json new file mode 100644 index 00000000..c9e9319c --- /dev/null +++ b/snapshots/GnoSharedMevEscrowTest.json @@ -0,0 +1,3 @@ +{ + "GnoSharedMevEscrowTest_test_sharedEscrowDeploymentGas": "224292" +} \ No newline at end of file diff --git a/snapshots/GnoVaultExitQueueTest.json b/snapshots/GnoVaultExitQueueTest.json new file mode 100644 index 00000000..a62fc779 --- /dev/null +++ b/snapshots/GnoVaultExitQueueTest.json @@ -0,0 +1,7 @@ +{ + "GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event": "193484", + "GnoVaultExitQueueTest_test_claim_position1_after_upgrade": "6137218", + "GnoVaultExitQueueTest_test_claim_position2_before_upgrade": "117260", + "GnoVaultExitQueueTest_test_claim_position3_after_upgrade": "89104", + "GnoVaultExitQueueTest_test_claim_position4_after_upgrade": "84291" +} \ No newline at end of file diff --git a/snapshots/GnoVaultTest.json b/snapshots/GnoVaultTest.json new file mode 100644 index 00000000..abe09284 --- /dev/null +++ b/snapshots/GnoVaultTest.json @@ -0,0 +1,8 @@ +{ + "GnoVaultTest_test_deploysCorrectly": "503812", + "GnoVaultTest_test_exitQueue_works": "94643", + "GnoVaultTest_test_upgradesCorrectly": "112526", + "GnoVaultTest_test_withdrawValidator_osTokenRedeemer": "74997", + "GnoVaultTest_test_withdrawValidator_unknown": "56838", + "GnoVaultTest_test_withdrawValidator_validatorsManager": "69758" +} \ No newline at end of file diff --git a/snapshots/KeeperOraclesTest.json b/snapshots/KeeperOraclesTest.json new file mode 100644 index 00000000..82aaff91 --- /dev/null +++ b/snapshots/KeeperOraclesTest.json @@ -0,0 +1,12 @@ +{ + "KeeperOraclesTest_test_addOracle_alreadyAdded": "28022", + "KeeperOraclesTest_test_addOracle_maxOraclesExceeded": "31511", + "KeeperOraclesTest_test_addOracle_onlyOwner": "32780", + "KeeperOraclesTest_test_addOracle_success": "53972", + "KeeperOraclesTest_test_removeOracle_alreadyRemoved": "28141", + "KeeperOraclesTest_test_removeOracle_onlyOwner": "26396", + "KeeperOraclesTest_test_removeOracle_success": "32154", + "KeeperOraclesTest_test_updateConfig_onlyOwner": "31726", + "KeeperOraclesTest_test_updateConfig_success": "32787", + "KeeperOraclesTest_test_verifySignatures_throughKeeperRewards": "208171" +} \ No newline at end of file diff --git a/snapshots/KeeperRewardsTest.json b/snapshots/KeeperRewardsTest.json new file mode 100644 index 00000000..d6d25f8d --- /dev/null +++ b/snapshots/KeeperRewardsTest.json @@ -0,0 +1,20 @@ +{ + "KeeperRewardsTest_test_canHarvest": "4438", + "KeeperRewardsTest_test_harvest": "128681", + "KeeperRewardsTest_test_harvestWithPenalties": "88494", + "KeeperRewardsTest_test_harvest_alreadyHarvested": "45945", + "KeeperRewardsTest_test_harvest_invalidProof": "44509", + "KeeperRewardsTest_test_harvest_invalidRewardsRoot": "45084", + "KeeperRewardsTest_test_harvest_nonVault": "35559", + "KeeperRewardsTest_test_isCollateralized": "1623", + "KeeperRewardsTest_test_isHarvestRequired": "2120", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_1": "128663", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_2": "495675", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_3": "493709", + "KeeperRewardsTest_test_setRewardsMinOracles": "33248", + "KeeperRewardsTest_test_setRewardsMinOracles_tooMany": "29542", + "KeeperRewardsTest_test_setRewardsMinOracles_zero": "25531", + "KeeperRewardsTest_test_updateRewards": "96923", + "KeeperRewardsTest_test_updateRewards_invalidAvgRewardPerSecond": "28759", + "KeeperRewardsTest_test_updateRewards_tooEarly": "28750" +} \ No newline at end of file diff --git a/snapshots/KeeperValidatorsTest.json b/snapshots/KeeperValidatorsTest.json new file mode 100644 index 00000000..e2349a64 --- /dev/null +++ b/snapshots/KeeperValidatorsTest.json @@ -0,0 +1,15 @@ +{ + "KeeperValidatorsTest_test_approveValidators_accessDenied": "139566", + "KeeperValidatorsTest_test_approveValidators_invalidDeadline": "29840", + "KeeperValidatorsTest_test_approveValidators_invalidRegistry": "132477", + "KeeperValidatorsTest_test_approveValidators_success": "174557", + "KeeperValidatorsTest_test_setValidatorsMinOracles_success": "33099", + "KeeperValidatorsTest_test_setValidatorsMinOracles_tooHigh": "29460", + "KeeperValidatorsTest_test_setValidatorsMinOracles_unauthorized": "25745", + "KeeperValidatorsTest_test_setValidatorsMinOracles_zero": "25382", + "KeeperValidatorsTest_test_updateExitSignatures_duplicateUpdate": "45635", + "KeeperValidatorsTest_test_updateExitSignatures_expiredDeadline": "34338", + "KeeperValidatorsTest_test_updateExitSignatures_invalidVault": "31986", + "KeeperValidatorsTest_test_updateExitSignatures_notCollateralized": "34313", + "KeeperValidatorsTest_test_updateExitSignatures_success": "68010" +} \ No newline at end of file diff --git a/snapshots/OsTokenConfigTest.json b/snapshots/OsTokenConfigTest.json new file mode 100644 index 00000000..f9a2f768 --- /dev/null +++ b/snapshots/OsTokenConfigTest.json @@ -0,0 +1,17 @@ +{ + "OsTokenConfigForkTest_test_setRedeemer": "30972", + "OsTokenConfigForkTest_test_setRedeemer_notOwner": "27710", + "OsTokenConfigForkTest_test_setRedeemer_sameValue": "27381", + "OsTokenConfigForkTest_test_updateConfig_disabledLiquidations": "56787", + "OsTokenConfigForkTest_test_updateConfig_forVault": "55186", + "OsTokenConfigForkTest_test_updateConfig_invalidDisabledLiquidations": "33162", + "OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_product": "28913", + "OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_tooLow": "33304", + "OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_ltv": "28675", + "OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_tooHigh": "28640", + "OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_zero": "33104", + "OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_tooHigh": "28671", + "OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_zero": "28479", + "OsTokenConfigForkTest_test_updateConfig_notOwner": "33393", + "OsTokenConfigTest_test_updateDefaultConfig_success": "37692" +} \ No newline at end of file diff --git a/snapshots/OsTokenTest.json b/snapshots/OsTokenTest.json new file mode 100644 index 00000000..491bbbd6 --- /dev/null +++ b/snapshots/OsTokenTest.json @@ -0,0 +1,19 @@ +{ + "OsTokenTest_test_burn": "32742", + "OsTokenTest_test_burn_onlyController": "27956", + "OsTokenTest_test_controllerIntegration_burn": "36343", + "OsTokenTest_test_controllerIntegration_mint": "103994", + "OsTokenTest_test_erc20_transfer": "54454", + "OsTokenTest_test_erc20_transferFrom": "95658", + "OsTokenTest_test_fullDepositFlow": "195278", + "OsTokenTest_test_mint": "54400", + "OsTokenTest_test_mint_onlyController": "30281", + "OsTokenTest_test_permit": "75632", + "OsTokenTest_test_permit_expiredDeadline": "32235", + "OsTokenTest_test_permit_invalidSignature": "51951", + "OsTokenTest_test_permit_zeroAddress": "56033", + "OsTokenTest_test_setController_add": "51103", + "OsTokenTest_test_setController_onlyOwner": "32836", + "OsTokenTest_test_setController_remove": "30637", + "OsTokenTest_test_setController_zeroAddress": "25570" +} \ No newline at end of file diff --git a/snapshots/OwnMevEscrowTest.json b/snapshots/OwnMevEscrowTest.json new file mode 100644 index 00000000..f2548a9b --- /dev/null +++ b/snapshots/OwnMevEscrowTest.json @@ -0,0 +1,8 @@ +{ + "OwnMevEscrowTest_test_harvest_fromNonVault": "23482", + "OwnMevEscrowTest_test_harvest_fromVault": "37691", + "OwnMevEscrowTest_test_harvest_zeroBalance": "22226", + "OwnMevEscrowTest_test_multipleHarvests": "37691", + "OwnMevEscrowTest_test_multipleSenders": "37691", + "OwnMevEscrowTest_test_receiveMev": "34061" +} \ No newline at end of file diff --git a/snapshots/PriceFeedTest.json b/snapshots/PriceFeedTest.json new file mode 100644 index 00000000..7b7f2eb5 --- /dev/null +++ b/snapshots/PriceFeedTest.json @@ -0,0 +1,5 @@ +{ + "PriceFeedTest_test_getRate_gas": "18476", + "PriceFeedTest_test_latestAnswer_gas": "18525", + "PriceFeedTest_test_latestRoundData_gas": "18996" +} \ No newline at end of file diff --git a/snapshots/VaultAdminTest.json b/snapshots/VaultAdminTest.json new file mode 100644 index 00000000..f9d9fc96 --- /dev/null +++ b/snapshots/VaultAdminTest.json @@ -0,0 +1,10 @@ +{ + "VaultAdminTest_test_checkAdmin_withOtherFunctions_admin": "43348", + "VaultAdminTest_test_checkAdmin_withOtherFunctions_nonAdmin": "34790", + "VaultAdminTest_test_initialization": "377286", + "VaultAdminTest_test_setAdmin_byAdmin": "39009", + "VaultAdminTest_test_setAdmin_byNonAdmin": "36858", + "VaultAdminTest_test_setAdmin_toZeroAddress": "34573", + "VaultAdminTest_test_setMetadata_byAdmin": "37018", + "VaultAdminTest_test_setMetadata_byNonAdmin": "35267" +} \ No newline at end of file diff --git a/snapshots/VaultEnterExitTest.json b/snapshots/VaultEnterExitTest.json new file mode 100644 index 00000000..4818ebb2 --- /dev/null +++ b/snapshots/VaultEnterExitTest.json @@ -0,0 +1,24 @@ +{ + "VaultEnterExitTest_test_calculateExitedAssets_invalidPosition": "16077", + "VaultEnterExitTest_test_claimExitedAssets": "604600", + "VaultEnterExitTest_test_claimExitedAssets_insufficientDelay": "39366", + "VaultEnterExitTest_test_claimExitedAssets_invalidCheckpoint": "36506", + "VaultEnterExitTest_test_deposit_exceedingCapacity": "47943", + "VaultEnterExitTest_test_deposit_success_basic": "78595", + "VaultEnterExitTest_test_deposit_success_differentReceiver": "76498", + "VaultEnterExitTest_test_deposit_success_multipleDeposits": "57398", + "VaultEnterExitTest_test_deposit_success_receiveFunction": "75053", + "VaultEnterExitTest_test_deposit_success_withReferrer": "76720", + "VaultEnterExitTest_test_deposit_zeroAddress": "49918", + "VaultEnterExitTest_test_deposit_zeroAmount": "43483", + "VaultEnterExitTest_test_enterExitQueue_afterValidatorExit": "89855", + "VaultEnterExitTest_test_enterExitQueue_basicFlow": "89843", + "VaultEnterExitTest_test_enterExitQueue_directRedemption": "81841", + "VaultEnterExitTest_test_enterExitQueue_invalidParams_tooManyShares": "47257", + "VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroAddress": "32832", + "VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroShares": "31356", + "VaultEnterExitTest_test_enterExitQueue_multiUser_sender2": "72995", + "VaultEnterExitTest_test_enterExitQueue_multiUser_user1": "89843", + "VaultEnterExitTest_test_enterExitQueue_multipleUpdates": "89746", + "VaultEnterExitTest_test_enterExitQueue_partialExit": "94643" +} \ No newline at end of file diff --git a/snapshots/VaultEthStakingTest.json b/snapshots/VaultEthStakingTest.json new file mode 100644 index 00000000..d12b65c6 --- /dev/null +++ b/snapshots/VaultEthStakingTest.json @@ -0,0 +1,18 @@ +{ + "VaultEthStakingTest_test_deposit": "80760", + "VaultEthStakingTest_test_depositAndMintOsToken": "199818", + "VaultEthStakingTest_test_fundValidators_invalid": "52830", + "VaultEthStakingTest_test_fundValidators_valid": "131837", + "VaultEthStakingTest_test_harvestAssets": "128671", + "VaultEthStakingTest_test_invalidSecurityDeposit": "307071", + "VaultEthStakingTest_test_receive": "72953", + "VaultEthStakingTest_test_receiveFromMevEscrow_fail": "36592", + "VaultEthStakingTest_test_receiveFromMevEscrow_success": "37848", + "VaultEthStakingTest_test_registerValidators_01prefix": "239744", + "VaultEthStakingTest_test_registerValidators_02prefix": "421816", + "VaultEthStakingTest_test_transferVaultAssets": "49705", + "VaultEthStakingTest_test_updateStateAndDeposit": "159946", + "VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken": "251911", + "VaultEthStakingTest_test_validatorMinMaxEffectiveBalance": "195664", + "VaultEthStakingTest_test_withdrawValidator_fullFlow": "69781" +} \ No newline at end of file diff --git a/snapshots/VaultFeeTest.json b/snapshots/VaultFeeTest.json new file mode 100644 index 00000000..22bdeacd --- /dev/null +++ b/snapshots/VaultFeeTest.json @@ -0,0 +1,15 @@ +{ + "VaultFeeTest_test_feeCollection": "115247", + "VaultFeeTest_test_feePercent_changeAffectsFutureRewards": "81049", + "VaultFeeTest_test_setFeePercent_aboveMaximum": "40380", + "VaultFeeTest_test_setFeePercent_initialZeroToOne": "42312", + "VaultFeeTest_test_setFeePercent_maxIncrease": "38472", + "VaultFeeTest_test_setFeePercent_notAdmin": "34556", + "VaultFeeTest_test_setFeePercent_requiresHarvest": "38001", + "VaultFeeTest_test_setFeePercent_success": "42575", + "VaultFeeTest_test_setFeePercent_tooSoon": "38137", + "VaultFeeTest_test_setFeeRecipient_notAdmin": "36854", + "VaultFeeTest_test_setFeeRecipient_requiresHarvest": "40296", + "VaultFeeTest_test_setFeeRecipient_success": "48796", + "VaultFeeTest_test_setFeeRecipient_zeroAddress": "40343" +} \ No newline at end of file diff --git a/snapshots/VaultGnoStakingTest.json b/snapshots/VaultGnoStakingTest.json new file mode 100644 index 00000000..2a88ce19 --- /dev/null +++ b/snapshots/VaultGnoStakingTest.json @@ -0,0 +1,14 @@ +{ + "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "136579", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid": "52815", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "170435", + "VaultGnoStakingTest_test_deposit": "101016", + "VaultGnoStakingTest_test_processTotalAssetsDelta": "219229", + "VaultGnoStakingTest_test_pullWithdrawals": "88447", + "VaultGnoStakingTest_test_receive_xDai": "33415", + "VaultGnoStakingTest_test_transferVaultAssets": "85372", + "VaultGnoStakingTest_test_vaultGnoStaking_init": "503857", + "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "69758", + "test_registerValidators_succeeds_0x01": "283609", + "test_registerValidators_succeeds_0x02": "545373" +} \ No newline at end of file diff --git a/snapshots/VaultOsTokenTest.json b/snapshots/VaultOsTokenTest.json new file mode 100644 index 00000000..a0a4878c --- /dev/null +++ b/snapshots/VaultOsTokenTest.json @@ -0,0 +1,48 @@ +{ + "VaultOsTokenTest_test_burnOsToken_afterFeeSync": "71424", + "VaultOsTokenTest_test_burnOsToken_allShares": "66187", + "VaultOsTokenTest_test_burnOsToken_basic": "70987", + "VaultOsTokenTest_test_burnOsToken_exceedingShares": "48701", + "VaultOsTokenTest_test_burnOsToken_improvesLTV": "70999", + "VaultOsTokenTest_test_burnOsToken_invalidPosition": "66210", + "VaultOsTokenTest_test_burnOsToken_multipleBurns": "70987", + "VaultOsTokenTest_test_burnOsToken_zeroShares": "37846", + "VaultOsTokenTest_test_enterExitQueue_ltvViolation": "118185", + "VaultOsTokenTest_test_liquidateOsToken_basic": "120072", + "VaultOsTokenTest_test_liquidateOsToken_bonus": "120072", + "VaultOsTokenTest_test_liquidateOsToken_invalidReceivedAssets": "73028", + "VaultOsTokenTest_test_liquidateOsToken_liquidationDisabled": "68988", + "VaultOsTokenTest_test_liquidateOsToken_partialLiquidation": "120072", + "VaultOsTokenTest_test_mintOsToken_basic": "157446", + "VaultOsTokenTest_test_mintOsToken_feeSync": "103337", + "VaultOsTokenTest_test_mintOsToken_ltvValidation": "140319", + "VaultOsTokenTest_test_mintOsToken_maxAmount": "157827", + "VaultOsTokenTest_test_mintOsToken_multipleReceivers": "119813", + "VaultOsTokenTest_test_mintOsToken_notCollateralized": "39431", + "VaultOsTokenTest_test_mintOsToken_notHarvested": "45593", + "VaultOsTokenTest_test_mintOsToken_repeatedMinting": "105518", + "VaultOsTokenTest_test_mintOsToken_zeroAddressReceiver": "86660", + "VaultOsTokenTest_test_mintOsToken_zeroShares": "88940", + "VaultOsTokenTest_test_redeemOsToken_afterFeeSync": "129608", + "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail": "44527", + "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success": "263310", + "VaultOsTokenTest_test_redeemOsToken_basic": "129171", + "VaultOsTokenTest_test_redeemOsToken_fullPosition": "129171", + "VaultOsTokenTest_test_redeemOsToken_goodHealthFactor": "129254", + "VaultOsTokenTest_test_redeemOsToken_insufficientShares": "106195", + "VaultOsTokenTest_test_redeemOsToken_nonExistentPosition": "87096", + "VaultOsTokenTest_test_redeemOsToken_onlyRedeemer": "36448", + "VaultOsTokenTest_test_redeemOsToken_zeroAddressReceiver": "34261", + "VaultOsTokenTest_test_redeemOsToken_zeroShares": "83797", + "VaultOsTokenTest_test_redeemVsLiquidate": "129254", + "VaultOsTokenTest_test_test_liquidateOsToken_notHarvested": "41526", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_basic": "163167", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_claim": "99265", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_maxAmount": "163179", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_moreThanOwned": "44795", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_noPosition": "43502", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested": "36830", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer": "173165", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process": "625682", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares": "47480" +} \ No newline at end of file diff --git a/snapshots/VaultTokenTest.json b/snapshots/VaultTokenTest.json new file mode 100644 index 00000000..358f0d78 --- /dev/null +++ b/snapshots/VaultTokenTest.json @@ -0,0 +1,22 @@ +{ + "VaultTokenTest_test_approve": "52346", + "VaultTokenTest_test_approveZeroAddress": "33703", + "VaultTokenTest_test_depositEmitsTransferEvent": "78928", + "VaultTokenTest_test_enterExitQueueEmitsTransferEvent": "94566", + "VaultTokenTest_test_invalidTokenMetaNameTooLong": "476767", + "VaultTokenTest_test_invalidTokenMetaSymbolTooLong": "309835", + "VaultTokenTest_test_permit": "82702", + "VaultTokenTest_test_permitExpiredDeadline": "30817", + "VaultTokenTest_test_permitInvalidSigner": "59070", + "VaultTokenTest_test_permitZeroAddressSpender": "30363", + "VaultTokenTest_test_transfer": "59941", + "VaultTokenTest_test_transferFrom": "61179", + "VaultTokenTest_test_transferFromMoreThanAllowance": "32458", + "VaultTokenTest_test_transferFromMoreThanBalance": "37906", + "VaultTokenTest_test_transferFromZeroAddress": "38513", + "VaultTokenTest_test_transferMoreThanBalance": "33862", + "VaultTokenTest_test_transferToZeroAddress": "29234", + "VaultTokenTest_test_transferWithOsTokenPosition": "91954", + "VaultTokenTest_test_unlimitedAllowance": "62839", + "VaultTokenTest_test_updateExitQueueBurnsShares": "142163" +} \ No newline at end of file diff --git a/snapshots/VaultValidatorsTest.json b/snapshots/VaultValidatorsTest.json new file mode 100644 index 00000000..6128d3d7 --- /dev/null +++ b/snapshots/VaultValidatorsTest.json @@ -0,0 +1,43 @@ +{ + "VaultValidatorsTest_test_consolidateValidators_byManager": "74807", + "VaultValidatorsTest_test_consolidateValidators_feeHandling": "81808", + "VaultValidatorsTest_test_consolidateValidators_invalidSignature": "67704", + "VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty": "51204", + "VaultValidatorsTest_test_consolidateValidators_invalidValidatorsLength": "57426", + "VaultValidatorsTest_test_consolidateValidators_multipleValidators": "94995", + "VaultValidatorsTest_test_consolidateValidators_notManager": "52834", + "VaultValidatorsTest_test_consolidateValidators_untrackedDestination": "74303", + "VaultValidatorsTest_test_consolidateValidators_withOracleSignatures": "111382", + "VaultValidatorsTest_test_consolidateValidators_withSignature": "107300", + "VaultValidatorsTest_test_fundValidators_byManager": "101092", + "VaultValidatorsTest_test_fundValidators_insufficientAssets": "101419", + "VaultValidatorsTest_test_fundValidators_invalidSignature": "59249", + "VaultValidatorsTest_test_fundValidators_invalidValidators": "41331", + "VaultValidatorsTest_test_fundValidators_multipleValidators": "143741", + "VaultValidatorsTest_test_fundValidators_nonExistingValidator": "52854", + "VaultValidatorsTest_test_fundValidators_notHarvested": "39858", + "VaultValidatorsTest_test_fundValidators_notManager": "44366", + "VaultValidatorsTest_test_fundValidators_v1Validators": "48296", + "VaultValidatorsTest_test_fundValidators_withSignature": "133557", + "VaultValidatorsTest_test_registerValidators_byManager": "265170", + "VaultValidatorsTest_test_registerValidators_insufficientAssets": "39964", + "VaultValidatorsTest_test_registerValidators_invalidSignature": "206586", + "VaultValidatorsTest_test_registerValidators_invalidValidatorLength": "194492", + "VaultValidatorsTest_test_registerValidators_invalidValidators": "188557", + "VaultValidatorsTest_test_registerValidators_multipleValidators": "299669", + "VaultValidatorsTest_test_registerValidators_nonceIncrement": "143933", + "VaultValidatorsTest_test_registerValidators_notHarvested": "166243", + "VaultValidatorsTest_test_registerValidators_notManager": "191735", + "VaultValidatorsTest_test_registerValidators_v1Validators": "239739", + "VaultValidatorsTest_test_registerValidators_v2Validators": "262670", + "VaultValidatorsTest_test_registerValidators_withSignature": "299634", + "VaultValidatorsTest_test_withdrawValidators_byManager": "69769", + "VaultValidatorsTest_test_withdrawValidators_byRedeemer": "75008", + "VaultValidatorsTest_test_withdrawValidators_feeHandling": "76770", + "VaultValidatorsTest_test_withdrawValidators_invalidSignature": "71746", + "VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty": "55970", + "VaultValidatorsTest_test_withdrawValidators_invalidValidatorsLength": "56660", + "VaultValidatorsTest_test_withdrawValidators_multipleValidators": "85451", + "VaultValidatorsTest_test_withdrawValidators_notAuthorized": "56912", + "VaultValidatorsTest_test_withdrawValidators_withSignature": "102206" +} \ No newline at end of file diff --git a/snapshots/VaultVersionTest.json b/snapshots/VaultVersionTest.json new file mode 100644 index 00000000..9ccbb283 --- /dev/null +++ b/snapshots/VaultVersionTest.json @@ -0,0 +1,12 @@ +{ + "VaultVersionTest_test_reinitializeFails": "30868", + "VaultVersionTest_test_upgradeMultipleSteps": "56466", + "VaultVersionTest_test_upgradeNonAdminFails": "38894", + "VaultVersionTest_test_upgradeToDifferentVaultIdFails": "42341", + "VaultVersionTest_test_upgradeToNextVersion": "83648", + "VaultVersionTest_test_upgradeToSameVersionFails": "32627", + "VaultVersionTest_test_upgradeToSkipVersionFails": "43084", + "VaultVersionTest_test_upgradeToUnapprovedImplementationFails": "46393", + "VaultVersionTest_test_upgradeToZeroAddressFails": "36662", + "VaultVersionTest_test_upgradeWithInvalidCallDataFails": "60697" +} \ No newline at end of file diff --git a/snapshots/VaultsRegistryTest.json b/snapshots/VaultsRegistryTest.json new file mode 100644 index 00000000..5456d7ba --- /dev/null +++ b/snapshots/VaultsRegistryTest.json @@ -0,0 +1,20 @@ +{ + "VaultsRegistryTest_test_addFactory": "56549", + "VaultsRegistryTest_test_addFactory_alreadyAdded": "27519", + "VaultsRegistryTest_test_addFactory_notOwner": "32228", + "VaultsRegistryTest_test_addVault": "52769", + "VaultsRegistryTest_test_addVaultImpl": "56720", + "VaultsRegistryTest_test_addVaultImpl_alreadyAdded": "27695", + "VaultsRegistryTest_test_addVaultImpl_notOwner": "32404", + "VaultsRegistryTest_test_addVault_asOwner": "59391", + "VaultsRegistryTest_test_addVault_notFactoryOrOwner": "33976", + "VaultsRegistryTest_test_initialize": "53876", + "VaultsRegistryTest_test_initialize_alreadyInitialized": "27356", + "VaultsRegistryTest_test_initialize_zeroAddress": "24983", + "VaultsRegistryTest_test_removeFactory": "28212", + "VaultsRegistryTest_test_removeFactory_alreadyRemoved": "34077", + "VaultsRegistryTest_test_removeFactory_notOwner": "25794", + "VaultsRegistryTest_test_removeVaultImpl": "28163", + "VaultsRegistryTest_test_removeVaultImpl_alreadyRemoved": "34044", + "VaultsRegistryTest_test_removeVaultImpl_notOwner": "25750" +} \ No newline at end of file diff --git a/test/ConsolidationsChecker.t.sol b/test/ConsolidationsChecker.t.sol index e9cfa2c8..6568714d 100644 --- a/test/ConsolidationsChecker.t.sol +++ b/test/ConsolidationsChecker.t.sol @@ -1,471 +1,427 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {ConsolidationsChecker} from '../contracts/validators/ConsolidationsChecker.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; +import {Test} from "forge-std/Test.sol"; +import {ConsolidationsChecker} from "../contracts/validators/ConsolidationsChecker.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; contract ConsolidationsCheckerTest is Test, EthHelpers { - ForkContracts public contracts; - ConsolidationsChecker public consolidationsChecker; - - address public admin; - address public vault; - - // Oracle-related variables - address[] private _oracleAddresses; - uint256[] private _oraclePrivateKeys; - uint256 private _validatorsMinOraclesBefore; - - // Constants for testing - uint256 private constant SIGNATURE_LENGTH = 65; - bytes32 private constant _consolidationsCheckerTypeHash = - keccak256('ConsolidationsChecker(address vault,bytes validators)'); - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - consolidationsChecker = ConsolidationsChecker(address(contracts.consolidationsChecker)); - - // Set up test accounts - admin = makeAddr('admin'); - vault = makeAddr('vault'); - - // Store initial min oracles value - _validatorsMinOraclesBefore = contracts.keeper.validatorsMinOracles(); - - // Create test oracles (we'll create 4 oracles) - _oracleAddresses = new address[](4); - _oraclePrivateKeys = new uint256[](4); - - for (uint i = 0; i < 4; i++) { - (_oracleAddresses[i], _oraclePrivateKeys[i]) = makeAddrAndKey( - string(abi.encodePacked('oracle', vm.toString(i))) - ); + ForkContracts public contracts; + ConsolidationsChecker public consolidationsChecker; + + address public admin; + address public vault; + + // Oracle-related variables + address[] private _oracleAddresses; + uint256[] private _oraclePrivateKeys; + uint256 private _validatorsMinOraclesBefore; + + // Constants for testing + uint256 private constant SIGNATURE_LENGTH = 65; + bytes32 private constant _consolidationsCheckerTypeHash = + keccak256("ConsolidationsChecker(address vault,bytes validators)"); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + consolidationsChecker = ConsolidationsChecker(address(contracts.consolidationsChecker)); + + // Set up test accounts + admin = makeAddr("admin"); + vault = makeAddr("vault"); + + // Store initial min oracles value + _validatorsMinOraclesBefore = contracts.keeper.validatorsMinOracles(); + + // Create test oracles (we'll create 4 oracles) + _oracleAddresses = new address[](4); + _oraclePrivateKeys = new uint256[](4); + + for (uint256 i = 0; i < 4; i++) { + (_oracleAddresses[i], _oraclePrivateKeys[i]) = + makeAddrAndKey(string(abi.encodePacked("oracle", vm.toString(i)))); + } + + // Configure keeper with our test oracles + _setupOracles(); } - // Configure keeper with our test oracles - _setupOracles(); - } + function tearDown() public { + // Clean up oracles to restore original state + _cleanupOracles(); + } - function tearDown() public { - // Clean up oracles to restore original state - _cleanupOracles(); - } + // Setup oracle configuration for testing + function _setupOracles() internal { + vm.startPrank(contracts.keeper.owner()); - // Setup oracle configuration for testing - function _setupOracles() internal { - vm.startPrank(contracts.keeper.owner()); + // Set min oracles to 3 for testing + contracts.keeper.setValidatorsMinOracles(3); - // Set min oracles to 3 for testing - contracts.keeper.setValidatorsMinOracles(3); + // Add our test oracles + for (uint256 i = 0; i < _oracleAddresses.length; i++) { + contracts.keeper.addOracle(_oracleAddresses[i]); + } - // Add our test oracles - for (uint i = 0; i < _oracleAddresses.length; i++) { - contracts.keeper.addOracle(_oracleAddresses[i]); + vm.stopPrank(); } - vm.stopPrank(); - } + // Cleanup after tests + function _cleanupOracles() internal { + vm.startPrank(contracts.keeper.owner()); + + // Remove test oracles + for (uint256 i = 0; i < _oracleAddresses.length; i++) { + if (contracts.keeper.isOracle(_oracleAddresses[i])) { + contracts.keeper.removeOracle(_oracleAddresses[i]); + } + } + + // Restore original min oracles setting + contracts.keeper.setValidatorsMinOracles(_validatorsMinOraclesBefore); - // Cleanup after tests - function _cleanupOracles() internal { - vm.startPrank(contracts.keeper.owner()); + vm.stopPrank(); + } - // Remove test oracles - for (uint i = 0; i < _oracleAddresses.length; i++) { - if (contracts.keeper.isOracle(_oracleAddresses[i])) { - contracts.keeper.removeOracle(_oracleAddresses[i]); - } + // Helper to create a message hash for signing + function _getMessageHash(address _vault, bytes memory validators) internal view returns (bytes32) { + bytes32 domainSeparator = keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256("ConsolidationsChecker"), + keccak256("1"), + block.chainid, + address(consolidationsChecker) + ) + ); + + bytes32 structHash = keccak256(abi.encode(_consolidationsCheckerTypeHash, _vault, keccak256(validators))); + + return MessageHashUtils.toTypedDataHash(domainSeparator, structHash); } - // Restore original min oracles setting - contracts.keeper.setValidatorsMinOracles(_validatorsMinOraclesBefore); - - vm.stopPrank(); - } - - // Helper to create a message hash for signing - function _getMessageHash( - address _vault, - bytes memory validators - ) internal view returns (bytes32) { - bytes32 domainSeparator = keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256('ConsolidationsChecker'), - keccak256('1'), - block.chainid, - address(consolidationsChecker) - ) - ); - - bytes32 structHash = keccak256( - abi.encode(_consolidationsCheckerTypeHash, _vault, keccak256(validators)) - ); - - return MessageHashUtils.toTypedDataHash(domainSeparator, structHash); - } - - // Helper to generate valid signatures for test oracles - function _generateValidSignatures( - address _vault, - bytes memory validators, - uint numSigners - ) internal returns (bytes memory) { - require(numSigners <= _oracleAddresses.length, 'Too many signers requested'); - - bytes32 messageHash = _getMessageHash(_vault, validators); - bytes memory signatures = new bytes(0); - - // Create signatures from oracles in ascending order - address[] memory signers = new address[](numSigners); - for (uint i = 0; i < numSigners; i++) { - signers[i] = _oracleAddresses[i]; + // Helper to generate valid signatures for test oracles + function _generateValidSignatures(address _vault, bytes memory validators, uint256 numSigners) + internal + returns (bytes memory) + { + require(numSigners <= _oracleAddresses.length, "Too many signers requested"); + + bytes32 messageHash = _getMessageHash(_vault, validators); + bytes memory signatures = new bytes(0); + + // Create signatures from oracles in ascending order + address[] memory signers = new address[](numSigners); + for (uint256 i = 0; i < numSigners; i++) { + signers[i] = _oracleAddresses[i]; + } + + // Sort signers by address (ascending) + for (uint256 i = 0; i < signers.length; i++) { + for (uint256 j = i + 1; j < signers.length; j++) { + if (signers[i] > signers[j]) { + address temp = signers[i]; + signers[i] = signers[j]; + signers[j] = temp; + + // Also swap corresponding private keys + uint256 tempKey = _oraclePrivateKeys[i]; + _oraclePrivateKeys[i] = _oraclePrivateKeys[j]; + _oraclePrivateKeys[j] = tempKey; + } + } + } + + // Generate signatures + for (uint256 i = 0; i < numSigners; i++) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKeys[i], messageHash); + signatures = bytes.concat(signatures, abi.encodePacked(r, s, v)); + } + + return signatures; } - // Sort signers by address (ascending) - for (uint i = 0; i < signers.length; i++) { - for (uint j = i + 1; j < signers.length; j++) { - if (signers[i] > signers[j]) { - address temp = signers[i]; - signers[i] = signers[j]; - signers[j] = temp; - - // Also swap corresponding private keys - uint256 tempKey = _oraclePrivateKeys[i]; - _oraclePrivateKeys[i] = _oraclePrivateKeys[j]; - _oraclePrivateKeys[j] = tempKey; + // Helper function to create a deterministic validator public key (48 bytes) + function _createPublicKey(string memory seed) internal pure returns (bytes memory) { + // Create a deterministic bytes array based on the seed + bytes32 hash = keccak256(abi.encodePacked(seed)); + bytes memory result = new bytes(48); + + // Use the hash to fill the first 32 bytes + for (uint256 i = 0; i < 32; i++) { + result[i] = hash[i]; + } + + // Fill the remaining 16 bytes with values derived from the hash + for (uint256 i = 32; i < 48; i++) { + result[i] = hash[i - 32]; } - } + + return result; + } + + // Test successful signature verification + function test_verifySignatures_success() public { + // Create test validator data with proper length public keys (48 bytes each) + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate valid signatures from the required number of oracles + bytes memory validSignatures = + _generateValidSignatures(vault, validatorsData, contracts.keeper.validatorsMinOracles()); + + // Verify that signature verification succeeds + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_success"); + consolidationsChecker.verifySignatures(vault, validatorsData, validSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, validSignatures); + assertTrue(isValid, "Signatures should be valid"); } - // Generate signatures - for (uint i = 0; i < numSigners; i++) { - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKeys[i], messageHash); - signatures = bytes.concat(signatures, abi.encodePacked(r, s, v)); + // Test failure with too few signatures + function test_verifySignatures_tooFewSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Required signatures is 3, generate only 2 + bytes memory insufficientSignatures = _generateValidSignatures(vault, validatorsData, 2); + + // Verify that signature verification fails + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_tooFewSignatures"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, insufficientSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, insufficientSignatures); + assertFalse(isValid, "Signatures should be invalid due to insufficient count"); } - return signatures; - } + // Test failure with unsorted signatures + function test_verifySignatures_unsortedSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - // Helper function to create a deterministic validator public key (48 bytes) - function _createPublicKey(string memory seed) internal pure returns (bytes memory) { - // Create a deterministic bytes array based on the seed - bytes32 hash = keccak256(abi.encodePacked(seed)); - bytes memory result = new bytes(48); + // Create message hash for signing + bytes32 messageHash = _getMessageHash(vault, validatorsData); - // Use the hash to fill the first 32 bytes - for (uint i = 0; i < 32; i++) { - result[i] = hash[i]; + // Generate unsorted signatures manually + bytes memory unsortedSignatures = new bytes(0); + + // Generate in reverse order (assuming _oracleAddresses is not already sorted) + for (uint256 i = 3; i > 0; i--) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKeys[i - 1], messageHash); + unsortedSignatures = bytes.concat(unsortedSignatures, abi.encodePacked(r, s, v)); + } + + // Verify that signature verification fails + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_unsortedSignatures"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, unsortedSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, unsortedSignatures); + assertFalse(isValid, "Signatures should be invalid due to incorrect ordering"); } - // Fill the remaining 16 bytes with values derived from the hash - for (uint i = 32; i < 48; i++) { - result[i] = hash[i - 32]; + // Test failure with repeated signer + function test_verifySignatures_repeatedSigner() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create message hash for signing + bytes32 messageHash = _getMessageHash(vault, validatorsData); + + // Generate signatures with a repeated signer + bytes memory repeatedSignatures = new bytes(0); + + // First oracle signs + (uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(_oraclePrivateKeys[0], messageHash); + repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r1, s1, v1)); + + // Second oracle signs + (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(_oraclePrivateKeys[1], messageHash); + repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r2, s2, v2)); + + // First oracle signs again (repeated) + repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r1, s1, v1)); + + // Verify that signature verification fails + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_repeatedSigner"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, repeatedSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, repeatedSignatures); + assertFalse(isValid, "Signatures should be invalid due to repeated signer"); } - return result; - } - - // Test successful signature verification - function test_verifySignatures_success() public { - // Create test validator data with proper length public keys (48 bytes each) - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Generate valid signatures from the required number of oracles - bytes memory validSignatures = _generateValidSignatures( - vault, - validatorsData, - contracts.keeper.validatorsMinOracles() - ); - - // Verify that signature verification succeeds - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_success'); - consolidationsChecker.verifySignatures(vault, validatorsData, validSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, validSignatures); - assertTrue(isValid, 'Signatures should be valid'); - } - - // Test failure with too few signatures - function test_verifySignatures_tooFewSignatures() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Required signatures is 3, generate only 2 - bytes memory insufficientSignatures = _generateValidSignatures(vault, validatorsData, 2); - - // Verify that signature verification fails - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_tooFewSignatures'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(vault, validatorsData, insufficientSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures( - vault, - validatorsData, - insufficientSignatures - ); - assertFalse(isValid, 'Signatures should be invalid due to insufficient count'); - } - - // Test failure with unsorted signatures - function test_verifySignatures_unsortedSignatures() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Create message hash for signing - bytes32 messageHash = _getMessageHash(vault, validatorsData); - - // Generate unsorted signatures manually - bytes memory unsortedSignatures = new bytes(0); - - // Generate in reverse order (assuming _oracleAddresses is not already sorted) - for (uint i = 3; i > 0; i--) { - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKeys[i - 1], messageHash); - unsortedSignatures = bytes.concat(unsortedSignatures, abi.encodePacked(r, s, v)); + // Test failure with non-oracle signer + function test_verifySignatures_nonOracleSigner() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create message hash for signing + bytes32 messageHash = _getMessageHash(vault, validatorsData); + + // Create a non-oracle signer + (, uint256 nonOracleKey) = makeAddrAndKey("nonOracle"); + + // Generate signatures with a non-oracle signer + bytes memory invalidSignatures = new bytes(0); + + // First valid oracle signs + (uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(_oraclePrivateKeys[0], messageHash); + invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r1, s1, v1)); + + // Non-oracle signer signs + (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(nonOracleKey, messageHash); + invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r2, s2, v2)); + + bytes memory validatorsData_ = validatorsData; + + // Third valid oracle signs + (uint8 v3, bytes32 r3, bytes32 s3) = vm.sign(_oraclePrivateKeys[2], messageHash); + invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r3, s3, v3)); + + // Verify that signature verification fails + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_nonOracleSigner"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData_, invalidSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData_, invalidSignatures); + assertFalse(isValid, "Signatures should be invalid due to non-oracle signer"); + } + + // Test with empty signatures + function test_verifySignatures_emptySignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Empty signatures + bytes memory emptySignatures = new bytes(0); + + // Verify that signature verification fails + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_emptySignatures"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData, emptySignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, emptySignatures); + assertFalse(isValid, "Signatures should be invalid because they are empty"); } - // Verify that signature verification fails - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_unsortedSignatures'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(vault, validatorsData, unsortedSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures( - vault, - validatorsData, - unsortedSignatures - ); - assertFalse(isValid, 'Signatures should be invalid due to incorrect ordering'); - } - - // Test failure with repeated signer - function test_verifySignatures_repeatedSigner() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Create message hash for signing - bytes32 messageHash = _getMessageHash(vault, validatorsData); - - // Generate signatures with a repeated signer - bytes memory repeatedSignatures = new bytes(0); - - // First oracle signs - (uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(_oraclePrivateKeys[0], messageHash); - repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r1, s1, v1)); - - // Second oracle signs - (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(_oraclePrivateKeys[1], messageHash); - repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r2, s2, v2)); - - // First oracle signs again (repeated) - repeatedSignatures = bytes.concat(repeatedSignatures, abi.encodePacked(r1, s1, v1)); - - // Verify that signature verification fails - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_repeatedSigner'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(vault, validatorsData, repeatedSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures( - vault, - validatorsData, - repeatedSignatures - ); - assertFalse(isValid, 'Signatures should be invalid due to repeated signer'); - } - - // Test failure with non-oracle signer - function test_verifySignatures_nonOracleSigner() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Create message hash for signing - bytes32 messageHash = _getMessageHash(vault, validatorsData); - - // Create a non-oracle signer - (, uint256 nonOracleKey) = makeAddrAndKey('nonOracle'); - - // Generate signatures with a non-oracle signer - bytes memory invalidSignatures = new bytes(0); - - // First valid oracle signs - (uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(_oraclePrivateKeys[0], messageHash); - invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r1, s1, v1)); - - // Non-oracle signer signs - (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(nonOracleKey, messageHash); - invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r2, s2, v2)); - - bytes memory validatorsData_ = validatorsData; - - // Third valid oracle signs - (uint8 v3, bytes32 r3, bytes32 s3) = vm.sign(_oraclePrivateKeys[2], messageHash); - invalidSignatures = bytes.concat(invalidSignatures, abi.encodePacked(r3, s3, v3)); - - // Verify that signature verification fails - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_nonOracleSigner'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(vault, validatorsData_, invalidSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures( - vault, - validatorsData_, - invalidSignatures - ); - assertFalse(isValid, 'Signatures should be invalid due to non-oracle signer'); - } - - // Test with empty signatures - function test_verifySignatures_emptySignatures() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Empty signatures - bytes memory emptySignatures = new bytes(0); - - // Verify that signature verification fails - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_emptySignatures'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(vault, validatorsData, emptySignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, emptySignatures); - assertFalse(isValid, 'Signatures should be invalid because they are empty'); - } - - // Test with minimum required signatures (edge case) - function test_verifySignatures_exactMinimumSignatures() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Generate signatures with exactly the minimum required number of oracles - bytes memory signatures = _generateValidSignatures( - vault, - validatorsData, - contracts.keeper.validatorsMinOracles() - ); - - // Verify that signature verification succeeds - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_exactMinimumSignatures'); - consolidationsChecker.verifySignatures(vault, validatorsData, signatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, signatures); - assertTrue(isValid, 'Signatures should be valid with exactly minimum required signatures'); - } - - // Test with more than minimum required signatures - function test_verifySignatures_moreThanMinimumSignatures() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Generate signatures with more than the minimum required number of oracles - bytes memory signatures = _generateValidSignatures( - vault, - validatorsData, - contracts.keeper.validatorsMinOracles() + 1 - ); - - // Verify that signature verification succeeds - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_moreThanMinimumSignatures'); - consolidationsChecker.verifySignatures(vault, validatorsData, signatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, signatures); - assertTrue(isValid, 'Signatures should be valid with more than minimum required signatures'); - } - - // Test with different validator data - function test_verifySignatures_differentValidatorData() public { - // Create test validator data sets with different public keys - bytes memory sourcePublicKey1 = _createPublicKey('source_key_1'); - bytes memory destPublicKey1 = _createPublicKey('dest_key_1'); - bytes memory validatorsData1 = bytes.concat(sourcePublicKey1, destPublicKey1); - - bytes memory sourcePublicKey2 = _createPublicKey('source_key_2'); - bytes memory destPublicKey2 = _createPublicKey('dest_key_2'); - bytes memory validatorsData2 = bytes.concat(sourcePublicKey2, destPublicKey2); - - // Generate valid signatures for validatorsData1 - bytes memory validSignatures = _generateValidSignatures( - vault, - validatorsData1, - contracts.keeper.validatorsMinOracles() - ); - - // Try to verify signatures with validatorsData2 - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_differentValidatorData'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(vault, validatorsData2, validSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData2, validSignatures); - assertFalse(isValid, 'Signatures should be invalid for different validator data'); - } - - // Test with different vault address - function test_verifySignatures_differentVault() public { - // Create test validator data with proper length public keys - bytes memory sourcePublicKey = _createPublicKey('source_key'); - bytes memory destPublicKey = _createPublicKey('dest_key'); - bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); - - // Generate valid signatures for original vault - bytes memory validSignatures = _generateValidSignatures( - vault, - validatorsData, - contracts.keeper.validatorsMinOracles() - ); - - // Create a different vault address - address differentVault = makeAddr('differentVault'); - - // Try to verify signatures with different vault - _startSnapshotGas('ConsolidationsCheckerTest_test_verifySignatures_differentVault'); - vm.expectRevert(Errors.InvalidSignatures.selector); - consolidationsChecker.verifySignatures(differentVault, validatorsData, validSignatures); - _stopSnapshotGas(); - - // Also test the direct isValidSignatures function - bool isValid = consolidationsChecker.isValidSignatures( - differentVault, - validatorsData, - validSignatures - ); - assertFalse(isValid, 'Signatures should be invalid for different vault address'); - } + // Test with minimum required signatures (edge case) + function test_verifySignatures_exactMinimumSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate signatures with exactly the minimum required number of oracles + bytes memory signatures = + _generateValidSignatures(vault, validatorsData, contracts.keeper.validatorsMinOracles()); + + // Verify that signature verification succeeds + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_exactMinimumSignatures"); + consolidationsChecker.verifySignatures(vault, validatorsData, signatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, signatures); + assertTrue(isValid, "Signatures should be valid with exactly minimum required signatures"); + } + + // Test with more than minimum required signatures + function test_verifySignatures_moreThanMinimumSignatures() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate signatures with more than the minimum required number of oracles + bytes memory signatures = + _generateValidSignatures(vault, validatorsData, contracts.keeper.validatorsMinOracles() + 1); + + // Verify that signature verification succeeds + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_moreThanMinimumSignatures"); + consolidationsChecker.verifySignatures(vault, validatorsData, signatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData, signatures); + assertTrue(isValid, "Signatures should be valid with more than minimum required signatures"); + } + + // Test with different validator data + function test_verifySignatures_differentValidatorData() public { + // Create test validator data sets with different public keys + bytes memory sourcePublicKey1 = _createPublicKey("source_key_1"); + bytes memory destPublicKey1 = _createPublicKey("dest_key_1"); + bytes memory validatorsData1 = bytes.concat(sourcePublicKey1, destPublicKey1); + + bytes memory sourcePublicKey2 = _createPublicKey("source_key_2"); + bytes memory destPublicKey2 = _createPublicKey("dest_key_2"); + bytes memory validatorsData2 = bytes.concat(sourcePublicKey2, destPublicKey2); + + // Generate valid signatures for validatorsData1 + bytes memory validSignatures = + _generateValidSignatures(vault, validatorsData1, contracts.keeper.validatorsMinOracles()); + + // Try to verify signatures with validatorsData2 + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_differentValidatorData"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(vault, validatorsData2, validSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(vault, validatorsData2, validSignatures); + assertFalse(isValid, "Signatures should be invalid for different validator data"); + } + + // Test with different vault address + function test_verifySignatures_differentVault() public { + // Create test validator data with proper length public keys + bytes memory sourcePublicKey = _createPublicKey("source_key"); + bytes memory destPublicKey = _createPublicKey("dest_key"); + bytes memory validatorsData = bytes.concat(sourcePublicKey, destPublicKey); + + // Generate valid signatures for original vault + bytes memory validSignatures = + _generateValidSignatures(vault, validatorsData, contracts.keeper.validatorsMinOracles()); + + // Create a different vault address + address differentVault = makeAddr("differentVault"); + + // Try to verify signatures with different vault + _startSnapshotGas("ConsolidationsCheckerTest_test_verifySignatures_differentVault"); + vm.expectRevert(Errors.InvalidSignatures.selector); + consolidationsChecker.verifySignatures(differentVault, validatorsData, validSignatures); + _stopSnapshotGas(); + + // Also test the direct isValidSignatures function + bool isValid = consolidationsChecker.isValidSignatures(differentVault, validatorsData, validSignatures); + assertFalse(isValid, "Signatures should be invalid for different vault address"); + } } diff --git a/test/DepositDataRegistry.t.sol b/test/DepositDataRegistry.t.sol index a229fe83..c2157af7 100644 --- a/test/DepositDataRegistry.t.sol +++ b/test/DepositDataRegistry.t.sol @@ -1,771 +1,692 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from '../lib/forge-std/src/Test.sol'; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IDepositDataRegistry} from '../contracts/interfaces/IDepositDataRegistry.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {IVaultVersion} from '../contracts/interfaces/IVaultVersion.sol'; -import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IVaultsRegistry} from '../contracts/interfaces/IVaultsRegistry.sol'; +import {Test} from "../lib/forge-std/src/Test.sol"; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {IDepositDataRegistry} from "../contracts/interfaces/IDepositDataRegistry.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; +import {IVaultValidators} from "../contracts/interfaces/IVaultValidators.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IKeeperValidators} from "../contracts/interfaces/IKeeperValidators.sol"; +import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; interface IVaultValidatorsV1 { - function validatorsRoot() external view returns (bytes32); - function validatorIndex() external view returns (uint256); - function keysManager() external view returns (address); + function validatorsRoot() external view returns (bytes32); + function validatorIndex() external view returns (uint256); + function keysManager() external view returns (address); } contract DepositDataRegistryTest is Test, EthHelpers { - ForkContracts private contracts; - IDepositDataRegistry private depositDataRegistry; - address private validVault; - address private invalidVault; - address private lowVersionVault; - address private admin; - address private nonAdmin; - address private newDepositDataManager; - uint256 private exitingAssets; - - function setUp() public { - contracts = _activateEthereumFork(); - - // Get existing deposit data registry - depositDataRegistry = IDepositDataRegistry(_depositDataRegistry); - - // Create a valid vault (version >= 2) - admin = makeAddr('admin'); - validVault = _getOrCreateVault( - VaultType.EthVault, - admin, - abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'metadataIpfsHash' - }) - ), - false - ); - (uint128 queuedShares, uint128 unclaimedAssets, , uint128 totalExitingAssets, ) = IEthVault( - validVault - ).getExitQueueData(); - exitingAssets = - totalExitingAssets + - IEthVault(validVault).convertToAssets(queuedShares) + - unclaimedAssets; - - invalidVault = makeAddr('invalidVault'); - nonAdmin = makeAddr('nonAdmin'); - newDepositDataManager = makeAddr('newDepositDataManager'); - - // Create or mock a vault with version < 2 - // For this test, we'll simulate a vault with version 1 - lowVersionVault = makeAddr('lowVersionVault'); - vm.mockCall( - lowVersionVault, - abi.encodeWithSelector(IVaultVersion.version.selector), - abi.encode(uint8(1)) - ); - - // Mock that lowVersionVault is registered in the vaults registry - vm.mockCall( - address(contracts.vaultsRegistry), - abi.encodeWithSelector(IVaultsRegistry.vaults.selector, lowVersionVault), - abi.encode(true) - ); - } - - function test_setDepositDataManager_failsForInvalidVault() public { - // Attempt to set deposit data manager for an invalid vault - vm.prank(admin); - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.setDepositDataManager(invalidVault, newDepositDataManager); - } - - function test_setDepositDataManager_failsForInvalidVaultVersion() public { - // Attempt to set deposit data manager for a vault with version < 2 - vm.prank(admin); - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.setDepositDataManager(lowVersionVault, newDepositDataManager); - } - - function test_setDepositDataManager_failsForNonAdmin() public { - // Attempt to set deposit data manager by a non-admin - vm.prank(nonAdmin); - vm.expectRevert(Errors.AccessDenied.selector); - depositDataRegistry.setDepositDataManager(validVault, newDepositDataManager); - } - - function test_setDepositDataManager_succeeds() public { - // Verify current deposit data manager before change - address initialManager = depositDataRegistry.getDepositDataManager(validVault); - - // Set new deposit data manager by the admin - vm.prank(admin); - - // Expect the DepositDataManagerUpdated event - vm.expectEmit(true, true, false, false); - emit IDepositDataRegistry.DepositDataManagerUpdated(validVault, newDepositDataManager); - - // Execute the function - _startSnapshotGas('DepositDataRegistryTest_test_setDepositDataManager_succeeds'); - depositDataRegistry.setDepositDataManager(validVault, newDepositDataManager); - _stopSnapshotGas(); - - // Verify deposit data manager was updated - address updatedManager = depositDataRegistry.getDepositDataManager(validVault); - assertEq(updatedManager, newDepositDataManager, 'Deposit data manager not updated correctly'); - assertNotEq(updatedManager, initialManager, 'Deposit data manager should have changed'); - } - - function test_setDepositDataRoot_failsForInvalidVault() public { - // Attempt to set deposit data root for an invalid vault - bytes32 newRoot = bytes32(uint256(1)); - vm.prank(admin); - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.setDepositDataRoot(invalidVault, newRoot); - } - - function test_setDepositDataRoot_failsForInvalidVaultVersion() public { - // Attempt to set deposit data root for a vault with version < 2 - bytes32 newRoot = bytes32(uint256(1)); - vm.prank(admin); - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.setDepositDataRoot(lowVersionVault, newRoot); - } - - function test_setDepositDataRoot_failsForNonDepositDataManager() public { - // Attempt to set deposit data root by a non-deposit data manager - bytes32 newRoot = bytes32(uint256(1)); - vm.prank(nonAdmin); - vm.expectRevert(Errors.AccessDenied.selector); - depositDataRegistry.setDepositDataRoot(validVault, newRoot); - } - - function test_setDepositDataRoot_failsForSameValue() public { - // First set initial deposit data root - bytes32 initialRoot = bytes32(uint256(1)); - - // Set the deposit data manager to admin for this test - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - - // Set initial deposit data root - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, initialRoot); - - // Attempt to set the same deposit data root - vm.prank(admin); - vm.expectRevert(Errors.ValueNotChanged.selector); - depositDataRegistry.setDepositDataRoot(validVault, initialRoot); - } - - function test_setDepositDataRoot_succeeds() public { - // Set up initial values - bytes32 newRoot = bytes32(uint256(1)); - - // Set the deposit data manager to admin for this test - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - - // Set deposit data root by the deposit data manager - vm.prank(admin); - - // Expect the DepositDataRootUpdated event - vm.expectEmit(true, false, false, false); - emit IDepositDataRegistry.DepositDataRootUpdated(validVault, newRoot); - - // Execute the function - _startSnapshotGas('DepositDataRegistryTest_test_setDepositDataRoot_succeeds'); - depositDataRegistry.setDepositDataRoot(validVault, newRoot); - _stopSnapshotGas(); - - // Verify deposit data root was updated - bytes32 updatedRoot = depositDataRegistry.depositDataRoots(validVault); - assertEq(updatedRoot, newRoot, 'Deposit data root not updated correctly'); - - // Verify deposit data index was reset to 0 - uint256 updatedIndex = depositDataRegistry.depositDataIndexes(validVault); - assertEq(updatedIndex, 0, 'Deposit data index not reset to 0'); - } - - function test_updateVaultState_succeeds() public { - // Prepare the vault for testing - _collateralizeEthVault(validVault); - - // Generate harvest params with some reward - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - validVault, - int160(1 ether), // totalReward - simulating 1 ETH of rewards - uint160(0) // unlockedMevReward - no MEV rewards for this test - ); - - // Record the initial state of the vault - uint256 initialTotalAssets = IEthVault(validVault).totalAssets(); - - // Execute the updateVaultState function - _startSnapshotGas('DepositDataRegistryTest_test_updateVaultState_succeeds'); - depositDataRegistry.updateVaultState(validVault, harvestParams); - _stopSnapshotGas(); - - // Verify that the vault state was updated - uint256 updatedTotalAssets = IEthVault(validVault).totalAssets(); - - // The total assets should have increased by the reward amount - assertGt( - updatedTotalAssets, - initialTotalAssets, - 'Vault total assets should have increased after state update' - ); - - // We can also verify that the vault is no longer requiring a state update - bool stateUpdateRequired = IEthVault(validVault).isStateUpdateRequired(); - assertFalse( - stateUpdateRequired, - 'Vault should not require state update after calling updateVaultState' - ); - } - - function test_registerValidator_failsForInvalidVault() public { - // Create validator approval params - uint256[] memory deposits = new uint256[](1); - deposits[0] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - _stopOracleImpersonate(address(contracts.keeper)); - - bytes32[] memory proof = new bytes32[](0); - - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.registerValidator(invalidVault, keeperParams, proof); - } - function test_registerValidator_failsForInvalidVaultVersion() public { - // Create validator approval params - uint256[] memory deposits = new uint256[](1); - deposits[0] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - lowVersionVault, - 'ipfsHash', - deposits, - true - ); - _stopOracleImpersonate(address(contracts.keeper)); - - bytes32[] memory proof = new bytes32[](0); - - // Attempt to register validator for a vault with version < 2 - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.registerValidator(lowVersionVault, keeperParams, proof); - } - - function test_registerValidator_failsWithInvalidProof() public { - vm.deal(validVault, exitingAssets + 32 ether); - - uint256[] memory deposits = new uint256[](1); - deposits[0] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - - // Create a deposit data root that doesn't match the validator - bytes32 depositDataRoot = keccak256('incorrect_root'); - - // Create an invalid proof that doesn't prove the validator is in the tree - bytes32[] memory invalidProof = new bytes32[](1); - invalidProof[0] = bytes32(uint256(123)); // Some random value - - // Set up the root - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - // Attempt to register with invalid proof - vm.expectRevert(Errors.InvalidProof.selector); - depositDataRegistry.registerValidator(validVault, keeperParams, invalidProof); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidator_succeedsWith0x01Validator() public { - vm.deal(validVault, exitingAssets + 32 ether); - - uint256 validatorIndex = 0; - uint256[] memory deposits = new uint256[](1); - deposits[0] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - - // Create root - bytes32 depositDataRoot = keccak256( - bytes.concat(keccak256(abi.encode(keeperParams.validators, validatorIndex))) - ); - bytes32[] memory proof = new bytes32[](0); - - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - _startSnapshotGas('DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator'); - depositDataRegistry.registerValidator(validVault, keeperParams, proof); - _stopSnapshotGas(); - - _stopOracleImpersonate(address(contracts.keeper)); - - // Verify the validator index was incremented - assertEq( - depositDataRegistry.depositDataIndexes(validVault), - 1, - 'Validator index should be incremented' - ); - } - - function test_registerValidator_succeedsWith0x02Validator() public { - vm.deal(validVault, exitingAssets + 67 ether); - - uint256 validatorIndex = 0; - uint256[] memory deposits = new uint256[](1); - deposits[0] = 67 ether / 1 gwei; // 67 ETH - - _startOracleImpersonate(address(contracts.keeper)); - // Create a 0x02 validator (isV1Validator = false) - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - false // 0x02 validator - ); - - // Create root for the validator - bytes32 depositDataRoot = keccak256( - bytes.concat(keccak256(abi.encode(keeperParams.validators, validatorIndex))) - ); - - // Empty proof for a single validator - bytes32[] memory proof = new bytes32[](0); - - // Set up the root - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - // Register validator - _startSnapshotGas('DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator'); - depositDataRegistry.registerValidator(validVault, keeperParams, proof); - _stopSnapshotGas(); - - _stopOracleImpersonate(address(contracts.keeper)); - - // Verify the validator index was incremented - assertEq( - depositDataRegistry.depositDataIndexes(validVault), - 1, - 'Validator index should be incremented' - ); - } - - function test_registerValidators_failsForInvalidVault() public { - // Create validator approval params - uint256[] memory deposits = new uint256[](2); - deposits[0] = 32 ether / 1 gwei; - deposits[1] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - - // Prepare proof params for multi-proof - uint256[] memory indexes = new uint256[](2); - indexes[0] = 0; - indexes[1] = 1; - bool[] memory proofFlags = new bool[](1); - proofFlags[0] = true; - bytes32[] memory proof = new bytes32[](1); - proof[0] = bytes32(uint256(1)); - - // Attempt to register validators for an invalid vault - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.registerValidators(invalidVault, keeperParams, indexes, proofFlags, proof); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidators_failsForInvalidVaultVersion() public { - // Create validator approval params - uint256[] memory deposits = new uint256[](2); - deposits[0] = 32 ether / 1 gwei; - deposits[1] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - lowVersionVault, - 'ipfsHash', - deposits, - true - ); - - // Prepare proof params for multi-proof - uint256[] memory indexes = new uint256[](2); - indexes[0] = 0; - indexes[1] = 1; - bool[] memory proofFlags = new bool[](1); - proofFlags[0] = true; - bytes32[] memory proof = new bytes32[](1); - proof[0] = bytes32(uint256(1)); - - // Attempt to register validators for a vault with version < 2 - vm.expectRevert(Errors.InvalidVault.selector); - depositDataRegistry.registerValidators( - lowVersionVault, - keeperParams, - indexes, - proofFlags, - proof - ); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidators_failsWithNoIndexes() public { - vm.deal(validVault, exitingAssets + 64 ether); - - // Create validator approval params - uint256[] memory deposits = new uint256[](2); - deposits[0] = 32 ether / 1 gwei; - deposits[1] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - - uint256[] memory indexes = new uint256[](0); - - bool[] memory proofFlags = new bool[](1); - proofFlags[0] = true; - bytes32[] memory proof = new bytes32[](1); - proof[0] = bytes32(uint256(1)); - - // Create a deposit data root - bytes32 depositDataRoot = keccak256('root'); - - // Set up the root - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - // Attempt to register with invalid validators length - vm.expectRevert(Errors.InvalidValidators.selector); - depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidators_failWithInvalidProof() public { - vm.deal(validVault, exitingAssets + 64 ether); - - uint256[] memory deposits = new uint256[](2); - deposits[0] = 32 ether / 1 gwei; - deposits[1] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - - // Prepare valid proof params - uint256[] memory indexes = new uint256[](2); - indexes[0] = 0; - indexes[1] = 1; - - bool[] memory proofFlags = new bool[](2); - proofFlags[0] = true; - proofFlags[1] = true; - - // Create an invalid proof - bytes32[] memory invalidProof = new bytes32[](1); - invalidProof[0] = bytes32(uint256(123)); // Some random value - - // Create a deposit data root that doesn't match the validators - bytes32 depositDataRoot = keccak256('incorrect_root'); - - // Set up the root - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - // Attempt to register with invalid proof - vm.expectRevert(MerkleProof.MerkleProofInvalidMultiproof.selector); - depositDataRegistry.registerValidators( - validVault, - keeperParams, - indexes, - proofFlags, - invalidProof - ); - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidators_successWith0x01Validators() public { - vm.deal(validVault, exitingAssets + 64 ether); - - // Create validator approval params for 2 validators - uint256[] memory deposits = new uint256[](2); - deposits[0] = 32 ether / 1 gwei; - deposits[1] = 32 ether / 1 gwei; - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - true - ); - - // Setup for multi-proof verification - uint256 validatorIndex = 0; - - // Extract each validator's data (each 176 bytes long for 0x01 validator) - bytes memory validator1 = _extractBytes(keeperParams.validators, 0, 176); - bytes memory validator2 = _extractBytes(keeperParams.validators, 176, 176); - - // Create a Merkle tree with the correct format for validator registration - bytes32[] memory leaves = new bytes32[](2); - leaves[0] = keccak256(bytes.concat(keccak256(abi.encode(validator1, validatorIndex)))); - leaves[1] = keccak256(bytes.concat(keccak256(abi.encode(validator2, validatorIndex + 1)))); - - // Sort the leaves before calculating the Merkle root - if (leaves[0] > leaves[1]) { - (leaves[0], leaves[1]) = (leaves[1], leaves[0]); + ForkContracts private contracts; + IDepositDataRegistry private depositDataRegistry; + address private validVault; + address private invalidVault; + address private lowVersionVault; + address private admin; + address private nonAdmin; + address private newDepositDataManager; + uint256 private exitingAssets; + + function setUp() public { + contracts = _activateEthereumFork(); + + // Get existing deposit data registry + depositDataRegistry = IDepositDataRegistry(_depositDataRegistry); + + // Create a valid vault (version >= 2) + admin = makeAddr("admin"); + validVault = _getOrCreateVault( + VaultType.EthVault, + admin, + abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "metadataIpfsHash" + }) + ), + false + ); + (uint128 queuedShares, uint128 unclaimedAssets,, uint128 totalExitingAssets,) = + IEthVault(validVault).getExitQueueData(); + exitingAssets = totalExitingAssets + IEthVault(validVault).convertToAssets(queuedShares) + unclaimedAssets; + + invalidVault = makeAddr("invalidVault"); + nonAdmin = makeAddr("nonAdmin"); + newDepositDataManager = makeAddr("newDepositDataManager"); + + // Create or mock a vault with version < 2 + // For this test, we'll simulate a vault with version 1 + lowVersionVault = makeAddr("lowVersionVault"); + vm.mockCall(lowVersionVault, abi.encodeWithSelector(IVaultVersion.version.selector), abi.encode(uint8(1))); + + // Mock that lowVersionVault is registered in the vaults registry + vm.mockCall( + address(contracts.vaultsRegistry), + abi.encodeWithSelector(IVaultsRegistry.vaults.selector, lowVersionVault), + abi.encode(true) + ); } - // Calculate the Merkle root (for simplicity with only 2 leaves, it's just the hash of both leaves) - bytes32 depositDataRoot = keccak256(abi.encodePacked(leaves[0], leaves[1])); - - // Setup multi-proof parameters - uint256[] memory indexes = new uint256[](2); - indexes[0] = 0; - indexes[1] = 1; - - // For a tree with just 2 leaves and we're verifying both, we don't need a complex proof - bool[] memory proofFlags = new bool[](1); - proofFlags[0] = true; - - bytes32[] memory proof = new bytes32[](0); - - // Set up the root in the registry - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - // Register validators - _startSnapshotGas('DepositDataRegistryTest_test_registerValidators_successWith0x01Validators'); - depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); - _stopSnapshotGas(); - - // Verify the validator index was incremented by 2 - assertEq( - depositDataRegistry.depositDataIndexes(validVault), - 2, - 'Validator index should be incremented by 2' - ); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidators_successWith0x02Validators() public { - // Fund the vault with enough ETH for two validators with 45 ETH each - vm.deal(validVault, exitingAssets + 90 ether); - - // Create validator approval params for 2 validators with 45 ETH each - uint256[] memory deposits = new uint256[](2); - deposits[0] = 45 ether / 1 gwei; // 45 ETH for first validator - deposits[1] = 45 ether / 1 gwei; // 45 ETH for second validator - - _startOracleImpersonate(address(contracts.keeper)); - IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - validVault, - 'ipfsHash', - deposits, - false // 0x02 validators - ); - - // Setup for multi-proof verification - uint256 validatorIndex = 0; - - // Extract each validator's data (each 184 bytes long for 0x02 validator) - bytes memory validator1 = _extractBytes(keeperParams.validators, 0, 184); - bytes memory validator2 = _extractBytes(keeperParams.validators, 184, 184); - - // Create a Merkle tree with the correct format for validator registration - bytes32[] memory leaves = new bytes32[](2); - leaves[0] = keccak256(bytes.concat(keccak256(abi.encode(validator1, validatorIndex)))); - leaves[1] = keccak256(bytes.concat(keccak256(abi.encode(validator2, validatorIndex + 1)))); - - // Sort the leaves before calculating the Merkle root - if (leaves[0] > leaves[1]) { - (leaves[0], leaves[1]) = (leaves[1], leaves[0]); + function test_setDepositDataManager_failsForInvalidVault() public { + // Attempt to set deposit data manager for an invalid vault + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataManager(invalidVault, newDepositDataManager); } - // Calculate the Merkle root (for simplicity with only 2 leaves, it's just the hash of both leaves) - bytes32 depositDataRoot = keccak256(abi.encodePacked(leaves[0], leaves[1])); - - // Setup multi-proof parameters - uint256[] memory indexes = new uint256[](2); - indexes[0] = 0; - indexes[1] = 1; - - // For a tree with just 2 leaves and we're verifying both, we don't need a complex proof - bool[] memory proofFlags = new bool[](1); - proofFlags[0] = true; - - bytes32[] memory proof = new bytes32[](0); - - // Set up the root in the registry - vm.prank(admin); - depositDataRegistry.setDepositDataManager(validVault, admin); - vm.prank(admin); - depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - - // Register validators - _startSnapshotGas('DepositDataRegistryTest_test_registerValidators_successWith0x02Validators'); - depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); - _stopSnapshotGas(); - - // Verify the validator index was incremented by 2 - assertEq( - depositDataRegistry.depositDataIndexes(validVault), - 2, - 'Validator index should be incremented by 2' - ); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_migrate_failsForInvalidVault() public { - // Attempt to migrate for an invalid vault - vm.expectRevert(Errors.InvalidVault.selector); - vm.prank(invalidVault); - depositDataRegistry.migrate(bytes32(0), 0, admin); - } - - function test_migrate_failsForInvalidVaultVersion() public { - // Attempt to migrate for a vault with version < 2 - vm.expectRevert(Errors.InvalidVault.selector); - vm.prank(lowVersionVault); - depositDataRegistry.migrate(bytes32(0), 0, admin); - } - - function test_migrate_failsWhenAlreadyMigrated() public { - address foxVault = _getForkVault(VaultType.EthFoxVault); - - _upgradeVault(VaultType.EthFoxVault, foxVault); - if (contracts.keeper.isHarvestRequired(foxVault)) { - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(foxVault, 0, 0); - IVaultState(foxVault).updateState(harvestParams); + function test_setDepositDataManager_failsForInvalidVaultVersion() public { + // Attempt to set deposit data manager for a vault with version < 2 + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataManager(lowVersionVault, newDepositDataManager); } - // Attempt to migrate when the vault has already been migrated - vm.expectRevert(Errors.AccessDenied.selector); - vm.prank(foxVault); - depositDataRegistry.migrate(bytes32(0), 0, admin); - } + function test_setDepositDataManager_failsForNonAdmin() public { + // Attempt to set deposit data manager by a non-admin + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + depositDataRegistry.setDepositDataManager(validVault, newDepositDataManager); + } + + function test_setDepositDataManager_succeeds() public { + // Verify current deposit data manager before change + address initialManager = depositDataRegistry.getDepositDataManager(validVault); + + // Set new deposit data manager by the admin + vm.prank(admin); + + // Expect the DepositDataManagerUpdated event + vm.expectEmit(true, true, false, false); + emit IDepositDataRegistry.DepositDataManagerUpdated(validVault, newDepositDataManager); + + // Execute the function + _startSnapshotGas("DepositDataRegistryTest_test_setDepositDataManager_succeeds"); + depositDataRegistry.setDepositDataManager(validVault, newDepositDataManager); + _stopSnapshotGas(); + + // Verify deposit data manager was updated + address updatedManager = depositDataRegistry.getDepositDataManager(validVault); + assertEq(updatedManager, newDepositDataManager, "Deposit data manager not updated correctly"); + assertNotEq(updatedManager, initialManager, "Deposit data manager should have changed"); + } + + function test_setDepositDataRoot_failsForInvalidVault() public { + // Attempt to set deposit data root for an invalid vault + bytes32 newRoot = bytes32(uint256(1)); + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataRoot(invalidVault, newRoot); + } + + function test_setDepositDataRoot_failsForInvalidVaultVersion() public { + // Attempt to set deposit data root for a vault with version < 2 + bytes32 newRoot = bytes32(uint256(1)); + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.setDepositDataRoot(lowVersionVault, newRoot); + } + + function test_setDepositDataRoot_failsForNonDepositDataManager() public { + // Attempt to set deposit data root by a non-deposit data manager + bytes32 newRoot = bytes32(uint256(1)); + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + depositDataRegistry.setDepositDataRoot(validVault, newRoot); + } + + function test_setDepositDataRoot_failsForSameValue() public { + // First set initial deposit data root + bytes32 initialRoot = bytes32(uint256(1)); + + // Set the deposit data manager to admin for this test + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + + // Set initial deposit data root + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, initialRoot); + + // Attempt to set the same deposit data root + vm.prank(admin); + vm.expectRevert(Errors.ValueNotChanged.selector); + depositDataRegistry.setDepositDataRoot(validVault, initialRoot); + } + + function test_setDepositDataRoot_succeeds() public { + // Set up initial values + bytes32 newRoot = bytes32(uint256(1)); + + // Set the deposit data manager to admin for this test + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + + // Set deposit data root by the deposit data manager + vm.prank(admin); + + // Expect the DepositDataRootUpdated event + vm.expectEmit(true, false, false, false); + emit IDepositDataRegistry.DepositDataRootUpdated(validVault, newRoot); + + // Execute the function + _startSnapshotGas("DepositDataRegistryTest_test_setDepositDataRoot_succeeds"); + depositDataRegistry.setDepositDataRoot(validVault, newRoot); + _stopSnapshotGas(); + + // Verify deposit data root was updated + bytes32 updatedRoot = depositDataRegistry.depositDataRoots(validVault); + assertEq(updatedRoot, newRoot, "Deposit data root not updated correctly"); + + // Verify deposit data index was reset to 0 + uint256 updatedIndex = depositDataRegistry.depositDataIndexes(validVault); + assertEq(updatedIndex, 0, "Deposit data index not reset to 0"); + } + + function test_updateVaultState_succeeds() public { + // Prepare the vault for testing + _collateralizeEthVault(validVault); + + // Generate harvest params with some reward + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + validVault, + int160(1 ether), // totalReward - simulating 1 ETH of rewards + uint160(0) // unlockedMevReward - no MEV rewards for this test + ); + + // Record the initial state of the vault + uint256 initialTotalAssets = IEthVault(validVault).totalAssets(); + + // Execute the updateVaultState function + _startSnapshotGas("DepositDataRegistryTest_test_updateVaultState_succeeds"); + depositDataRegistry.updateVaultState(validVault, harvestParams); + _stopSnapshotGas(); + + // Verify that the vault state was updated + uint256 updatedTotalAssets = IEthVault(validVault).totalAssets(); + + // The total assets should have increased by the reward amount + assertGt(updatedTotalAssets, initialTotalAssets, "Vault total assets should have increased after state update"); + + // We can also verify that the vault is no longer requiring a state update + bool stateUpdateRequired = IEthVault(validVault).isStateUpdateRequired(); + assertFalse(stateUpdateRequired, "Vault should not require state update after calling updateVaultState"); + } + + function test_registerValidator_failsForInvalidVault() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + _stopOracleImpersonate(address(contracts.keeper)); + + bytes32[] memory proof = new bytes32[](0); + + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidator(invalidVault, keeperParams, proof); + } + + function test_registerValidator_failsForInvalidVaultVersion() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + lowVersionVault, + "ipfsHash", + deposits, + true + ); + _stopOracleImpersonate(address(contracts.keeper)); + + bytes32[] memory proof = new bytes32[](0); + + // Attempt to register validator for a vault with version < 2 + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidator(lowVersionVault, keeperParams, proof); + } + + function test_registerValidator_failsWithInvalidProof() public { + vm.deal(validVault, exitingAssets + 32 ether); + + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + + // Create a deposit data root that doesn't match the validator + bytes32 depositDataRoot = keccak256("incorrect_root"); + + // Create an invalid proof that doesn't prove the validator is in the tree + bytes32[] memory invalidProof = new bytes32[](1); + invalidProof[0] = bytes32(uint256(123)); // Some random value + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Attempt to register with invalid proof + vm.expectRevert(Errors.InvalidProof.selector); + depositDataRegistry.registerValidator(validVault, keeperParams, invalidProof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidator_succeedsWith0x01Validator() public { + vm.deal(validVault, exitingAssets + 32 ether); + + uint256 validatorIndex = 0; + uint256[] memory deposits = new uint256[](1); + deposits[0] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + + // Create root + bytes32 depositDataRoot = + keccak256(bytes.concat(keccak256(abi.encode(keeperParams.validators, validatorIndex)))); + bytes32[] memory proof = new bytes32[](0); - function test_migrate_succeeds() public { - address foxVault = _getForkVault(VaultType.EthFoxVault); + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); - address depositDataManagerBefore = IVaultValidatorsV1(foxVault).keysManager(); - bytes32 depositDataRootBefore = IVaultValidatorsV1(foxVault).validatorsRoot(); - uint256 depositDataIndexBefore = IVaultValidatorsV1(foxVault).validatorIndex(); + _startSnapshotGas("DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator"); + depositDataRegistry.registerValidator(validVault, keeperParams, proof); + _stopSnapshotGas(); - _upgradeVault(VaultType.EthFoxVault, foxVault); - if (contracts.keeper.isHarvestRequired(foxVault)) { - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(foxVault, 0, 0); - IVaultState(foxVault).updateState(harvestParams); + _stopOracleImpersonate(address(contracts.keeper)); + + // Verify the validator index was incremented + assertEq(depositDataRegistry.depositDataIndexes(validVault), 1, "Validator index should be incremented"); + } + + function test_registerValidator_succeedsWith0x02Validator() public { + vm.deal(validVault, exitingAssets + 67 ether); + + uint256 validatorIndex = 0; + uint256[] memory deposits = new uint256[](1); + deposits[0] = 67 ether / 1 gwei; // 67 ETH + + _startOracleImpersonate(address(contracts.keeper)); + // Create a 0x02 validator (isV1Validator = false) + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + "ipfsHash", + deposits, + false // 0x02 validator + ); + + // Create root for the validator + bytes32 depositDataRoot = + keccak256(bytes.concat(keccak256(abi.encode(keeperParams.validators, validatorIndex)))); + + // Empty proof for a single validator + bytes32[] memory proof = new bytes32[](0); + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Register validator + _startSnapshotGas("DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator"); + depositDataRegistry.registerValidator(validVault, keeperParams, proof); + _stopSnapshotGas(); + + _stopOracleImpersonate(address(contracts.keeper)); + + // Verify the validator index was incremented + assertEq(depositDataRegistry.depositDataIndexes(validVault), 1, "Validator index should be incremented"); + } + + function test_registerValidators_failsForInvalidVault() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + + // Prepare proof params for multi-proof + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); + + // Attempt to register validators for an invalid vault + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidators(invalidVault, keeperParams, indexes, proofFlags, proof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_failsForInvalidVaultVersion() public { + // Create validator approval params + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + lowVersionVault, + "ipfsHash", + deposits, + true + ); + + // Prepare proof params for multi-proof + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); + + // Attempt to register validators for a vault with version < 2 + vm.expectRevert(Errors.InvalidVault.selector); + depositDataRegistry.registerValidators(lowVersionVault, keeperParams, indexes, proofFlags, proof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_failsWithNoIndexes() public { + vm.deal(validVault, exitingAssets + 64 ether); + + // Create validator approval params + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + + uint256[] memory indexes = new uint256[](0); + + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); + + // Create a deposit data root + bytes32 depositDataRoot = keccak256("root"); + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Attempt to register with invalid validators length + vm.expectRevert(Errors.InvalidValidators.selector); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_failWithInvalidProof() public { + vm.deal(validVault, exitingAssets + 64 ether); + + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + + // Prepare valid proof params + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + + bool[] memory proofFlags = new bool[](2); + proofFlags[0] = true; + proofFlags[1] = true; + + // Create an invalid proof + bytes32[] memory invalidProof = new bytes32[](1); + invalidProof[0] = bytes32(uint256(123)); // Some random value + + // Create a deposit data root that doesn't match the validators + bytes32 depositDataRoot = keccak256("incorrect_root"); + + // Set up the root + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Attempt to register with invalid proof + vm.expectRevert(MerkleProof.MerkleProofInvalidMultiproof.selector); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, invalidProof); + _stopOracleImpersonate(address(contracts.keeper)); } - // Check the vault has been upgraded - assertEq( - IVaultValidators(foxVault).validatorsManager(), - address(depositDataRegistry), - 'Validators manager should be set to the deposit data registry after upgrade' - ); - assertEq(IVaultVersion(foxVault).version(), 2, 'Vault should have been upgraded to version 2'); - assertEq( - depositDataRegistry.getDepositDataManager(foxVault), - depositDataManagerBefore, - 'Deposit data manager should be the same after upgrade' - ); - assertEq( - depositDataRegistry.depositDataIndexes(foxVault), - depositDataIndexBefore, - 'Deposit data index should be the same after upgrade' - ); - assertEq( - depositDataRegistry.depositDataRoots(foxVault), - depositDataRootBefore, - 'Deposit data root should be the same after upgrade' - ); - } + function test_registerValidators_successWith0x01Validators() public { + vm.deal(validVault, exitingAssets + 64 ether); + + // Create validator approval params for 2 validators + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), address(contracts.validatorsRegistry), validVault, "ipfsHash", deposits, true + ); + + // Setup for multi-proof verification + uint256 validatorIndex = 0; + + // Extract each validator's data (each 176 bytes long for 0x01 validator) + bytes memory validator1 = _extractBytes(keeperParams.validators, 0, 176); + bytes memory validator2 = _extractBytes(keeperParams.validators, 176, 176); + + // Create a Merkle tree with the correct format for validator registration + bytes32[] memory leaves = new bytes32[](2); + leaves[0] = keccak256(bytes.concat(keccak256(abi.encode(validator1, validatorIndex)))); + leaves[1] = keccak256(bytes.concat(keccak256(abi.encode(validator2, validatorIndex + 1)))); + + // Sort the leaves before calculating the Merkle root + if (leaves[0] > leaves[1]) { + (leaves[0], leaves[1]) = (leaves[1], leaves[0]); + } + + // Calculate the Merkle root (for simplicity with only 2 leaves, it's just the hash of both leaves) + bytes32 depositDataRoot = keccak256(abi.encodePacked(leaves[0], leaves[1])); + + // Setup multi-proof parameters + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + + // For a tree with just 2 leaves and we're verifying both, we don't need a complex proof + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + bytes32[] memory proof = new bytes32[](0); + + // Set up the root in the registry + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Register validators + _startSnapshotGas("DepositDataRegistryTest_test_registerValidators_successWith0x01Validators"); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); + _stopSnapshotGas(); + + // Verify the validator index was incremented by 2 + assertEq(depositDataRegistry.depositDataIndexes(validVault), 2, "Validator index should be incremented by 2"); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_successWith0x02Validators() public { + // Fund the vault with enough ETH for two validators with 45 ETH each + vm.deal(validVault, exitingAssets + 90 ether); + + // Create validator approval params for 2 validators with 45 ETH each + uint256[] memory deposits = new uint256[](2); + deposits[0] = 45 ether / 1 gwei; // 45 ETH for first validator + deposits[1] = 45 ether / 1 gwei; // 45 ETH for second validator + + _startOracleImpersonate(address(contracts.keeper)); + IKeeperValidators.ApprovalParams memory keeperParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + validVault, + "ipfsHash", + deposits, + false // 0x02 validators + ); + + // Setup for multi-proof verification + uint256 validatorIndex = 0; + + // Extract each validator's data (each 184 bytes long for 0x02 validator) + bytes memory validator1 = _extractBytes(keeperParams.validators, 0, 184); + bytes memory validator2 = _extractBytes(keeperParams.validators, 184, 184); + + // Create a Merkle tree with the correct format for validator registration + bytes32[] memory leaves = new bytes32[](2); + leaves[0] = keccak256(bytes.concat(keccak256(abi.encode(validator1, validatorIndex)))); + leaves[1] = keccak256(bytes.concat(keccak256(abi.encode(validator2, validatorIndex + 1)))); + + // Sort the leaves before calculating the Merkle root + if (leaves[0] > leaves[1]) { + (leaves[0], leaves[1]) = (leaves[1], leaves[0]); + } + + // Calculate the Merkle root (for simplicity with only 2 leaves, it's just the hash of both leaves) + bytes32 depositDataRoot = keccak256(abi.encodePacked(leaves[0], leaves[1])); + + // Setup multi-proof parameters + uint256[] memory indexes = new uint256[](2); + indexes[0] = 0; + indexes[1] = 1; + + // For a tree with just 2 leaves and we're verifying both, we don't need a complex proof + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + bytes32[] memory proof = new bytes32[](0); + + // Set up the root in the registry + vm.prank(admin); + depositDataRegistry.setDepositDataManager(validVault, admin); + vm.prank(admin); + depositDataRegistry.setDepositDataRoot(validVault, depositDataRoot); + + // Register validators + _startSnapshotGas("DepositDataRegistryTest_test_registerValidators_successWith0x02Validators"); + depositDataRegistry.registerValidators(validVault, keeperParams, indexes, proofFlags, proof); + _stopSnapshotGas(); + + // Verify the validator index was incremented by 2 + assertEq(depositDataRegistry.depositDataIndexes(validVault), 2, "Validator index should be incremented by 2"); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_migrate_failsForInvalidVault() public { + // Attempt to migrate for an invalid vault + vm.expectRevert(Errors.InvalidVault.selector); + vm.prank(invalidVault); + depositDataRegistry.migrate(bytes32(0), 0, admin); + } + + function test_migrate_failsForInvalidVaultVersion() public { + // Attempt to migrate for a vault with version < 2 + vm.expectRevert(Errors.InvalidVault.selector); + vm.prank(lowVersionVault); + depositDataRegistry.migrate(bytes32(0), 0, admin); + } + + function test_migrate_failsWhenAlreadyMigrated() public { + address foxVault = _getForkVault(VaultType.EthFoxVault); + + _upgradeVault(VaultType.EthFoxVault, foxVault); + if (contracts.keeper.isHarvestRequired(foxVault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(foxVault, 0, 0); + IVaultState(foxVault).updateState(harvestParams); + } + + // Attempt to migrate when the vault has already been migrated + vm.expectRevert(Errors.AccessDenied.selector); + vm.prank(foxVault); + depositDataRegistry.migrate(bytes32(0), 0, admin); + } + + function test_migrate_succeeds() public { + address foxVault = _getForkVault(VaultType.EthFoxVault); + + address depositDataManagerBefore = IVaultValidatorsV1(foxVault).keysManager(); + bytes32 depositDataRootBefore = IVaultValidatorsV1(foxVault).validatorsRoot(); + uint256 depositDataIndexBefore = IVaultValidatorsV1(foxVault).validatorIndex(); + + _upgradeVault(VaultType.EthFoxVault, foxVault); + if (contracts.keeper.isHarvestRequired(foxVault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(foxVault, 0, 0); + IVaultState(foxVault).updateState(harvestParams); + } + + // Check the vault has been upgraded + assertEq( + IVaultValidators(foxVault).validatorsManager(), + address(depositDataRegistry), + "Validators manager should be set to the deposit data registry after upgrade" + ); + assertEq(IVaultVersion(foxVault).version(), 2, "Vault should have been upgraded to version 2"); + assertEq( + depositDataRegistry.getDepositDataManager(foxVault), + depositDataManagerBefore, + "Deposit data manager should be the same after upgrade" + ); + assertEq( + depositDataRegistry.depositDataIndexes(foxVault), + depositDataIndexBefore, + "Deposit data index should be the same after upgrade" + ); + assertEq( + depositDataRegistry.depositDataRoots(foxVault), + depositDataRootBefore, + "Deposit data root should be the same after upgrade" + ); + } } diff --git a/test/EthBlocklistErc20Vault.t.sol b/test/EthBlocklistErc20Vault.t.sol index 9d24ec51..8646e5dd 100644 --- a/test/EthBlocklistErc20Vault.t.sol +++ b/test/EthBlocklistErc20Vault.t.sol @@ -1,355 +1,350 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; -import {EthBlocklistErc20Vault} from '../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; +import {EthBlocklistErc20Vault} from "../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthBlocklistErc20VaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthBlocklistErc20Vault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public blocklistManager; - address public referrer = address(0); - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - blocklistManager = makeAddr('blocklistManager'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(other, 100 ether); - vm.deal(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthBlocklistErc20Vault, admin, initParams, false); - vault = EthBlocklistErc20Vault(payable(_vault)); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('EthBlocklistErc20Vault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 5); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_transfer() public { - uint256 amount = 1 ether; - - // Deposit ETH to get vault tokens - _depositEth(amount, sender, sender); - - // Transfer tokens - vm.prank(sender); - _startSnapshotGas('EthBlocklistErc20VaultTest_test_transfer'); - vault.transfer(other, amount); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.balanceOf(sender), 0); - assertEq(vault.balanceOf(other), amount); - } - - function test_cannotTransferToBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Deposit ETH to get vault tokens - _depositEth(amount, sender, sender); - - // Try to transfer to blocked user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotTransferFromBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Deposit ETH for both users - _depositEth(amount, sender, sender); - _depositEth(amount, other, other); - - // Block sender - vm.prank(blocklistManager); - vault.updateBlocklist(sender, true); - - // Try to transfer from blocked user to other - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotDepositFromBlockedSender() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit from blocked user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - IEthErc20Vault(vault).deposit{value: amount}(receiver, address(0)); - vm.stopPrank(); - } - - function test_cannotDepositToBlockedReceiver() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - IEthErc20Vault(vault).deposit{value: amount}(other, referrer); - vm.stopPrank(); - } - - function test_canDepositAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // Deposit as non-blocked user - _startSnapshotGas('EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser'); - _depositEth(amount, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.balanceOf(receiver), amount); - } - - function test_cannotDepositUsingReceiveAsBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - Address.sendValue(payable(vault), amount); - } - - function test_canDepositUsingReceiveAsNotBlockedUser() public { - uint256 amount = 1 ether; - - // Deposit as non-blocked user - _startSnapshotGas('EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser'); - vm.prank(sender); - Address.sendValue(payable(vault), amount); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.balanceOf(sender), amount); - } - - function test_cannotMintOsTokenFromBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Deposit ETH to get vault tokens - _depositEth(amount, sender, sender); - - // Set blocklist manager and block sender - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(sender, true); - - // Try to mint osToken from blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Deposit ETH to get vault tokens - _depositEth(amount, sender, sender); - - // Mint osToken as non-blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('EthBlocklistErc20VaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.EthBlocklistErc20Vault, admin, initParams, true); - _stopSnapshotGas(); - EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = blocklistVault.getExitQueueData(); - assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); - assertEq(blocklistVault.version(), 5); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.totalShares(), _securityDeposit); - assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(queuedShares, 0); - assertEq(totalTickets, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalExitingAssets, 0); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(blocklistVault.totalSupply(), _securityDeposit); - assertEq(blocklistVault.symbol(), 'SW-ETH-1'); - assertEq(blocklistVault.name(), 'SW ETH Vault'); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault( - VaultType.EthBlocklistErc20Vault, - admin, - initParams, - true - ); - EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); - - _depositToVault(address(blocklistVault), 95 ether, sender, sender); - _registerEthValidator(address(blocklistVault), 32 ether, true); - - vm.prank(sender); - blocklistVault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = blocklistVault.totalShares(); - uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(blocklistVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV4(address(blocklistVault)).queuedShares(); - uint256 senderBalanceBefore = blocklistVault.getShares(sender); - - assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); - assertEq(blocklistVault.version(), 4); - - _startSnapshotGas('EthBlocklistErc20VaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthBlocklistErc20Vault, address(blocklistVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); - assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistErc20Vault')); - assertEq(blocklistVault.version(), 5); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(queuedShares, queuedSharesBefore); - assertEq(blocklistVault.totalShares(), totalSharesBefore); - assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(blocklistVault.getShares(sender), senderBalanceBefore); - assertEq(blocklistVault.totalSupply(), totalSharesBefore); - assertEq(blocklistVault.symbol(), 'SW-ETH-1'); - assertEq(blocklistVault.name(), 'SW ETH Vault'); - } - - function _depositEth(uint256 amount, address from, address to) internal { - vm.prank(from); - IEthErc20Vault(vault).deposit{value: amount}(to, address(0)); - } + ForkContracts public contracts; + EthBlocklistErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + blocklistManager = makeAddr("blocklistManager"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthBlocklistErc20Vault, admin, initParams, false); + vault = EthBlocklistErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("EthBlocklistErc20Vault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_transfer() public { + uint256 amount = 1 ether; + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas("EthBlocklistErc20VaultTest_test_transfer"); + vault.transfer(other, amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(sender), 0); + assertEq(vault.balanceOf(other), amount); + } + + function test_cannotTransferToBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Try to transfer to blocked user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferFromBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit ETH for both users + _depositEth(amount, sender, sender); + _depositEth(amount, other, other); + + // Block sender + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to transfer from blocked user to other + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + IEthErc20Vault(vault).deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthErc20Vault(vault).deposit{value: amount}(other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas("EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser"); + _depositEth(amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(receiver), amount); + } + + function test_cannotDepositUsingReceiveAsBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_canDepositUsingReceiveAsNotBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas("EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser"); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(sender), amount); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault tokens + _depositEth(amount, sender, sender); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("EthBlocklistErc20VaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.EthBlocklistErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256("EthBlocklistErc20Vault")); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(queuedShares, 0); + assertEq(totalTickets, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalExitingAssets, 0); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.totalSupply(), _securityDeposit); + assertEq(blocklistVault.symbol(), "SW-ETH-1"); + assertEq(blocklistVault.name(), "SW ETH Vault"); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthBlocklistErc20Vault, admin, initParams, true); + EthBlocklistErc20Vault blocklistVault = EthBlocklistErc20Vault(payable(_vault)); + + _depositToVault(address(blocklistVault), 95 ether, sender, sender); + _registerEthValidator(address(blocklistVault), 32 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(blocklistVault)).queuedShares(); + uint256 senderBalanceBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256("EthBlocklistErc20Vault")); + assertEq(blocklistVault.version(), 4); + + _startSnapshotGas("EthBlocklistErc20VaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthBlocklistErc20Vault, address(blocklistVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256("EthBlocklistErc20Vault")); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(queuedShares, queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq(blocklistVault.totalSupply(), totalSharesBefore); + assertEq(blocklistVault.symbol(), "SW-ETH-1"); + assertEq(blocklistVault.name(), "SW ETH Vault"); + } + + function _depositEth(uint256 amount, address from, address to) internal { + vm.prank(from); + IEthErc20Vault(vault).deposit{value: amount}(to, address(0)); + } } diff --git a/test/EthBlocklistVault.t.sol b/test/EthBlocklistVault.t.sol index 2d2b4912..128b1967 100644 --- a/test/EthBlocklistVault.t.sol +++ b/test/EthBlocklistVault.t.sol @@ -1,305 +1,301 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {EthBlocklistVault} from '../contracts/vaults/ethereum/EthBlocklistVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {EthBlocklistVault} from "../contracts/vaults/ethereum/EthBlocklistVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthBlocklistVaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthBlocklistVault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public blocklistManager; - address public referrer = address(0); - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - blocklistManager = makeAddr('blocklistManager'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(other, 100 ether); - vm.deal(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthBlocklistVault, admin, initParams, false); - vault = EthBlocklistVault(payable(_vault)); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('EthBlocklistVault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 5); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_cannotDepositFromBlockedSender() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit from blocked user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - IEthVault(vault).deposit{value: amount}(receiver, address(0)); - vm.stopPrank(); - } - - function test_cannotDepositToBlockedReceiver() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - IEthVault(vault).deposit{value: amount}(other, referrer); - vm.stopPrank(); - } - - function test_canDepositAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // Deposit as non-blocked user - _startSnapshotGas('EthBlocklistVaultTest_test_canDepositAsNonBlockedUser'); - _depositToVault(address(vault), amount, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.getShares(receiver), amount); - } - - function test_cannotDepositUsingReceiveAsBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - Address.sendValue(payable(vault), amount); - } - - function test_cannotUpdateStateAndDepositFromBlockedSender() public { - _collateralizeVault( - address(contracts.keeper), - address(contracts.validatorsRegistry), - address(vault) - ); - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Try to deposit from blocked user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); - vm.stopPrank(); - } - - function test_canDepositUsingReceiveAsNotBlockedUser() public { - uint256 amount = 1 ether; - - // Deposit as non-blocked user - _startSnapshotGas('EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser'); - vm.prank(sender); - Address.sendValue(payable(vault), amount); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.getShares(sender), amount); - } - - function test_cannotMintOsTokenFromBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - - // Set blocklist manager and block sender - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(sender, true); - - // Try to mint osToken from blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Mint osToken as non-blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('EthBlocklistVaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.EthBlocklistVault, admin, initParams, true); - _stopSnapshotGas(); - EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = blocklistVault.getExitQueueData(); - assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); - assertEq(blocklistVault.version(), 5); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.totalShares(), _securityDeposit); - assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(queuedShares, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.EthBlocklistVault, admin, initParams, true); - EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); - - _depositToVault(address(blocklistVault), 95 ether, sender, sender); - _registerEthValidator(address(blocklistVault), 32 ether, true); - - vm.prank(sender); - blocklistVault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = blocklistVault.totalShares(); - uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(blocklistVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV4(address(blocklistVault)).queuedShares(); - uint256 senderSharesBefore = blocklistVault.getShares(sender); - - assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); - assertEq(blocklistVault.version(), 4); - - _startSnapshotGas('EthBlocklistVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthBlocklistVault, address(blocklistVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); - - assertEq(blocklistVault.vaultId(), keccak256('EthBlocklistVault')); - assertEq(blocklistVault.version(), 5); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(queuedShares, queuedSharesBefore); - assertEq(blocklistVault.totalShares(), totalSharesBefore); - assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(blocklistVault.getShares(sender), senderSharesBefore); - } + ForkContracts public contracts; + EthBlocklistVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + blocklistManager = makeAddr("blocklistManager"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthBlocklistVault, admin, initParams, false); + vault = EthBlocklistVault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("EthBlocklistVault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas("EthBlocklistVaultTest_test_canDepositAsNonBlockedUser"); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.getShares(receiver), amount); + } + + function test_cannotDepositUsingReceiveAsBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_cannotUpdateStateAndDepositFromBlockedSender() public { + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), address(vault)); + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_canDepositUsingReceiveAsNotBlockedUser() public { + uint256 amount = 1 ether; + + // Deposit as non-blocked user + _startSnapshotGas("EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser"); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.getShares(sender), amount); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("EthBlocklistVaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.EthBlocklistVault, admin, initParams, true); + _stopSnapshotGas(); + EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256("EthBlocklistVault")); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthBlocklistVault, admin, initParams, true); + EthBlocklistVault blocklistVault = EthBlocklistVault(payable(_vault)); + + _depositToVault(address(blocklistVault), 95 ether, sender, sender); + _registerEthValidator(address(blocklistVault), 32 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(blocklistVault)).queuedShares(); + uint256 senderSharesBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256("EthBlocklistVault")); + assertEq(blocklistVault.version(), 4); + + _startSnapshotGas("EthBlocklistVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthBlocklistVault, address(blocklistVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = blocklistVault.getExitQueueData(); + + assertEq(blocklistVault.vaultId(), keccak256("EthBlocklistVault")); + assertEq(blocklistVault.version(), 5); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(queuedShares, queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderSharesBefore); + } } diff --git a/test/EthErc20Vault.t.sol b/test/EthErc20Vault.t.sol index 9384ec94..0415201c 100644 --- a/test/EthErc20Vault.t.sol +++ b/test/EthErc20Vault.t.sol @@ -1,494 +1,471 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthErc20Vault} from "../contracts/vaults/ethereum/EthErc20Vault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthErc20VaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthErc20Vault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public referrer = address(0); - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(other, 100 ether); - vm.deal(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); - vault = EthErc20Vault(payable(_vault)); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('EthErc20VaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.EthErc20Vault, admin, initParams, false); - _stopSnapshotGas(); - EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = erc20Vault.getExitQueueData(); - assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); - assertEq(erc20Vault.version(), 5); - assertEq(erc20Vault.admin(), admin); - assertEq(erc20Vault.capacity(), 1000 ether); - assertEq(erc20Vault.feePercent(), 1000); - assertEq(erc20Vault.feeRecipient(), admin); - assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.totalShares(), _securityDeposit); - assertEq(erc20Vault.totalAssets(), _securityDeposit); - assertEq(erc20Vault.validatorsManagerNonce(), 0); - assertEq(erc20Vault.totalSupply(), _securityDeposit); - assertEq(erc20Vault.symbol(), 'SW-ETH-1'); - assertEq(erc20Vault.name(), 'SW ETH Vault'); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.EthErc20Vault, admin, initParams, false); - EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); - - // Deposit enough for validator (32 ETH minimum) - _depositToVault(address(erc20Vault), 40 ether, sender, sender); - - // Add funds directly to the vault to cover the validator - vm.deal(address(erc20Vault), address(erc20Vault).balance + 32 ether); - - _registerEthValidator(address(erc20Vault), 32 ether, true); - - vm.prank(sender); - erc20Vault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = erc20Vault.totalShares(); - uint256 totalAssetsBefore = erc20Vault.totalAssets(); - uint256 senderBalanceBefore = erc20Vault.getShares(sender); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(erc20Vault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV4(address(erc20Vault)).queuedShares(); - - assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); - assertEq(erc20Vault.version(), 4); - - _startSnapshotGas('EthErc20VaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthErc20Vault, address(erc20Vault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); - - assertEq(erc20Vault.vaultId(), keccak256('EthErc20Vault')); - assertEq(erc20Vault.version(), 5); - assertEq(erc20Vault.admin(), admin); - assertEq(erc20Vault.capacity(), 1000 ether); - assertEq(erc20Vault.feePercent(), 1000); - assertEq(erc20Vault.feeRecipient(), admin); - assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(queuedShares, queuedSharesBefore); - assertEq(erc20Vault.totalShares(), totalSharesBefore); - assertEq(erc20Vault.totalAssets(), totalAssetsBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq(erc20Vault.validatorsManagerNonce(), 0); - assertEq(erc20Vault.getShares(sender), senderBalanceBefore); - assertEq(erc20Vault.totalSupply(), totalSharesBefore); - assertEq(erc20Vault.symbol(), 'SW-ETH-1'); - assertEq(erc20Vault.name(), 'SW ETH Vault'); - } - - function test_deposit_emitsTransfer() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // When depositing, the vault will mint shares to the receiver - // So we should expect a Transfer event from address(0) to the receiver - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(address(0), sender, shares); - - // Call deposit directly - _startSnapshotGas('EthErc20VaultTest_test_deposit_emitsTransfer'); - vm.prank(sender); - vault.deposit{value: amount}(sender, referrer); - _stopSnapshotGas(); - } - - function test_enterExitQueue_emitsTransfer() public { - _collateralizeEthVault(address(vault)); - - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // First deposit - _depositEth(amount, sender, sender); - - // Expect Transfer event when entering exit queue - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(sender, address(vault), shares); - - // Enter exit queue - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - _startSnapshotGas('EthErc20VaultTest_test_enterExitQueue_emitsTransfer'); - uint256 positionTicket = vault.enterExitQueue(shares, sender); - _stopSnapshotGas(); - - // Process the exit queue (update state) - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Claim exited assets - vm.prank(sender); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - } - - function test_redeem_emitsEvent() public { - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createVault(VaultType.EthErc20Vault, admin, initParams, false); - EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); - - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // First deposit - _depositToVault(_vault, amount, sender, sender); - - // Expect Transfer event when entering exit queue - vm.expectEmit(true, true, true, false, _vault); - emit IERC20.Transfer(sender, address(0), shares); - - // Redeem - vm.prank(sender); - _startSnapshotGas('EthErc20VaultTest_test_redeem_emitsEvent'); - uint256 positionTicket = erc20Vault.enterExitQueue(shares, sender); - _stopSnapshotGas(); - - assertEq(positionTicket, type(uint256).max); - } - - function test_cannotTransferFromSharesWithLowLtv() public { - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - uint256 depositAmount = 10 ether; - - // Deposit ETH - _depositEth(depositAmount, sender, sender); - - // First mint the maximum amount of osToken - vm.prank(sender); - vault.mintOsToken(sender, type(uint256).max, referrer); - - // Approve other to transfer a significant amount - vm.prank(sender); - vault.approve(other, depositAmount / 4); - - // Try to transferFrom a significant amount - vm.prank(other); - _startSnapshotGas('EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv'); - vm.expectRevert(Errors.LowLtv.selector); - vault.transferFrom(sender, other, depositAmount / 4); // 25% of collateral - _stopSnapshotGas(); - } - - function test_canTransferFromSharesWithHighLtv() public { - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - uint256 depositAmount = 10 ether; - uint256 depositShares = vault.convertToShares(depositAmount); - - // Deposit ETH - _depositEth(depositAmount, sender, sender); - - // Mint a very small amount of osToken - vm.prank(sender); - vault.mintOsToken(sender, depositShares / 100, referrer); // Just 1% of deposit - - // Approve other to transfer shares - vm.prank(sender); - vault.approve(other, depositShares / 2); - - // Should be able to transferFrom most shares - vm.prank(other); - _startSnapshotGas('EthErc20VaultTest_test_canTransferFromSharesWithHighLtv'); - vault.transferFrom(sender, other, depositShares / 2); - _stopSnapshotGas(); - - // Verify the transfer succeeded - assertApproxEqAbs(vault.balanceOf(sender), depositShares - depositShares / 2, 1); - assertApproxEqAbs(vault.balanceOf(other), depositShares / 2, 1); - } - - function test_depositAndMintOsToken() public { - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - uint256 depositAmount = 10 ether; - uint256 osTokenShares = vault.convertToShares(depositAmount) / 2; // Use half for osToken - - // Call depositAndMintOsToken - vm.prank(sender); - _startSnapshotGas('EthErc20VaultTest_test_depositAndMintOsToken'); - uint256 mintedAssets = vault.depositAndMintOsToken{value: depositAmount}( - sender, - osTokenShares, - referrer - ); - _stopSnapshotGas(); - - // Check results - assertGt(mintedAssets, 0, 'Should have minted some osToken assets'); - assertEq( - vault.osTokenPositions(sender), - osTokenShares, - 'Should have minted expected osToken shares' - ); - assertEq( - vault.balanceOf(sender), - vault.convertToShares(depositAmount), - 'Should have received tokens for the deposit' - ); - } - - function test_updateStateAndDepositAndMintOsToken() public { - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Create harvest params - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - uint256 depositAmount = 5 ether; - uint256 osTokenShares = vault.convertToShares(depositAmount) / 2; // Use half for osToken - - // Call updateStateAndDepositAndMintOsToken - vm.prank(sender); - _startSnapshotGas('EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken'); - uint256 mintedAssets = vault.updateStateAndDepositAndMintOsToken{value: depositAmount}( - sender, - osTokenShares, - referrer, - harvestParams - ); - _stopSnapshotGas(); - - // Check results - assertGt(mintedAssets, 0, 'Should have minted some osToken assets'); - assertEq( - vault.osTokenPositions(sender), - osTokenShares, - 'Should have minted expected osToken shares' - ); - assertEq( - vault.balanceOf(sender), - vault.convertToShares(depositAmount), - 'Should have received tokens for the deposit' - ); - } - - function test_withdrawValidator_validatorsManager() public { - // 1. Set validators manager - address validatorsManager = makeAddr('validatorsManager'); - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // 2. First deposit enough ETH to register a validator (32 ETH minimum) - _depositEth(35 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(validatorsManager); - _startSnapshotGas('EthErc20VaultTest_test_withdrawValidator_validatorsManager'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_withdrawValidator_osTokenRedeemer() public { - // 1. Set osToken redeemer - address osTokenRedeemer = makeAddr('osTokenRedeemer'); - vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); - contracts.osTokenConfig.setRedeemer(osTokenRedeemer); - - uint256 withdrawFee = 0.1 ether; - vm.deal(osTokenRedeemer, withdrawFee); - - // 2. First deposit enough ETH to register a validator (32 ETH minimum) - _depositEth(35 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(osTokenRedeemer); - _startSnapshotGas('EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_withdrawValidator_unknown() public { - // 1. Set unknown address - address unknown = makeAddr('unknown'); - - uint256 withdrawFee = 0.1 ether; - vm.deal(unknown, withdrawFee); - - // 2. First deposit enough ETH to register a validator (32 ETH minimum) - _depositEth(35 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(unknown); - _startSnapshotGas('EthErc20VaultTest_test_withdrawValidator_unknown'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_depositViaReceiveFallback_emitsTransfer() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // When depositing via the receive fallback, the vault should emit a Transfer event - // from address(0) to the sender - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(address(0), sender, shares); - - // Use low-level call to trigger the receive function - _startSnapshotGas('EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer'); - vm.prank(sender); - (bool success, ) = address(vault).call{value: amount}(''); - _stopSnapshotGas(); - - require(success, 'ETH transfer failed'); - - // Verify sender received the correct number of tokens - assertEq(vault.balanceOf(sender), shares, 'Sender should have received tokens'); - } - - function test_updateExitQueue_emitsTransfer() public { - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // We need to deposit enough ETH to cover the validator registration (32 ETH) - uint256 amount = 40 ether; - - // Deposit ETH - _depositEth(amount, sender, sender); - - // Enter exit queue with 10 ETH - uint256 exitAmount = 10 ether; - uint256 exitShares = vault.convertToShares(exitAmount); - - vm.prank(sender); - vault.enterExitQueue(exitShares, sender); - - // Set some rewards to trigger state update and exit queue processing - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(1 ether), - 0 - ); - - // Update state which should process the exit queue - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(address(vault), address(0), exitShares); - _startSnapshotGas('EthErc20VaultTest_test_updateExitQueue_emitsTransfer'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify the exit queue was processed correctly - // The queue might not be fully processed in one update, so we'll check that progress was made - (uint128 queuedShares, , , , ) = vault.getExitQueueData(); - assertLt(queuedShares, exitShares, 'Exit queue should be at least partially processed'); - } - - // Helper function to deposit ETH to the vault - function _depositEth(uint256 amount, address from, address to) internal { - vm.prank(from); - IEthErc20Vault(vault).deposit{value: amount}(to, referrer); - } + ForkContracts public contracts; + EthErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("EthErc20VaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.EthErc20Vault, admin, initParams, false); + _stopSnapshotGas(); + EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = erc20Vault.getExitQueueData(); + assertEq(erc20Vault.vaultId(), keccak256("EthErc20Vault")); + assertEq(erc20Vault.version(), 5); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.totalShares(), _securityDeposit); + assertEq(erc20Vault.totalAssets(), _securityDeposit); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.totalSupply(), _securityDeposit); + assertEq(erc20Vault.symbol(), "SW-ETH-1"); + assertEq(erc20Vault.name(), "SW ETH Vault"); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthErc20Vault, admin, initParams, false); + EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + + // Deposit enough for validator (32 ETH minimum) + _depositToVault(address(erc20Vault), 40 ether, sender, sender); + + // Add funds directly to the vault to cover the validator + vm.deal(address(erc20Vault), address(erc20Vault).balance + 32 ether); + + _registerEthValidator(address(erc20Vault), 32 ether, true); + + vm.prank(sender); + erc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = erc20Vault.totalShares(); + uint256 totalAssetsBefore = erc20Vault.totalAssets(); + uint256 senderBalanceBefore = erc20Vault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(erc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(erc20Vault)).queuedShares(); + + assertEq(erc20Vault.vaultId(), keccak256("EthErc20Vault")); + assertEq(erc20Vault.version(), 4); + + _startSnapshotGas("EthErc20VaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthErc20Vault, address(erc20Vault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = erc20Vault.getExitQueueData(); + + assertEq(erc20Vault.vaultId(), keccak256("EthErc20Vault")); + assertEq(erc20Vault.version(), 5); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(queuedShares, queuedSharesBefore); + assertEq(erc20Vault.totalShares(), totalSharesBefore); + assertEq(erc20Vault.totalAssets(), totalAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.getShares(sender), senderBalanceBefore); + assertEq(erc20Vault.totalSupply(), totalSharesBefore); + assertEq(erc20Vault.symbol(), "SW-ETH-1"); + assertEq(erc20Vault.name(), "SW ETH Vault"); + } + + function test_deposit_emitsTransfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // When depositing, the vault will mint shares to the receiver + // So we should expect a Transfer event from address(0) to the receiver + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Call deposit directly + _startSnapshotGas("EthErc20VaultTest_test_deposit_emitsTransfer"); + vm.prank(sender); + vault.deposit{value: amount}(sender, referrer); + _stopSnapshotGas(); + } + + function test_enterExitQueue_emitsTransfer() public { + _collateralizeEthVault(address(vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositEth(amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(sender, address(vault), shares); + + // Enter exit queue + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas("EthErc20VaultTest_test_enterExitQueue_emitsTransfer"); + uint256 positionTicket = vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Claim exited assets + vm.prank(sender); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_redeem_emitsEvent() public { + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createVault(VaultType.EthErc20Vault, admin, initParams, false); + EthErc20Vault erc20Vault = EthErc20Vault(payable(_vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositToVault(_vault, amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, _vault); + emit IERC20.Transfer(sender, address(0), shares); + + // Redeem + vm.prank(sender); + _startSnapshotGas("EthErc20VaultTest_test_redeem_emitsEvent"); + uint256 positionTicket = erc20Vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + assertEq(positionTicket, type(uint256).max); + } + + function test_cannotTransferFromSharesWithLowLtv() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + uint256 depositAmount = 10 ether; + + // Deposit ETH + _depositEth(depositAmount, sender, sender); + + // First mint the maximum amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, type(uint256).max, referrer); + + // Approve other to transfer a significant amount + vm.prank(sender); + vault.approve(other, depositAmount / 4); + + // Try to transferFrom a significant amount + vm.prank(other); + _startSnapshotGas("EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv"); + vm.expectRevert(Errors.LowLtv.selector); + vault.transferFrom(sender, other, depositAmount / 4); // 25% of collateral + _stopSnapshotGas(); + } + + function test_canTransferFromSharesWithHighLtv() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + uint256 depositAmount = 10 ether; + uint256 depositShares = vault.convertToShares(depositAmount); + + // Deposit ETH + _depositEth(depositAmount, sender, sender); + + // Mint a very small amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, depositShares / 100, referrer); // Just 1% of deposit + + // Approve other to transfer shares + vm.prank(sender); + vault.approve(other, depositShares / 2); + + // Should be able to transferFrom most shares + vm.prank(other); + _startSnapshotGas("EthErc20VaultTest_test_canTransferFromSharesWithHighLtv"); + vault.transferFrom(sender, other, depositShares / 2); + _stopSnapshotGas(); + + // Verify the transfer succeeded + assertApproxEqAbs(vault.balanceOf(sender), depositShares - depositShares / 2, 1); + assertApproxEqAbs(vault.balanceOf(other), depositShares / 2, 1); + } + + function test_depositAndMintOsToken() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + uint256 depositAmount = 10 ether; + uint256 osTokenShares = vault.convertToShares(depositAmount) / 2; // Use half for osToken + + // Call depositAndMintOsToken + vm.prank(sender); + _startSnapshotGas("EthErc20VaultTest_test_depositAndMintOsToken"); + uint256 mintedAssets = vault.depositAndMintOsToken{value: depositAmount}(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check results + assertGt(mintedAssets, 0, "Should have minted some osToken assets"); + assertEq(vault.osTokenPositions(sender), osTokenShares, "Should have minted expected osToken shares"); + assertEq( + vault.balanceOf(sender), vault.convertToShares(depositAmount), "Should have received tokens for the deposit" + ); + } + + function test_updateStateAndDepositAndMintOsToken() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Create harvest params + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + uint256 depositAmount = 5 ether; + uint256 osTokenShares = vault.convertToShares(depositAmount) / 2; // Use half for osToken + + // Call updateStateAndDepositAndMintOsToken + vm.prank(sender); + _startSnapshotGas("EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken"); + uint256 mintedAssets = vault.updateStateAndDepositAndMintOsToken{value: depositAmount}( + sender, osTokenShares, referrer, harvestParams + ); + _stopSnapshotGas(); + + // Check results + assertGt(mintedAssets, 0, "Should have minted some osToken assets"); + assertEq(vault.osTokenPositions(sender), osTokenShares, "Should have minted expected osToken shares"); + assertEq( + vault.balanceOf(sender), vault.convertToShares(depositAmount), "Should have received tokens for the deposit" + ); + } + + function test_withdrawValidator_validatorsManager() public { + // 1. Set validators manager + address validatorsManager = makeAddr("validatorsManager"); + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 2. First deposit enough ETH to register a validator (32 ETH minimum) + _depositEth(35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas("EthErc20VaultTest_test_withdrawValidator_validatorsManager"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_withdrawValidator_osTokenRedeemer() public { + // 1. Set osToken redeemer + address osTokenRedeemer = makeAddr("osTokenRedeemer"); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // 2. First deposit enough ETH to register a validator (32 ETH minimum) + _depositEth(35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(osTokenRedeemer); + _startSnapshotGas("EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_withdrawValidator_unknown() public { + // 1. Set unknown address + address unknown = makeAddr("unknown"); + + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // 2. First deposit enough ETH to register a validator (32 ETH minimum) + _depositEth(35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(unknown); + _startSnapshotGas("EthErc20VaultTest_test_withdrawValidator_unknown"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_depositViaReceiveFallback_emitsTransfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // When depositing via the receive fallback, the vault should emit a Transfer event + // from address(0) to the sender + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Use low-level call to trigger the receive function + _startSnapshotGas("EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer"); + vm.prank(sender); + (bool success,) = address(vault).call{value: amount}(""); + _stopSnapshotGas(); + + require(success, "ETH transfer failed"); + + // Verify sender received the correct number of tokens + assertEq(vault.balanceOf(sender), shares, "Sender should have received tokens"); + } + + function test_updateExitQueue_emitsTransfer() public { + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // We need to deposit enough ETH to cover the validator registration (32 ETH) + uint256 amount = 40 ether; + + // Deposit ETH + _depositEth(amount, sender, sender); + + // Enter exit queue with 10 ETH + uint256 exitAmount = 10 ether; + uint256 exitShares = vault.convertToShares(exitAmount); + + vm.prank(sender); + vault.enterExitQueue(exitShares, sender); + + // Set some rewards to trigger state update and exit queue processing + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), int160(1 ether), 0); + + // Update state which should process the exit queue + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(vault), address(0), exitShares); + _startSnapshotGas("EthErc20VaultTest_test_updateExitQueue_emitsTransfer"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify the exit queue was processed correctly + // The queue might not be fully processed in one update, so we'll check that progress was made + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + assertLt(queuedShares, exitShares, "Exit queue should be at least partially processed"); + } + + // Helper function to deposit ETH to the vault + function _depositEth(uint256 amount, address from, address to) internal { + vm.prank(from); + IEthErc20Vault(vault).deposit{value: amount}(to, referrer); + } } diff --git a/test/EthFoxVault.t.sol b/test/EthFoxVault.t.sol index 80b96bfd..32c900c6 100644 --- a/test/EthFoxVault.t.sol +++ b/test/EthFoxVault.t.sol @@ -1,299 +1,295 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IEthFoxVault} from '../contracts/interfaces/IEthFoxVault.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {EthFoxVault} from '../contracts/vaults/ethereum/custom/EthFoxVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {IEthFoxVault} from "../contracts/interfaces/IEthFoxVault.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {EthFoxVault} from "../contracts/vaults/ethereum/custom/EthFoxVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract EthFoxVaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthFoxVault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public blocklistManager; - address public referrer = address(0); - uint256 exitingAssets; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - blocklistManager = makeAddr('blocklistManager'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(other, 100 ether); - vm.deal(admin, 100 ether); - - // Get or create the EthFoxVault - bytes memory initParams = abi.encode( - IEthFoxVault.EthFoxVaultInitParams({ - admin: admin, - ownMevEscrow: address(0), // Using shared MEV escrow - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthFoxVault, admin, initParams, false); - vault = EthFoxVault(payable(_vault)); - (uint128 queuedShares, , , ,) = vault.getExitQueueData(); - exitingAssets = vault.convertToAssets(queuedShares) + address(vault).balance; - } - - function test_deployFails() public { - // Deploy the vault directly - vm.deal(admin, 1 ether); - vm.prank(admin); - address impl = _getOrCreateVaultImpl(VaultType.EthFoxVault); - address _vault = address(new ERC1967Proxy(impl, '')); - - bytes memory initParams = abi.encode( - IEthFoxVault.EthFoxVaultInitParams({ - admin: admin, - ownMevEscrow: address(0), // Using shared MEV escrow - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - vm.expectRevert(Errors.UpgradeFailed.selector); - EthFoxVault(payable(_vault)).initialize(initParams); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('EthFoxVault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 2); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_cannotDepositFromBlockedSender() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit from blocked user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit{value: amount}(receiver, address(0)); - vm.stopPrank(); - } - - function test_cannotDepositToBlockedReceiver() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit{value: amount}(other, referrer); - vm.stopPrank(); - } - - function test_canDepositAsNonBlockedUser() public { - uint256 amount = 1 ether; - uint256 expectedShares = vault.convertToShares(amount); - - // Deposit as non-blocked user - _startSnapshotGas('EthFoxVaultTest_test_canDepositAsNonBlockedUser'); - _depositToVault(address(vault), amount, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(receiver), expectedShares, 1); - } - - function test_cannotDepositUsingReceiveAsBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - Address.sendValue(payable(vault), amount); - } - - function test_canDepositUsingReceiveAsNotBlockedUser() public { - uint256 amount = 1 ether; - uint256 expectedShares = vault.convertToShares(amount); - - // Deposit as non-blocked user - _startSnapshotGas('EthFoxVaultTest_test_canDepositUsingReceiveAsNotBlockedUser'); - vm.prank(sender); - Address.sendValue(payable(vault), amount); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(sender), expectedShares, 1); - } - - function test_cannotUpdateStateAndDepositFromBlockedSender() public { - _collateralizeVault( - address(contracts.keeper), - address(contracts.validatorsRegistry), - address(vault) - ); - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Try to deposit from blocked user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); - vm.stopPrank(); - } - - function test_ejectUser() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - (uint256 queuedSharesBefore, , , ,) = vault.getExitQueueData(); - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Verify user is not yet in blocklist - assertFalse(vault.blockedAccounts(sender)); - - // Eject user - _startSnapshotGas('EthFoxVaultTest_test_ejectUser'); - vm.prank(blocklistManager); - vault.ejectUser(sender); - _stopSnapshotGas(); - - // Verify user is now in blocklist - assertTrue(vault.blockedAccounts(sender)); - - // User's shares should be in exit queue - assertEq(vault.getShares(sender), 0); - (uint256 queuedShares, , , ,) = vault.getExitQueueData(); - assertApproxEqAbs(queuedShares, queuedSharesBefore + shares, 1); - } - - function test_ejectUserWithNoShares() public { - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - (uint256 queuedSharesBefore, , , ,) = vault.getExitQueueData(); - - // Eject user with no shares - _startSnapshotGas('EthFoxVaultTest_test_ejectUserWithNoShares'); - vm.prank(blocklistManager); - vault.ejectUser(sender); - _stopSnapshotGas(); - - // Verify user is in blocklist - assertTrue(vault.blockedAccounts(sender)); - - // No shares should be in exit queue - (uint256 queuedShares, , , ,) = vault.getExitQueueData(); - assertEq(queuedShares, queuedSharesBefore); - } - - function test_ejectUserFailsFromNonBlocklistManager() public { - uint256 amount = 1 ether; - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Try to eject user by non-blocklist manager - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.ejectUser(sender); - } - - function test_withdrawValidator_validatorsManager() public { - // 1. Set validators manager - address validatorsManager = makeAddr('validatorsManager'); - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // 2. First deposit and register a validator - _depositToVault(address(vault), 35 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(validatorsManager); - _startSnapshotGas('EthFoxVaultTest_test_withdrawValidator_validatorsManager'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_withdrawValidator_unknown() public { - // 1. Set unknown address - address unknown = makeAddr('unknown'); - - uint256 withdrawFee = 0.1 ether; - vm.deal(unknown, withdrawFee); - - // 2. First deposit and register a validator - _depositToVault(address(vault), 35 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(unknown); - _startSnapshotGas('EthFoxVaultTest_test_withdrawValidator_unknown'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } + ForkContracts public contracts; + EthFoxVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + uint256 exitingAssets; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + blocklistManager = makeAddr("blocklistManager"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // Get or create the EthFoxVault + bytes memory initParams = abi.encode( + IEthFoxVault.EthFoxVaultInitParams({ + admin: admin, + ownMevEscrow: address(0), // Using shared MEV escrow + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthFoxVault, admin, initParams, false); + vault = EthFoxVault(payable(_vault)); + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + exitingAssets = vault.convertToAssets(queuedShares) + address(vault).balance; + } + + function test_deployFails() public { + // Deploy the vault directly + vm.deal(admin, 1 ether); + vm.prank(admin); + address impl = _getOrCreateVaultImpl(VaultType.EthFoxVault); + address _vault = address(new ERC1967Proxy(impl, "")); + + bytes memory initParams = abi.encode( + IEthFoxVault.EthFoxVaultInitParams({ + admin: admin, + ownMevEscrow: address(0), // Using shared MEV escrow + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + vm.expectRevert(Errors.UpgradeFailed.selector); + EthFoxVault(payable(_vault)).initialize(initParams); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("EthFoxVault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 2); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Deposit as non-blocked user + _startSnapshotGas("EthFoxVaultTest_test_canDepositAsNonBlockedUser"); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), expectedShares, 1); + } + + function test_cannotDepositUsingReceiveAsBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_canDepositUsingReceiveAsNotBlockedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Deposit as non-blocked user + _startSnapshotGas("EthFoxVaultTest_test_canDepositUsingReceiveAsNotBlockedUser"); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(sender), expectedShares, 1); + } + + function test_cannotUpdateStateAndDepositFromBlockedSender() public { + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), address(vault)); + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to deposit from blocked user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_ejectUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + (uint256 queuedSharesBefore,,,,) = vault.getExitQueueData(); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Verify user is not yet in blocklist + assertFalse(vault.blockedAccounts(sender)); + + // Eject user + _startSnapshotGas("EthFoxVaultTest_test_ejectUser"); + vm.prank(blocklistManager); + vault.ejectUser(sender); + _stopSnapshotGas(); + + // Verify user is now in blocklist + assertTrue(vault.blockedAccounts(sender)); + + // User's shares should be in exit queue + assertEq(vault.getShares(sender), 0); + (uint256 queuedShares,,,,) = vault.getExitQueueData(); + assertApproxEqAbs(queuedShares, queuedSharesBefore + shares, 1); + } + + function test_ejectUserWithNoShares() public { + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + (uint256 queuedSharesBefore,,,,) = vault.getExitQueueData(); + + // Eject user with no shares + _startSnapshotGas("EthFoxVaultTest_test_ejectUserWithNoShares"); + vm.prank(blocklistManager); + vault.ejectUser(sender); + _stopSnapshotGas(); + + // Verify user is in blocklist + assertTrue(vault.blockedAccounts(sender)); + + // No shares should be in exit queue + (uint256 queuedShares,,,,) = vault.getExitQueueData(); + assertEq(queuedShares, queuedSharesBefore); + } + + function test_ejectUserFailsFromNonBlocklistManager() public { + uint256 amount = 1 ether; + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Try to eject user by non-blocklist manager + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.ejectUser(sender); + } + + function test_withdrawValidator_validatorsManager() public { + // 1. Set validators manager + address validatorsManager = makeAddr("validatorsManager"); + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 2. First deposit and register a validator + _depositToVault(address(vault), 35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas("EthFoxVaultTest_test_withdrawValidator_validatorsManager"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_withdrawValidator_unknown() public { + // 1. Set unknown address + address unknown = makeAddr("unknown"); + + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // 2. First deposit and register a validator + _depositToVault(address(vault), 35 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(unknown); + _startSnapshotGas("EthFoxVaultTest_test_withdrawValidator_unknown"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } } diff --git a/test/EthGenesisVault.t.sol b/test/EthGenesisVault.t.sol index 42dacd9b..0328d848 100644 --- a/test/EthGenesisVault.t.sol +++ b/test/EthGenesisVault.t.sol @@ -1,378 +1,335 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IEthGenesisVault} from '../contracts/interfaces/IEthGenesisVault.sol'; -import {IEthPoolEscrow} from '../contracts/interfaces/IEthPoolEscrow.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {EthGenesisVault} from '../contracts/vaults/ethereum/EthGenesisVault.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IEthGenesisVault} from "../contracts/interfaces/IEthGenesisVault.sol"; +import {IEthPoolEscrow} from "../contracts/interfaces/IEthPoolEscrow.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {EthGenesisVault} from "../contracts/vaults/ethereum/EthGenesisVault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthGenesisVaultTest is Test, EthHelpers { - ForkContracts public contracts; - address public admin; - address public user; - address public poolEscrow; - address public rewardEthToken; - bytes public initParams; - - function setUp() public { - // Activate Ethereum fork and get contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - - // Fund accounts with ETH for testing - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - - // Get pool escrow and reward token addresses from the helper - poolEscrow = _poolEscrow; - rewardEthToken = _rewardEthToken; - - initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - } - - function test_deployFails() public { - // Deploy the vault directly - vm.deal(admin, 1 ether); - vm.prank(admin); - address impl = _getOrCreateVaultImpl(VaultType.EthGenesisVault); - address _vault = address(new ERC1967Proxy(impl, '')); - - vm.expectRevert(Errors.UpgradeFailed.selector); - IEthGenesisVault(_vault).initialize(initParams); - } - - function test_upgradesCorrectly() public { - // Get or create a vault - address vaultAddr = _getForkVault(VaultType.EthGenesisVault); - EthGenesisVault existingVault = EthGenesisVault(payable(vaultAddr)); - - vm.deal( - vaultAddr, - IVaultStateV4(address(existingVault)).totalExitingAssets() + - existingVault.convertToAssets(IVaultStateV4(address(existingVault)).queuedShares()) + - vaultAddr.balance - ); - _depositToVault(address(existingVault), 40 ether, user, user); - _registerEthValidator(address(existingVault), 32 ether, true); - - vm.prank(user); - existingVault.enterExitQueue(10 ether, user); - - // Record initial state - uint256 initialTotalAssets = existingVault.totalAssets(); - uint256 initialTotalShares = existingVault.totalShares(); - uint256 senderBalanceBefore = existingVault.getShares(user); - uint256 initialCapacity = existingVault.capacity(); - uint256 initialFeePercent = existingVault.feePercent(); - address validatorsManager = existingVault.validatorsManager(); - address feeRecipient = existingVault.feeRecipient(); - address adminBefore = existingVault.admin(); - uint256 queuedSharesBefore = IVaultStateV4(address(existingVault)).queuedShares(); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(existingVault)).totalExitingAssets(); - - assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); - assertEq(existingVault.version(), 4); - - _startSnapshotGas('EthGenesisVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthGenesisVault, address(existingVault)); - _stopSnapshotGas(); - - (uint128 queuedSharesAfter, , , uint128 totalExitingAssetsAfter, ) = existingVault - .getExitQueueData(); - assertEq(existingVault.vaultId(), keccak256('EthGenesisVault')); - assertEq(existingVault.version(), 5); - assertEq(existingVault.admin(), adminBefore); - assertEq(existingVault.capacity(), initialCapacity); - assertEq(existingVault.feePercent(), initialFeePercent); - assertEq(existingVault.feeRecipient(), feeRecipient); - assertEq(existingVault.validatorsManager(), validatorsManager); - assertEq(queuedSharesAfter, queuedSharesBefore); - assertEq(existingVault.totalShares(), initialTotalShares); - assertEq(existingVault.totalAssets(), initialTotalAssets); - assertEq(totalExitingAssetsAfter, totalExitingAssetsBefore); - assertEq(existingVault.validatorsManagerNonce(), 0); - assertEq(existingVault.getShares(user), senderBalanceBefore); - } - - function test_cannotInitializeTwice() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Try to initialize it again - vm.prank(admin); - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize(initParams); - } - - function test_migrate_failsWithInvalidCaller() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Try to migrate with invalid caller (not rewardEthToken) - vm.prank(user); - vm.expectRevert(Errors.AccessDenied.selector); - vault.migrate(user, 1 ether); - } - - function test_migrate_failsWithInvalidPoolEscrowOwner() public { - // Get or create a vault with a different pool escrow ownership - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Mock the pool escrow owner to be different from the vault - vm.mockCall( - poolEscrow, - abi.encodeWithSelector(IEthPoolEscrow.owner.selector), - abi.encode(address(0x123)) - ); - - // Try to migrate - vm.prank(rewardEthToken); - vm.expectRevert(Errors.AccessDenied.selector); - vault.migrate(user, 1 ether); - } - - function test_migrate_failsWithNotHarvested() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Mock the pool escrow owner to be the vault - vm.mockCall( - poolEscrow, - abi.encodeWithSelector(IEthPoolEscrow.owner.selector), - abi.encode(address(vault)) - ); - - // Ensure vault needs harvesting - _setEthVaultReward(address(vault), 1 ether, 0); - _setEthVaultReward(address(vault), 2 ether, 0); - - vm.prank(rewardEthToken); - vm.expectRevert(Errors.NotHarvested.selector); - vault.migrate(user, 1 ether); - } - - function test_migrate_failsWithInvalidReceiver() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Mock the pool escrow owner to be the vault - vm.mockCall( - poolEscrow, - abi.encodeWithSelector(IEthPoolEscrow.owner.selector), - abi.encode(address(vault)) - ); - - vm.prank(rewardEthToken); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.migrate(address(0), 1 ether); - } - - function test_migrate_failsWithInvalidAssets() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Mock the pool escrow owner to be the vault - vm.mockCall( - poolEscrow, - abi.encodeWithSelector(IEthPoolEscrow.owner.selector), - abi.encode(address(vault)) - ); - - vm.prank(rewardEthToken); - vm.expectRevert(Errors.InvalidAssets.selector); - vault.migrate(user, 0); - } - - function test_migrate_works() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Ensure vault is harvested - _collateralizeEthVault(address(vault)); - - // Mock the pool escrow owner to be the vault - vm.mockCall( - poolEscrow, - abi.encodeWithSelector(IEthPoolEscrow.owner.selector), - abi.encode(address(vault)) - ); - - // Record initial state - uint256 initialTotalAssets = vault.totalAssets(); - uint256 initialTotalShares = vault.totalShares(); - - // Set up migration - uint256 migrateAmount = 10 ether; - uint256 osTokenShares = vault.osTokenPositions(user); - assertEq(osTokenShares, 0, 'OsToken position should be empty'); - - // Perform migration - _startSnapshotGas('EthGenesisVaultTest_test_migrate_works'); - vm.prank(rewardEthToken); - uint256 shares = vault.migrate(user, migrateAmount); - _stopSnapshotGas(); - - // Verify results - assertGt(shares, 0, 'Should have minted shares'); - assertEq(vault.getShares(user), shares, 'User should have received shares'); - assertEq( - vault.totalAssets(), - initialTotalAssets + migrateAmount, - 'Total assets should increase' - ); - assertEq(vault.totalShares(), initialTotalShares + shares, 'Total shares should increase'); - - // Verify OsToken position - osTokenShares = vault.osTokenPositions(user); - assertGt(osTokenShares, 0, 'OsToken position should be created'); - } - - function test_pullWithdrawals_claimEscrowAssets() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - // Add some ETH to the pool escrow - uint256 escrowAmount = 40 ether; - vm.deal(poolEscrow, poolEscrow.balance + escrowAmount); - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); - vm.deal( - address(vault), - address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets - ); - - // Record initial balances - uint256 vaultInitialBalance = address(vault).balance; - - // Register a validator to trigger _pullWithdrawals - _startSnapshotGas('GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets'); - _registerEthValidator(address(vault), 32 ether, false); - _stopSnapshotGas(); - - // Verify results - uint256 vaultFinalBalance = address(vault).balance; - uint256 escrowFinalBalance = poolEscrow.balance; - - assertGt( - vaultFinalBalance, - vaultInitialBalance, - 'Vault balance should increase from claiming escrow assets' - ); - - assertEq(escrowFinalBalance, 0, 'Pool escrow balance should be emptied'); - } - - function test_fallback_acceptsEtherFromPoolEscrow() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - uint256 initialBalance = address(vault).balance; - uint256 totalShares = vault.totalShares(); - uint256 amount = 3 ether; - - // Send ETH from pool escrow - vm.deal(poolEscrow, poolEscrow.balance + amount); - vm.prank(poolEscrow); - _startSnapshotGas('EthGenesisVaultTest_test_fallback_acceptsEtherFromPoolEscrow'); - (bool success, ) = address(vault).call{value: amount}(''); - _stopSnapshotGas(); - - assertTrue(success, 'ETH transfer should succeed'); - assertEq( - vault.totalShares(), - totalShares, - 'Total shares should not change after deposit from pool escrow' - ); - assertEq( - address(vault).balance, - initialBalance + amount, - 'Vault balance should increase by transfer amount' - ); - } - - function test_fallback_acceptsEtherFromUser() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - uint256 initialShares = vault.getShares(user); - uint256 amount = 2 ether; - - // Send ETH from user (should create shares) - _startSnapshotGas('EthGenesisVaultTest_test_fallback_acceptsEtherFromUser'); - vm.prank(user); - (bool success, ) = address(vault).call{value: amount}(''); - _stopSnapshotGas(); - - assertTrue(success, 'ETH transfer should succeed'); - assertGt(vault.getShares(user), initialShares, 'User shares should increase after deposit'); - } - - function test_claimsPoolEscrowAssets() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); - EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); - uint256 vaultAmount = address(vault).balance + - vault.convertToAssets(queuedShares) + - totalExitingAssets; - - uint256 depositAmount = 3 ether; - uint256 shares = vault.convertToShares(depositAmount); - _depositToVault(vaultAddr, depositAmount, user, user); - - vm.deal(vaultAddr, 0); - vm.deal(poolEscrow, vaultAmount + depositAmount); - - // Enter exit queue - vm.prank(user); - uint256 timestamp = vm.getBlockTimestamp(); - _startSnapshotGas('EthGenesisVaultTest_test_claimsPoolEscrowAssets'); - uint256 positionTicket = vault.enterExitQueue(shares, user); - _stopSnapshotGas(); - - // Process the exit queue (update state) - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Claim exited assets - vm.prank(user); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - } + ForkContracts public contracts; + address public admin; + address public user; + address public poolEscrow; + address public rewardEthToken; + bytes public initParams; + + function setUp() public { + // Activate Ethereum fork and get contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + + // Fund accounts with ETH for testing + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Get pool escrow and reward token addresses from the helper + poolEscrow = _poolEscrow; + rewardEthToken = _rewardEthToken; + + initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + } + + function test_deployFails() public { + // Deploy the vault directly + vm.deal(admin, 1 ether); + vm.prank(admin); + address impl = _getOrCreateVaultImpl(VaultType.EthGenesisVault); + address _vault = address(new ERC1967Proxy(impl, "")); + + vm.expectRevert(Errors.UpgradeFailed.selector); + IEthGenesisVault(_vault).initialize(initParams); + } + + function test_upgradesCorrectly() public { + // Get or create a vault + address vaultAddr = _getForkVault(VaultType.EthGenesisVault); + EthGenesisVault existingVault = EthGenesisVault(payable(vaultAddr)); + + vm.deal( + vaultAddr, + IVaultStateV4(address(existingVault)).totalExitingAssets() + + existingVault.convertToAssets(IVaultStateV4(address(existingVault)).queuedShares()) + vaultAddr.balance + ); + _depositToVault(address(existingVault), 40 ether, user, user); + _registerEthValidator(address(existingVault), 32 ether, true); + + vm.prank(user); + existingVault.enterExitQueue(10 ether, user); + + // Record initial state + uint256 initialTotalAssets = existingVault.totalAssets(); + uint256 initialTotalShares = existingVault.totalShares(); + uint256 senderBalanceBefore = existingVault.getShares(user); + uint256 initialCapacity = existingVault.capacity(); + uint256 initialFeePercent = existingVault.feePercent(); + address validatorsManager = existingVault.validatorsManager(); + address feeRecipient = existingVault.feeRecipient(); + address adminBefore = existingVault.admin(); + uint256 queuedSharesBefore = IVaultStateV4(address(existingVault)).queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(existingVault)).totalExitingAssets(); + + assertEq(existingVault.vaultId(), keccak256("EthGenesisVault")); + assertEq(existingVault.version(), 4); + + _startSnapshotGas("EthGenesisVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthGenesisVault, address(existingVault)); + _stopSnapshotGas(); + + (uint128 queuedSharesAfter,,, uint128 totalExitingAssetsAfter,) = existingVault.getExitQueueData(); + assertEq(existingVault.vaultId(), keccak256("EthGenesisVault")); + assertEq(existingVault.version(), 5); + assertEq(existingVault.admin(), adminBefore); + assertEq(existingVault.capacity(), initialCapacity); + assertEq(existingVault.feePercent(), initialFeePercent); + assertEq(existingVault.feeRecipient(), feeRecipient); + assertEq(existingVault.validatorsManager(), validatorsManager); + assertEq(queuedSharesAfter, queuedSharesBefore); + assertEq(existingVault.totalShares(), initialTotalShares); + assertEq(existingVault.totalAssets(), initialTotalAssets); + assertEq(totalExitingAssetsAfter, totalExitingAssetsBefore); + assertEq(existingVault.validatorsManagerNonce(), 0); + assertEq(existingVault.getShares(user), senderBalanceBefore); + } + + function test_cannotInitializeTwice() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Try to initialize it again + vm.prank(admin); + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize(initParams); + } + + function test_migrate_failsWithInvalidCaller() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Try to migrate with invalid caller (not rewardEthToken) + vm.prank(user); + vm.expectRevert(Errors.AccessDenied.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithInvalidPoolEscrowOwner() public { + // Get or create a vault with a different pool escrow ownership + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be different from the vault + vm.mockCall(poolEscrow, abi.encodeWithSelector(IEthPoolEscrow.owner.selector), abi.encode(address(0x123))); + + // Try to migrate + vm.prank(rewardEthToken); + vm.expectRevert(Errors.AccessDenied.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithNotHarvested() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be the vault + vm.mockCall(poolEscrow, abi.encodeWithSelector(IEthPoolEscrow.owner.selector), abi.encode(address(vault))); + + // Ensure vault needs harvesting + _setEthVaultReward(address(vault), 1 ether, 0); + _setEthVaultReward(address(vault), 2 ether, 0); + + vm.prank(rewardEthToken); + vm.expectRevert(Errors.NotHarvested.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithInvalidReceiver() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be the vault + vm.mockCall(poolEscrow, abi.encodeWithSelector(IEthPoolEscrow.owner.selector), abi.encode(address(vault))); + + vm.prank(rewardEthToken); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.migrate(address(0), 1 ether); + } + + function test_migrate_failsWithInvalidAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Mock the pool escrow owner to be the vault + vm.mockCall(poolEscrow, abi.encodeWithSelector(IEthPoolEscrow.owner.selector), abi.encode(address(vault))); + + vm.prank(rewardEthToken); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.migrate(user, 0); + } + + function test_migrate_works() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Ensure vault is harvested + _collateralizeEthVault(address(vault)); + + // Mock the pool escrow owner to be the vault + vm.mockCall(poolEscrow, abi.encodeWithSelector(IEthPoolEscrow.owner.selector), abi.encode(address(vault))); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + + // Set up migration + uint256 migrateAmount = 10 ether; + uint256 osTokenShares = vault.osTokenPositions(user); + assertEq(osTokenShares, 0, "OsToken position should be empty"); + + // Perform migration + _startSnapshotGas("EthGenesisVaultTest_test_migrate_works"); + vm.prank(rewardEthToken); + uint256 shares = vault.migrate(user, migrateAmount); + _stopSnapshotGas(); + + // Verify results + assertGt(shares, 0, "Should have minted shares"); + assertEq(vault.getShares(user), shares, "User should have received shares"); + assertEq(vault.totalAssets(), initialTotalAssets + migrateAmount, "Total assets should increase"); + assertEq(vault.totalShares(), initialTotalShares + shares, "Total shares should increase"); + + // Verify OsToken position + osTokenShares = vault.osTokenPositions(user); + assertGt(osTokenShares, 0, "OsToken position should be created"); + } + + function test_pullWithdrawals_claimEscrowAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + // Add some ETH to the pool escrow + uint256 escrowAmount = 40 ether; + vm.deal(poolEscrow, poolEscrow.balance + escrowAmount); + (uint128 queuedShares,,, uint128 totalExitingAssets,) = vault.getExitQueueData(); + vm.deal(address(vault), address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets); + + // Record initial balances + uint256 vaultInitialBalance = address(vault).balance; + + // Register a validator to trigger _pullWithdrawals + _startSnapshotGas("GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets"); + _registerEthValidator(address(vault), 32 ether, false); + _stopSnapshotGas(); + + // Verify results + uint256 vaultFinalBalance = address(vault).balance; + uint256 escrowFinalBalance = poolEscrow.balance; + + assertGt(vaultFinalBalance, vaultInitialBalance, "Vault balance should increase from claiming escrow assets"); + + assertEq(escrowFinalBalance, 0, "Pool escrow balance should be emptied"); + } + + function test_fallback_acceptsEtherFromPoolEscrow() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + uint256 initialBalance = address(vault).balance; + uint256 totalShares = vault.totalShares(); + uint256 amount = 3 ether; + + // Send ETH from pool escrow + vm.deal(poolEscrow, poolEscrow.balance + amount); + vm.prank(poolEscrow); + _startSnapshotGas("EthGenesisVaultTest_test_fallback_acceptsEtherFromPoolEscrow"); + (bool success,) = address(vault).call{value: amount}(""); + _stopSnapshotGas(); + + assertTrue(success, "ETH transfer should succeed"); + assertEq(vault.totalShares(), totalShares, "Total shares should not change after deposit from pool escrow"); + assertEq(address(vault).balance, initialBalance + amount, "Vault balance should increase by transfer amount"); + } + + function test_fallback_acceptsEtherFromUser() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + uint256 initialShares = vault.getShares(user); + uint256 amount = 2 ether; + + // Send ETH from user (should create shares) + _startSnapshotGas("EthGenesisVaultTest_test_fallback_acceptsEtherFromUser"); + vm.prank(user); + (bool success,) = address(vault).call{value: amount}(""); + _stopSnapshotGas(); + + assertTrue(success, "ETH transfer should succeed"); + assertGt(vault.getShares(user), initialShares, "User shares should increase after deposit"); + } + + function test_claimsPoolEscrowAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.EthGenesisVault, admin, initParams, false); + EthGenesisVault vault = EthGenesisVault(payable(vaultAddr)); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = vault.getExitQueueData(); + uint256 vaultAmount = address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets; + + uint256 depositAmount = 3 ether; + uint256 shares = vault.convertToShares(depositAmount); + _depositToVault(vaultAddr, depositAmount, user, user); + + vm.deal(vaultAddr, 0); + vm.deal(poolEscrow, vaultAmount + depositAmount); + + // Enter exit queue + vm.prank(user); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas("EthGenesisVaultTest_test_claimsPoolEscrowAssets"); + uint256 positionTicket = vault.enterExitQueue(shares, user); + _stopSnapshotGas(); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Claim exited assets + vm.prank(user); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + } } diff --git a/test/EthOsTokenVaultEscrow.t.sol b/test/EthOsTokenVaultEscrow.t.sol index d5f14ef5..2470c7f0 100644 --- a/test/EthOsTokenVaultEscrow.t.sol +++ b/test/EthOsTokenVaultEscrow.t.sol @@ -1,1440 +1,1221 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; -import {IOsTokenVaultEscrow} from '../contracts/interfaces/IOsTokenVaultEscrow.sol'; -import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IOsTokenConfig} from "../contracts/interfaces/IOsTokenConfig.sol"; +import {IOsTokenVaultEscrow} from "../contracts/interfaces/IOsTokenVaultEscrow.sol"; +import {IOsTokenVaultController} from "../contracts/interfaces/IOsTokenVaultController.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IStrategiesRegistry { - function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; - function setStrategy(address strategy, bool enabled) external; + function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; + function setStrategy(address strategy, bool enabled) external; - function owner() external view returns (address); + function owner() external view returns (address); } contract EthOsTokenVaultEscrowTest is Test, EthHelpers { - IStrategiesRegistry private constant _strategiesRegistry = - IStrategiesRegistry(0x90b82E4b3aa385B4A02B7EBc1892a4BeD6B5c465); - - ForkContracts public contracts; - IEthVault public vault; - - address public user; - address public admin; - address public liquidator; - - function setUp() public { - // Activate Ethereum fork and get contracts - contracts = _activateEthereumFork(); - - // Setup addresses - user = makeAddr('user'); - admin = makeAddr('admin'); - liquidator = makeAddr('liquidator'); - - // Fund accounts - vm.deal(user, 100 ether); - vm.deal(admin, 100 ether); - vm.deal(liquidator, 100 ether); - - // Register user - vm.prank(_strategiesRegistry.owner()); - _strategiesRegistry.setStrategy(address(this), true); - _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(user)), user); - - // Create a vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = IEthVault(_vault); - - // Ensure the vault has enough ETH to process exit requests - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); - vm.deal( - address(vault), - address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets - ); - } - - function test_register_success() public { - // Arrange: First, collateralize the vault and deposit ETH - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - // Calculate osToken shares based on the vault's LTV ratio - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - // Mint osToken shares to the user - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - uint256 cumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); - - // Expect the PositionCreated event - vm.expectEmit(true, false, true, true); - emit IOsTokenVaultEscrow.PositionCreated( - address(vault), - 0, - user, - osTokenShares, - cumulativeFeePerShare - ); - - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Act & Assert: Verify the position was registered correctly - (address registeredOwner, uint256 exitedAssets, uint256 registeredShares) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - assertEq(registeredOwner, user, 'Incorrect owner registered'); - assertEq(exitedAssets, 0, 'Initial exited assets should be zero'); - assertEq(registeredShares, osTokenShares, 'Incorrect osToken shares registered'); - } - - function test_register_directCall() public { - // Arrange: Set up authenticator to allow calls - address authenticator = contracts.osTokenVaultEscrow.authenticator(); - - // We need to mock the authenticator to test direct calls - vm.mockCall( - authenticator, - abi.encodeWithSelector( - bytes4(keccak256('canRegister(address,address,uint256,uint256)')), - address(this), - user, - 123, - 100 - ), - abi.encode(true) - ); - - // Act: Call register directly - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_directCall'); - - // Expect the PositionCreated event - vm.expectEmit(true, true, true, true); - emit IOsTokenVaultEscrow.PositionCreated( - address(this), - 123, - user, - 100, - 1e18 // default cumulativeFeePerShare - ); - - contracts.osTokenVaultEscrow.register(user, 123, 100, 1e18); - _stopSnapshotGas(); - - // Assert: Verify position was created - (address owner, uint256 exitedAssets, uint256 shares) = contracts - .osTokenVaultEscrow - .getPosition(address(this), 123); - - assertEq(owner, user, 'Incorrect owner'); - assertEq(exitedAssets, 0, 'Initial exited assets should be zero'); - assertEq(shares, 100, 'Incorrect shares amount'); - - // Clear the mock - vm.clearMockedCalls(); - } - - function test_register_accessDenied() public { - // Arrange: Set up authenticator to deny calls - address authenticator = contracts.osTokenVaultEscrow.authenticator(); - - vm.mockCall( - authenticator, - abi.encodeWithSelector( - bytes4(keccak256('canRegister(address,address,uint256,uint256)')), - address(this), - user, - 123, - 100 - ), - abi.encode(false) - ); - - // Act & Assert: Expect revert on unauthorized call - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_accessDenied'); - vm.expectRevert(Errors.AccessDenied.selector); - contracts.osTokenVaultEscrow.register(user, 123, 100, 1e18); - _stopSnapshotGas(); - - // Clear the mock - vm.clearMockedCalls(); - } - - function test_register_zeroAddress() public { - // Arrange: Set up authenticator to allow calls - address authenticator = contracts.osTokenVaultEscrow.authenticator(); - - vm.mockCall( - authenticator, - abi.encodeWithSelector( - bytes4(keccak256('canRegister(address,address,uint256,uint256)')), - address(this), - address(0), - 123, - 100 - ), - abi.encode(true) - ); - - // Act & Assert: Expect revert on zero address - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_zeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - contracts.osTokenVaultEscrow.register(address(0), 123, 100, 1e18); - _stopSnapshotGas(); - - // Clear the mock - vm.clearMockedCalls(); - } - - function test_register_invalidShares() public { - // Arrange: Set up authenticator to allow calls - address authenticator = contracts.osTokenVaultEscrow.authenticator(); - - vm.mockCall( - authenticator, - abi.encodeWithSelector( - bytes4(keccak256('canRegister(address,address,uint256,uint256)')), - address(this), - user, - 123, - 0 - ), - abi.encode(true) - ); - - // Act & Assert: Expect revert on zero shares - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_invalidShares'); - vm.expectRevert(Errors.InvalidShares.selector); - contracts.osTokenVaultEscrow.register(user, 123, 0, 1e18); - _stopSnapshotGas(); - - // Clear the mock - vm.clearMockedCalls(); - } - - function test_register_fullFlow() public { - // This test demonstrates the full flow from deposit to registering with the escrow - - // 1. Collateralize the vault and make a deposit - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - // 2. Calculate and mint osToken shares - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - // 3. Transfer position to escrow (which calls register internally) - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_register_fullFlow'); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - _stopSnapshotGas(); - - // 4. Verify the position in escrow - (address owner, uint256 exitedAssets, uint256 shares) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - assertEq(owner, user, 'Incorrect owner'); - assertEq(exitedAssets, 0, 'Initial exited assets should be zero'); - assertEq(shares, osTokenShares, 'Incorrect shares amount'); - - // 5. Verify user's osToken position is now zero - uint256 userOsTokenPosition = vault.osTokenPositions(user); - assertEq(userOsTokenPosition, 0, 'User should have no remaining osTokens'); - } - - function test_processExitedAssets_success() public { - // Arrange: First, collateralize the vault and deposit ETH - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - // Calculate osToken shares based on the vault's LTV ratio - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - // Mint osToken shares to the user - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - // Transfer position to escrow (which calls register internally) - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Update vault state to process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Move time forward to allow claiming exited assets - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exitQueueIndex - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Expect the ExitedAssetsProcessed event - vm.expectEmit(true, true, true, false); - emit IOsTokenVaultEscrow.ExitedAssetsProcessed( - address(vault), - address(this), // msg.sender in the test context - exitPositionTicket, - 0 // We don't check exact value as it depends on conversion calculations - ); - - // Act: Process exited assets - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_success'); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - _stopSnapshotGas(); - - // Assert: Verify the position's exited assets were updated - (address owner, uint256 exitedAssets, uint256 shares) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - assertEq(owner, user, 'Owner should still be the same'); - assertGt(exitedAssets, 0, 'Exited assets should be greater than zero'); - assertGt(shares, osTokenShares, 'Shares should have accrued fees'); - } - - function test_processExitedAssets_invalidPosition() public { - // Arrange: Use a non-existent position - uint256 nonExistentTicket = 9999; - - // Act & Assert: Expect revert on invalid position - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_invalidPosition'); - vm.expectRevert(Errors.InvalidPosition.selector); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - nonExistentTicket, - vm.getBlockTimestamp(), - 0 - ); - _stopSnapshotGas(); - } - - function test_processExitedAssets_exitRequestNotProcessed() public { - // Arrange: Collateralize vault, deposit ETH, and set up position - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Act & Assert: Try to process before updateState and expect failure - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_exitRequestNotProcessed'); - vm.expectRevert(Errors.ExitRequestNotProcessed.selector); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - _stopSnapshotGas(); - } - - function test_processExitedAssets_claimExitedAssets() public { - // disable fee shares accrual - vm.prank(address(contracts.keeper)); - IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); - - // Arrange: Set up all the way to processing - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Process exit queue and advance time - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exitQueueIndex - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Expect the ExitedAssetsProcessed event - vm.expectEmit(true, true, true, false); - emit IOsTokenVaultEscrow.ExitedAssetsProcessed( - address(vault), - address(this), // msg.sender in the test context - exitPositionTicket, - 0 // We don't check exact value as it depends on conversion calculations - ); - - // Process exited assets - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Get position details - (, uint256 exitedAssets, ) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - - // Record user balance before claiming - uint256 userBalanceBefore = user.balance; - - // Act: Claim the exited assets - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_claimExitedAssets'); - vm.prank(user); - uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares - ); - _stopSnapshotGas(); - - // Assert: Verify assets were received and position was deleted - uint256 userBalanceAfter = user.balance; - assertEq( - userBalanceAfter - userBalanceBefore, - claimedAssets, - 'User should receive the claimed assets' - ); - assertEq(claimedAssets, exitedAssets, 'Claimed assets should equal exited assets'); - - // Verify position is deleted after full claim - (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - assertEq(ownerAfter, address(0), 'Position should be deleted after full claim'); - assertEq(exitedAssetsAfter, 0, 'Exited assets should be zero after full claim'); - assertEq(sharesAfter, 0, 'Shares should be zero after full claim'); - } - - function test_processExitedAssets_partialClaim() public { - // disable fee shares accrual - vm.prank(address(contracts.keeper)); - IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); - - // Arrange: Set up all the way to processing - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Process exit queue and advance time - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exitQueueIndex - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Expect the ExitedAssetsProcessed event - vm.expectEmit(true, true, true, false); - emit IOsTokenVaultEscrow.ExitedAssetsProcessed( - address(vault), - address(this), // msg.sender in the test context - exitPositionTicket, - 0 // We don't check exact value as it depends on conversion calculations - ); - - // Process exited assets - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Get position details - (address owner, uint256 exitedAssets, uint256 shares) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - // Record user balance before claiming - uint256 userBalanceBefore = user.balance; - - // Act: Claim half of the exited assets - uint256 halfShares = osTokenShares / 2; - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_processExitedAssets_partialClaim'); - vm.prank(user); - uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - halfShares - ); - _stopSnapshotGas(); - - // push down the stack - uint256 exitPositionTicket_ = exitPositionTicket; - - // Assert: Verify assets were received and position was updated - uint256 userBalanceAfter = user.balance; - assertEq( - userBalanceAfter - userBalanceBefore, - claimedAssets, - 'User should receive the claimed assets' - ); - - // Expected claimed assets should be proportional to shares claimed - uint256 expectedClaimedAssets = (exitedAssets * halfShares) / osTokenShares; - assertApproxEqAbs( - claimedAssets, - expectedClaimedAssets, - 1, - 'Claimed assets should be proportional to shares' - ); - - // Verify position is updated after partial claim - (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket_); - - assertEq(ownerAfter, owner, 'Owner should remain unchanged after partial claim'); - assertEq( - exitedAssetsAfter, - exitedAssets - claimedAssets, - 'Exited assets should be reduced by claimed amount' - ); - assertEq(sharesAfter, shares - halfShares, 'Shares should be reduced by claimed amount'); - } - - function test_claimExitedAssets_notOwner() public { - // Setup a position - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Try to claim as a different user - address otherUser = makeAddr('otherUser'); - _mintOsToken(otherUser, osTokenShares); // Give them the required osToken shares - - vm.startPrank(otherUser); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_notOwner'); - vm.expectRevert(Errors.AccessDenied.selector); - contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares - ); - _stopSnapshotGas(); - vm.stopPrank(); - } - - function test_claimExitedAssets_insufficientShares() public { - // Setup a position - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Mint extra shares to the user so they have enough to try claiming - _mintOsToken(user, osTokenShares * 2); - - // Try to claim more shares than available - vm.prank(user); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_insufficientShares'); - vm.expectRevert(Errors.InvalidShares.selector); - contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares * 2 // More than available - ); - _stopSnapshotGas(); - } - - function test_claimExitedAssets_nonExistentPosition() public { - // Try to claim from a non-existent position ticket - uint256 nonExistentTicket = 9999; - - _mintOsToken(user, 1 ether); // Give them some osToken shares - - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_nonExistentPosition'); - vm.expectRevert(); // Will revert with a custom error - contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), nonExistentTicket, 1 ether); - _stopSnapshotGas(); - } - - function test_claimExitedAssets_noProcessedAssets() public { - // Setup a position without processing exited assets - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Skip processing exit queue - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Try to claim without processed assets - vm.prank(user); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_noProcessedAssets'); - vm.expectRevert(Errors.ExitRequestNotProcessed.selector); - contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares - ); - _stopSnapshotGas(); - } - - function test_claimExitedAssets_withFeeAccrual() public { - // Set up a realistic APR for fee accrual - vm.prank(address(contracts.keeper)); - IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(868240800); // ~3% APR - - // Setup a position - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 initialCumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Fast forward time to accrue fees - vm.warp(timestamp + _exitingAssetsClaimDelay + 30 days); - - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Check if fees accrued - uint256 newCumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); - assertGt(newCumulativeFeePerShare, initialCumulativeFeePerShare, 'Fees should have accrued'); - - // Get position details before claiming - (, uint256 exitedAssets, uint256 positionShares) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - - // Shares should have increased due to fee accrual - assertGt(positionShares, osTokenShares, 'Position shares should have increased due to fees'); - - // Record user balance before claiming - uint256 userBalanceBefore = user.balance; - - // Claim assets - vm.prank(user); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_withFeeAccrual'); - uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares - ); - _stopSnapshotGas(); - - // Verify assets were received - uint256 userBalanceAfter = user.balance; - assertEq( - userBalanceAfter - userBalanceBefore, - claimedAssets, - 'User should receive the correct amount of assets' - ); - assertLt(claimedAssets, exitedAssets, 'Fee assets should not be included in the claim'); - } - - function test_claimExitedAssets_minimalAmount() public { - // disable fee shares accrual - vm.prank(address(contracts.keeper)); - IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); - - // Setup a position - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Get position details - (, uint256 exitedAssets, uint256 shares) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - - // Try to claim minimal shares (1 wei) - uint256 minimalShares = 1; - uint256 userBalanceBefore = user.balance; - - vm.prank(user); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_claimExitedAssets_minimalAmount'); - uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - minimalShares - ); - _stopSnapshotGas(); - - // Verify appropriate tiny amount was claimed - uint256 userBalanceAfter = user.balance; - assertEq( - userBalanceAfter - userBalanceBefore, - claimedAssets, - 'User should receive the claimed assets' - ); - - // Expected claimed assets for tiny share amount - uint256 expectedClaimedAssets = (exitedAssets * minimalShares) / shares; - assertEq( - claimedAssets, - expectedClaimedAssets, - 'Claimed assets should be proportional to shares' - ); - } - - // Helper function to setup a position in escrow - function _setupEscrowPosition() - internal - returns (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) - { - // Collateralize vault and deposit - _collateralizeEthVault(address(vault)); - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, user, user); - - // Calculate and mint osToken shares - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - // Transfer position to escrow - timestamp = vm.getBlockTimestamp(); - vm.prank(user); - exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - - return (exitPositionTicket, osTokenShares, timestamp); - } - - // Helper function to make a position unhealthy for liquidation - function _makePositionUnhealthy( - address _vault, - uint256 exitPositionTicket, - uint256 timestamp, - uint256 exitQueueIndex - ) internal { - // Process exited assets first - contracts.osTokenVaultEscrow.processExitedAssets( - _vault, - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Artificially manipulate the position to make it unhealthy - // We'll simulate a price drop by increasing the value of the osToken shares relative to exited assets - // This is done by setting a high average reward per second in the vault controller - vm.prank(address(contracts.keeper)); - contracts.osTokenVaultController.setAvgRewardPerSecond(4341204000); // 15 % - - // Advance time to allow the high APR to take effect - vm.warp(vm.getBlockTimestamp() + 365 days); - - // Force an update of the osToken state to reflect the new values - contracts.osTokenVaultController.updateState(); - - vm.prank(address(contracts.keeper)); - contracts.osTokenVaultController.setAvgRewardPerSecond(0); - } - - function test_liquidateOsToken_success() public { - // Setup a position in escrow - (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Make the position unhealthy for liquidation - _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); - - // Mint osToken shares to liquidator - _mintOsToken(liquidator, osTokenShares); - - // Get position details before liquidation - (address ownerBefore, uint256 exitedAssetsBefore, uint256 sharesBefore) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - // push down the stack - uint256 exitPositionTicket_ = exitPositionTicket; - - // Record liquidator balance before - uint256 liquidatorBalanceBefore = liquidator.balance; - - // Expected bonus based on the liquidation bonus from the contract - uint256 liqBonusPercent = contracts.osTokenVaultEscrow.liqBonusPercent(); - uint256 liquidationAssets = (exitedAssetsBefore * 1e18) / liqBonusPercent; - uint256 liquidationShares = contracts.osTokenVaultController.convertToShares(liquidationAssets); - - // Expect liquidation event - vm.expectEmit(true, true, true, false); - emit IOsTokenVaultEscrow.OsTokenLiquidated( - liquidator, - address(vault), - exitPositionTicket_, - liquidator, - liquidationShares, - exitedAssetsBefore - ); - - // Liquidate the position - vm.prank(liquidator); - _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_success'); - contracts.osTokenVaultEscrow.liquidateOsToken( - address(vault), - exitPositionTicket_, - liquidationShares, - liquidator - ); - _stopSnapshotGas(); - - // Get position details after liquidation - (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket_); - - // Verify liquidator received assets - uint256 liquidatorBalanceAfter = liquidator.balance; - assertApproxEqAbs( - liquidatorBalanceAfter - liquidatorBalanceBefore, - exitedAssetsBefore, - 2, - 'Liquidator did not receive correct amount of assets' - ); - - // Verify position was updated - assertEq(ownerAfter, ownerBefore, 'Owner should not change'); - assertApproxEqAbs(exitedAssetsAfter, 0, 2, 'Exited assets not correctly reduced'); - assertLt(sharesAfter, sharesBefore, 'Shares not correctly reduced'); - } - - function test_liquidateOsToken_invalidHealthFactor() public { - // Setup a position in escrow - (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Process exited assets without making the position unhealthy - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Mint osToken shares to liquidator - _mintOsToken(liquidator, osTokenShares); - - // Get liquidation amount - (, , uint256 sharesBefore) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - uint256 liquidationShares = sharesBefore / 2; - - // Try to liquidate a healthy position - vm.prank(liquidator); - _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_invalidHealthFactor'); - vm.expectRevert(Errors.InvalidHealthFactor.selector); - contracts.osTokenVaultEscrow.liquidateOsToken( - address(vault), - exitPositionTicket, - liquidationShares, - liquidator - ); - _stopSnapshotGas(); - } - - function test_liquidateOsToken_invalidPosition() public { - // Setup a non-existent position - uint256 nonExistentTicket = 9999; - - // Mint osToken shares to liquidator - _mintOsToken(liquidator, 1 ether); - - // Try to liquidate a non-existent position - vm.prank(liquidator); - _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_invalidPosition'); - vm.expectRevert(Errors.InvalidPosition.selector); - contracts.osTokenVaultEscrow.liquidateOsToken( - address(vault), - nonExistentTicket, - 1 ether, - liquidator - ); - _stopSnapshotGas(); - } - - function test_liquidateOsToken_zeroAddress() public { - // Setup a position in escrow - (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Make the position unhealthy for liquidation - _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); - - // Mint osToken shares to liquidator - _mintOsToken(liquidator, osTokenShares); - - // Try to liquidate to zero address - vm.prank(liquidator); - _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_zeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - contracts.osTokenVaultEscrow.liquidateOsToken( - address(vault), - exitPositionTicket, - osTokenShares, - address(0) - ); - _stopSnapshotGas(); - } - - function test_liquidateOsToken_invalidReceivedAssets() public { - // Setup a position in escrow - (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Make the position unhealthy for liquidation - _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); - - // Mint too many osToken shares to liquidator (much more than the position value) - uint256 excessiveShares = osTokenShares * 100; - _mintOsToken(liquidator, excessiveShares); - - // Try to liquidate with excessive shares - vm.prank(liquidator); - _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_invalidReceivedAssets'); - vm.expectRevert(Errors.InvalidReceivedAssets.selector); - contracts.osTokenVaultEscrow.liquidateOsToken( - address(vault), - exitPositionTicket, - excessiveShares, - liquidator - ); - _stopSnapshotGas(); - } - - function test_liquidateOsToken_partialLiquidation() public { - // Setup a position in escrow - (uint256 exitPositionTicket, , uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Make the position unhealthy for liquidation - _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); - - // Get position details before liquidation - (address ownerBefore, uint256 exitedAssetsBefore, uint256 sharesBefore) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - // Only liquidate half of the position - uint256 liqBonusPercent = contracts.osTokenVaultEscrow.liqBonusPercent(); - uint256 halfExitedAssets = exitedAssetsBefore / 2; - uint256 halfLiquidationAssets = (halfExitedAssets * 1e18) / liqBonusPercent; - uint256 halfLiquidationShares = contracts.osTokenVaultController.convertToShares( - halfLiquidationAssets - ); - - // Mint osToken shares to liquidator - _mintOsToken(liquidator, halfLiquidationShares); - - // Record liquidator balance before - uint256 liquidatorBalanceBefore = liquidator.balance; - - // Liquidate half the position - vm.prank(liquidator); - _startSnapshotGas('OsTokenLiquidationTest_test_liquidateOsToken_partialLiquidation'); - contracts.osTokenVaultEscrow.liquidateOsToken( - address(vault), - exitPositionTicket, - halfLiquidationShares, - liquidator - ); - _stopSnapshotGas(); - - // push down the stack - uint256 exitPositionTicket_ = exitPositionTicket; - - // Get position details after liquidation - (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket_); - - // Verify partial liquidation results - assertEq(ownerAfter, ownerBefore, 'Owner should not change'); - assertApproxEqAbs( - exitedAssetsAfter, - exitedAssetsBefore - halfExitedAssets, - 10, - 'Exited assets should be reduced by approximately half' - ); - assertLt(sharesAfter, sharesBefore, 'Shares should be reduced'); - - // Verify liquidator received assets - uint256 liquidatorBalanceAfter = liquidator.balance; - assertApproxEqAbs( - liquidatorBalanceAfter - liquidatorBalanceBefore, - halfExitedAssets, - 10, - 'Liquidator should receive approximately half of the exited assets' - ); - } - - function test_redeemOsToken_success() public { - vm.prank(address(contracts.keeper)); - contracts.osTokenVaultController.setAvgRewardPerSecond(0); - - // Setup a position in escrow - (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Process exited assets - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Get position details before redemption - (address ownerBefore, uint256 exitedAssetsBefore, ) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - uint256 expectedAssets = contracts.osTokenVaultController.convertToAssets(osTokenShares); - - // Mint osToken shares to the redeemer - address redeemer = makeAddr('redeemer'); - _mintOsToken(redeemer, osTokenShares); - - // set redeemer - vm.prank(Ownable(address(contracts.keeper)).owner()); - contracts.osTokenConfig.setRedeemer(redeemer); - - // Record redeemer balance before - address receiver = makeAddr('receiver'); - uint256 receiverBalanceBefore = receiver.balance; - - // Expect OsTokenRedeemed event - vm.expectEmit(true, true, true, true); - emit IOsTokenVaultEscrow.OsTokenRedeemed( - redeemer, - address(vault), - exitPositionTicket, - receiver, - osTokenShares, - expectedAssets - ); - - // Redeem the position - vm.prank(redeemer); - _startSnapshotGas('OsTokenLiquidationTest_test_redeemOsToken_success'); - contracts.osTokenVaultEscrow.redeemOsToken( - address(vault), - exitPositionTicket, - osTokenShares, - receiver - ); - _stopSnapshotGas(); - - // Verify receiver received assets - uint256 receiverBalanceAfter = receiver.balance; - assertEq( - receiverBalanceAfter - receiverBalanceBefore, - expectedAssets, - 'Receiver should receive all exited assets' - ); - - // push down the stack - uint256 exitPositionTicket_ = exitPositionTicket; - - // Get position details after redemption - (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket_); - - // Verify position was updated - assertEq(ownerAfter, ownerBefore, 'Owner should not change'); - assertEq( - exitedAssetsAfter, - exitedAssetsBefore - expectedAssets, - 'Exited assets should be zero' - ); - assertEq(sharesAfter, 0, 'Shares should be zero'); - } - - function test_redeemOsToken_notRedeemer() public { - // Setup a position in escrow - (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); - - // Process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); - - // Process exited assets - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - exitQueueIndex - ); - - // Mock the osTokenConfig.redeemer call to return an official redeemer address - address officialRedeemer = makeAddr('officialRedeemer'); - vm.mockCall( - address(contracts.osTokenConfig), - abi.encodeWithSelector(bytes4(keccak256('redeemer()'))), - abi.encode(officialRedeemer) - ); - - // Try to redeem from an unauthorized address - address unauthorizedCaller = makeAddr('unauthorizedCaller'); - _mintOsToken(unauthorizedCaller, osTokenShares); - - vm.prank(unauthorizedCaller); - _startSnapshotGas('OsTokenLiquidationTest_test_redeemOsToken_notRedeemer'); - vm.expectRevert(Errors.AccessDenied.selector); - contracts.osTokenVaultEscrow.redeemOsToken( - address(vault), - exitPositionTicket, - osTokenShares, - unauthorizedCaller - ); - _stopSnapshotGas(); - - // Clear the mock - vm.clearMockedCalls(); - } - - function test_updateLiqConfig_success() public { - // Get the owner of the escrow contract - address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); - - // Define new values - using conservative values - uint64 newLiqThresholdPercent = 5e17; // 50% - uint256 newLiqBonusPercent = 1.1e18; // 110% - - // Expect LiqConfigUpdated event - vm.expectEmit(true, true, false, false); - emit IOsTokenVaultEscrow.LiqConfigUpdated(newLiqThresholdPercent, newLiqBonusPercent); - - // Call updateLiqConfig as owner - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_success'); - contracts.osTokenVaultEscrow.updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent); - _stopSnapshotGas(); - - // Verify state was updated - assertEq( - contracts.osTokenVaultEscrow.liqThresholdPercent(), - newLiqThresholdPercent, - 'liqThresholdPercent not updated correctly' - ); - assertEq( - contracts.osTokenVaultEscrow.liqBonusPercent(), - newLiqBonusPercent, - 'liqBonusPercent not updated correctly' - ); - } - - function test_updateLiqConfig_onlyOwner() public { - // Define values - uint64 newLiqThresholdPercent = 5e17; // 50% - uint256 newLiqBonusPercent = 1.1e18; // 110% - - // Get a non-owner address - address nonOwner = makeAddr('nonOwner'); - - // Call updateLiqConfig as non-owner, should revert - vm.prank(nonOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_onlyOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - contracts.osTokenVaultEscrow.updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent); - _stopSnapshotGas(); - } - - function test_updateLiqConfig_invalidThreshold() public { - // Get the owner of the escrow contract - address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); - - // Test with threshold = 0 - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_zero'); - vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); - contracts.osTokenVaultEscrow.updateLiqConfig(0, 1.1e18); - _stopSnapshotGas(); - - // Test with threshold = 1e18 (100%) - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_max'); - vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); - contracts.osTokenVaultEscrow.updateLiqConfig(1e18, 1.1e18); - _stopSnapshotGas(); - } - - function test_updateLiqConfig_invalidBonus() public { - // Get the owner of the escrow contract - address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); - - // Test with bonus < _maxPercent (1e18) - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_low'); - vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); - contracts.osTokenVaultEscrow.updateLiqConfig(5e17, 0.9e18); - _stopSnapshotGas(); - - // Test with bonus too high (threshold * bonus > _maxPercent) - // If threshold = 90% (0.9e18) and bonus = 112% (1.12e18), - // then 0.9e18 * 1.12e18 / 1e18 = 1.008e18 > 1e18 - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_high'); - vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); - contracts.osTokenVaultEscrow.updateLiqConfig(9e17, 1.12e18); - _stopSnapshotGas(); - } - - function test_setAuthenticator_success() public { - // Get the owner of the escrow contract - address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); - - // Get current authenticator - address currentAuthenticator = contracts.osTokenVaultEscrow.authenticator(); - - // Create a new authenticator address - address newAuthenticator = makeAddr('newAuthenticator'); - - // Ensure it's different from the current one - if (newAuthenticator == currentAuthenticator) { - newAuthenticator = makeAddr('newAuthenticator2'); + IStrategiesRegistry private constant _strategiesRegistry = + IStrategiesRegistry(0x90b82E4b3aa385B4A02B7EBc1892a4BeD6B5c465); + + ForkContracts public contracts; + IEthVault public vault; + + address public user; + address public admin; + address public liquidator; + + function setUp() public { + // Activate Ethereum fork and get contracts + contracts = _activateEthereumFork(); + + // Setup addresses + user = makeAddr("user"); + admin = makeAddr("admin"); + liquidator = makeAddr("liquidator"); + + // Fund accounts + vm.deal(user, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(liquidator, 100 ether); + + // Register user + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(user)), user); + + // Create a vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = IEthVault(_vault); + + // Ensure the vault has enough ETH to process exit requests + (uint128 queuedShares,,, uint128 totalExitingAssets,) = vault.getExitQueueData(); + vm.deal(address(vault), address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets); } - // Expect AuthenticatorUpdated event - vm.expectEmit(true, false, false, false); - emit IOsTokenVaultEscrow.AuthenticatorUpdated(newAuthenticator); - - // Call setAuthenticator as owner - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_setAuthenticator_success'); - contracts.osTokenVaultEscrow.setAuthenticator(newAuthenticator); - _stopSnapshotGas(); - - // Verify state was updated - assertEq( - contracts.osTokenVaultEscrow.authenticator(), - newAuthenticator, - 'Authenticator not updated correctly' - ); - } - - function test_setAuthenticator_onlyOwner() public { - // Create a new authenticator address - address newAuthenticator = makeAddr('newAuthenticator'); - - // Get a non-owner address - address nonOwner = makeAddr('nonOwner'); - - // Call setAuthenticator as non-owner, should revert - vm.prank(nonOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_setAuthenticator_onlyOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - contracts.osTokenVaultEscrow.setAuthenticator(newAuthenticator); - _stopSnapshotGas(); - } - - function test_setAuthenticator_valueNotChanged() public { - // Get the owner of the escrow contract - address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); - - // Get current authenticator - address currentAuthenticator = contracts.osTokenVaultEscrow.authenticator(); - - // Call setAuthenticator with the same authenticator, should revert - vm.prank(escrowOwner); - _startSnapshotGas('EthOsTokenVaultEscrowTest_test_setAuthenticator_valueNotChanged'); - vm.expectRevert(Errors.ValueNotChanged.selector); - contracts.osTokenVaultEscrow.setAuthenticator(currentAuthenticator); - _stopSnapshotGas(); - } + function test_register_success() public { + // Arrange: First, collateralize the vault and deposit ETH + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // Calculate osToken shares based on the vault's LTV ratio + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + // Mint osToken shares to the user + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + uint256 cumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); + + // Expect the PositionCreated event + vm.expectEmit(true, false, true, true); + emit IOsTokenVaultEscrow.PositionCreated(address(vault), 0, user, osTokenShares, cumulativeFeePerShare); + + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Act & Assert: Verify the position was registered correctly + (address registeredOwner, uint256 exitedAssets, uint256 registeredShares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(registeredOwner, user, "Incorrect owner registered"); + assertEq(exitedAssets, 0, "Initial exited assets should be zero"); + assertEq(registeredShares, osTokenShares, "Incorrect osToken shares registered"); + } + + function test_register_directCall() public { + // Arrange: Set up authenticator to allow calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + // We need to mock the authenticator to test direct calls + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256("canRegister(address,address,uint256,uint256)")), address(this), user, 123, 100 + ), + abi.encode(true) + ); + + // Act: Call register directly + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_register_directCall"); + + // Expect the PositionCreated event + vm.expectEmit(true, true, true, true); + emit IOsTokenVaultEscrow.PositionCreated( + address(this), + 123, + user, + 100, + 1e18 // default cumulativeFeePerShare + ); + + contracts.osTokenVaultEscrow.register(user, 123, 100, 1e18); + _stopSnapshotGas(); + + // Assert: Verify position was created + (address owner, uint256 exitedAssets, uint256 shares) = + contracts.osTokenVaultEscrow.getPosition(address(this), 123); + + assertEq(owner, user, "Incorrect owner"); + assertEq(exitedAssets, 0, "Initial exited assets should be zero"); + assertEq(shares, 100, "Incorrect shares amount"); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_accessDenied() public { + // Arrange: Set up authenticator to deny calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256("canRegister(address,address,uint256,uint256)")), address(this), user, 123, 100 + ), + abi.encode(false) + ); + + // Act & Assert: Expect revert on unauthorized call + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_register_accessDenied"); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.osTokenVaultEscrow.register(user, 123, 100, 1e18); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_zeroAddress() public { + // Arrange: Set up authenticator to allow calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256("canRegister(address,address,uint256,uint256)")), address(this), address(0), 123, 100 + ), + abi.encode(true) + ); + + // Act & Assert: Expect revert on zero address + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_register_zeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + contracts.osTokenVaultEscrow.register(address(0), 123, 100, 1e18); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_invalidShares() public { + // Arrange: Set up authenticator to allow calls + address authenticator = contracts.osTokenVaultEscrow.authenticator(); + + vm.mockCall( + authenticator, + abi.encodeWithSelector( + bytes4(keccak256("canRegister(address,address,uint256,uint256)")), address(this), user, 123, 0 + ), + abi.encode(true) + ); + + // Act & Assert: Expect revert on zero shares + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_register_invalidShares"); + vm.expectRevert(Errors.InvalidShares.selector); + contracts.osTokenVaultEscrow.register(user, 123, 0, 1e18); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_register_fullFlow() public { + // This test demonstrates the full flow from deposit to registering with the escrow + + // 1. Collateralize the vault and make a deposit + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // 2. Calculate and mint osToken shares + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // 3. Transfer position to escrow (which calls register internally) + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_register_fullFlow"); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + + // 4. Verify the position in escrow + (address owner, uint256 exitedAssets, uint256 shares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(owner, user, "Incorrect owner"); + assertEq(exitedAssets, 0, "Initial exited assets should be zero"); + assertEq(shares, osTokenShares, "Incorrect shares amount"); + + // 5. Verify user's osToken position is now zero + uint256 userOsTokenPosition = vault.osTokenPositions(user); + assertEq(userOsTokenPosition, 0, "User should have no remaining osTokens"); + } + + function test_processExitedAssets_success() public { + // Arrange: First, collateralize the vault and deposit ETH + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // Calculate osToken shares based on the vault's LTV ratio + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + // Mint osToken shares to the user + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // Transfer position to escrow (which calls register internally) + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Update vault state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Move time forward to allow claiming exited assets + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exitQueueIndex + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Expect the ExitedAssetsProcessed event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.ExitedAssetsProcessed( + address(vault), + address(this), // msg.sender in the test context + exitPositionTicket, + 0 // We don't check exact value as it depends on conversion calculations + ); + + // Act: Process exited assets + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_processExitedAssets_success"); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + _stopSnapshotGas(); + + // Assert: Verify the position's exited assets were updated + (address owner, uint256 exitedAssets, uint256 shares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(owner, user, "Owner should still be the same"); + assertGt(exitedAssets, 0, "Exited assets should be greater than zero"); + assertGt(shares, osTokenShares, "Shares should have accrued fees"); + } + + function test_processExitedAssets_invalidPosition() public { + // Arrange: Use a non-existent position + uint256 nonExistentTicket = 9999; + + // Act & Assert: Expect revert on invalid position + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_processExitedAssets_invalidPosition"); + vm.expectRevert(Errors.InvalidPosition.selector); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), nonExistentTicket, vm.getBlockTimestamp(), 0); + _stopSnapshotGas(); + } + + function test_processExitedAssets_exitRequestNotProcessed() public { + // Arrange: Collateralize vault, deposit ETH, and set up position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Act & Assert: Try to process before updateState and expect failure + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_processExitedAssets_exitRequestNotProcessed"); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + _stopSnapshotGas(); + } + + function test_processExitedAssets_claimExitedAssets() public { + // disable fee shares accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); + + // Arrange: Set up all the way to processing + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue and advance time + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exitQueueIndex + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Expect the ExitedAssetsProcessed event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.ExitedAssetsProcessed( + address(vault), + address(this), // msg.sender in the test context + exitPositionTicket, + 0 // We don't check exact value as it depends on conversion calculations + ); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Get position details + (, uint256 exitedAssets,) = contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + // Record user balance before claiming + uint256 userBalanceBefore = user.balance; + + // Act: Claim the exited assets + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_processExitedAssets_claimExitedAssets"); + vm.prank(user); + uint256 claimedAssets = + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, osTokenShares); + _stopSnapshotGas(); + + // Assert: Verify assets were received and position was deleted + uint256 userBalanceAfter = user.balance; + assertEq(userBalanceAfter - userBalanceBefore, claimedAssets, "User should receive the claimed assets"); + assertEq(claimedAssets, exitedAssets, "Claimed assets should equal exited assets"); + + // Verify position is deleted after full claim + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(ownerAfter, address(0), "Position should be deleted after full claim"); + assertEq(exitedAssetsAfter, 0, "Exited assets should be zero after full claim"); + assertEq(sharesAfter, 0, "Shares should be zero after full claim"); + } + + function test_processExitedAssets_partialClaim() public { + // disable fee shares accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); + + // Arrange: Set up all the way to processing + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue and advance time + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exitQueueIndex + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Expect the ExitedAssetsProcessed event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.ExitedAssetsProcessed( + address(vault), + address(this), // msg.sender in the test context + exitPositionTicket, + 0 // We don't check exact value as it depends on conversion calculations + ); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Get position details + (address owner, uint256 exitedAssets, uint256 shares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + // Record user balance before claiming + uint256 userBalanceBefore = user.balance; + + // Act: Claim half of the exited assets + uint256 halfShares = osTokenShares / 2; + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_processExitedAssets_partialClaim"); + vm.prank(user); + uint256 claimedAssets = + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, halfShares); + _stopSnapshotGas(); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Assert: Verify assets were received and position was updated + uint256 userBalanceAfter = user.balance; + assertEq(userBalanceAfter - userBalanceBefore, claimedAssets, "User should receive the claimed assets"); + + // Expected claimed assets should be proportional to shares claimed + uint256 expectedClaimedAssets = (exitedAssets * halfShares) / osTokenShares; + assertApproxEqAbs(claimedAssets, expectedClaimedAssets, 1, "Claimed assets should be proportional to shares"); + + // Verify position is updated after partial claim + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket_); + + assertEq(ownerAfter, owner, "Owner should remain unchanged after partial claim"); + assertEq(exitedAssetsAfter, exitedAssets - claimedAssets, "Exited assets should be reduced by claimed amount"); + assertEq(sharesAfter, shares - halfShares, "Shares should be reduced by claimed amount"); + } + + function test_claimExitedAssets_notOwner() public { + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Try to claim as a different user + address otherUser = makeAddr("otherUser"); + _mintOsToken(otherUser, osTokenShares); // Give them the required osToken shares + + vm.startPrank(otherUser); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_claimExitedAssets_notOwner"); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, osTokenShares); + _stopSnapshotGas(); + vm.stopPrank(); + } + + function test_claimExitedAssets_insufficientShares() public { + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint extra shares to the user so they have enough to try claiming + _mintOsToken(user, osTokenShares * 2); + + // Try to claim more shares than available + vm.prank(user); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_claimExitedAssets_insufficientShares"); + vm.expectRevert(Errors.InvalidShares.selector); + contracts.osTokenVaultEscrow.claimExitedAssets( + address(vault), + exitPositionTicket, + osTokenShares * 2 // More than available + ); + _stopSnapshotGas(); + } + + function test_claimExitedAssets_nonExistentPosition() public { + // Try to claim from a non-existent position ticket + uint256 nonExistentTicket = 9999; + + _mintOsToken(user, 1 ether); // Give them some osToken shares + + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_claimExitedAssets_nonExistentPosition"); + vm.expectRevert(); // Will revert with a custom error + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), nonExistentTicket, 1 ether); + _stopSnapshotGas(); + } + + function test_claimExitedAssets_noProcessedAssets() public { + // Setup a position without processing exited assets + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Skip processing exit queue + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Try to claim without processed assets + vm.prank(user); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_claimExitedAssets_noProcessedAssets"); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, osTokenShares); + _stopSnapshotGas(); + } + + function test_claimExitedAssets_withFeeAccrual() public { + // Set up a realistic APR for fee accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(868240800); // ~3% APR + + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 initialCumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Fast forward time to accrue fees + vm.warp(timestamp + _exitingAssetsClaimDelay + 30 days); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Check if fees accrued + uint256 newCumulativeFeePerShare = contracts.osTokenVaultController.cumulativeFeePerShare(); + assertGt(newCumulativeFeePerShare, initialCumulativeFeePerShare, "Fees should have accrued"); + + // Get position details before claiming + (, uint256 exitedAssets, uint256 positionShares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + // Shares should have increased due to fee accrual + assertGt(positionShares, osTokenShares, "Position shares should have increased due to fees"); + + // Record user balance before claiming + uint256 userBalanceBefore = user.balance; + + // Claim assets + vm.prank(user); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_claimExitedAssets_withFeeAccrual"); + uint256 claimedAssets = + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, osTokenShares); + _stopSnapshotGas(); + + // Verify assets were received + uint256 userBalanceAfter = user.balance; + assertEq( + userBalanceAfter - userBalanceBefore, claimedAssets, "User should receive the correct amount of assets" + ); + assertLt(claimedAssets, exitedAssets, "Fee assets should not be included in the claim"); + } + + function test_claimExitedAssets_minimalAmount() public { + // disable fee shares accrual + vm.prank(address(contracts.keeper)); + IOsTokenVaultController(contracts.osTokenVaultController).setAvgRewardPerSecond(0); + + // Setup a position + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Get position details + (, uint256 exitedAssets, uint256 shares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + // Try to claim minimal shares (1 wei) + uint256 minimalShares = 1; + uint256 userBalanceBefore = user.balance; + + vm.prank(user); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_claimExitedAssets_minimalAmount"); + uint256 claimedAssets = + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, minimalShares); + _stopSnapshotGas(); + + // Verify appropriate tiny amount was claimed + uint256 userBalanceAfter = user.balance; + assertEq(userBalanceAfter - userBalanceBefore, claimedAssets, "User should receive the claimed assets"); + + // Expected claimed assets for tiny share amount + uint256 expectedClaimedAssets = (exitedAssets * minimalShares) / shares; + assertEq(claimedAssets, expectedClaimedAssets, "Claimed assets should be proportional to shares"); + } + + // Helper function to setup a position in escrow + function _setupEscrowPosition() + internal + returns (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) + { + // Collateralize vault and deposit + _collateralizeEthVault(address(vault)); + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, user, user); + + // Calculate and mint osToken shares + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // Transfer position to escrow + timestamp = vm.getBlockTimestamp(); + vm.prank(user); + exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + + return (exitPositionTicket, osTokenShares, timestamp); + } + + // Helper function to make a position unhealthy for liquidation + function _makePositionUnhealthy( + address _vault, + uint256 exitPositionTicket, + uint256 timestamp, + uint256 exitQueueIndex + ) internal { + // Process exited assets first + contracts.osTokenVaultEscrow.processExitedAssets(_vault, exitPositionTicket, timestamp, exitQueueIndex); + + // Artificially manipulate the position to make it unhealthy + // We'll simulate a price drop by increasing the value of the osToken shares relative to exited assets + // This is done by setting a high average reward per second in the vault controller + vm.prank(address(contracts.keeper)); + contracts.osTokenVaultController.setAvgRewardPerSecond(4341204000); // 15 % + + // Advance time to allow the high APR to take effect + vm.warp(vm.getBlockTimestamp() + 365 days); + + // Force an update of the osToken state to reflect the new values + contracts.osTokenVaultController.updateState(); + + vm.prank(address(contracts.keeper)); + contracts.osTokenVaultController.setAvgRewardPerSecond(0); + } + + function test_liquidateOsToken_success() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, osTokenShares); + + // Get position details before liquidation + (address ownerBefore, uint256 exitedAssetsBefore, uint256 sharesBefore) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Record liquidator balance before + uint256 liquidatorBalanceBefore = liquidator.balance; + + // Expected bonus based on the liquidation bonus from the contract + uint256 liqBonusPercent = contracts.osTokenVaultEscrow.liqBonusPercent(); + uint256 liquidationAssets = (exitedAssetsBefore * 1e18) / liqBonusPercent; + uint256 liquidationShares = contracts.osTokenVaultController.convertToShares(liquidationAssets); + + // Expect liquidation event + vm.expectEmit(true, true, true, false); + emit IOsTokenVaultEscrow.OsTokenLiquidated( + liquidator, address(vault), exitPositionTicket_, liquidator, liquidationShares, exitedAssetsBefore + ); + + // Liquidate the position + vm.prank(liquidator); + _startSnapshotGas("OsTokenLiquidationTest_test_liquidateOsToken_success"); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), exitPositionTicket_, liquidationShares, liquidator + ); + _stopSnapshotGas(); + + // Get position details after liquidation + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket_); + + // Verify liquidator received assets + uint256 liquidatorBalanceAfter = liquidator.balance; + assertApproxEqAbs( + liquidatorBalanceAfter - liquidatorBalanceBefore, + exitedAssetsBefore, + 2, + "Liquidator did not receive correct amount of assets" + ); + + // Verify position was updated + assertEq(ownerAfter, ownerBefore, "Owner should not change"); + assertApproxEqAbs(exitedAssetsAfter, 0, 2, "Exited assets not correctly reduced"); + assertLt(sharesAfter, sharesBefore, "Shares not correctly reduced"); + } + + function test_liquidateOsToken_invalidHealthFactor() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Process exited assets without making the position unhealthy + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, osTokenShares); + + // Get liquidation amount + (,, uint256 sharesBefore) = contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + uint256 liquidationShares = sharesBefore / 2; + + // Try to liquidate a healthy position + vm.prank(liquidator); + _startSnapshotGas("OsTokenLiquidationTest_test_liquidateOsToken_invalidHealthFactor"); + vm.expectRevert(Errors.InvalidHealthFactor.selector); + contracts.osTokenVaultEscrow.liquidateOsToken(address(vault), exitPositionTicket, liquidationShares, liquidator); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_invalidPosition() public { + // Setup a non-existent position + uint256 nonExistentTicket = 9999; + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, 1 ether); + + // Try to liquidate a non-existent position + vm.prank(liquidator); + _startSnapshotGas("OsTokenLiquidationTest_test_liquidateOsToken_invalidPosition"); + vm.expectRevert(Errors.InvalidPosition.selector); + contracts.osTokenVaultEscrow.liquidateOsToken(address(vault), nonExistentTicket, 1 ether, liquidator); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_zeroAddress() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, osTokenShares); + + // Try to liquidate to zero address + vm.prank(liquidator); + _startSnapshotGas("OsTokenLiquidationTest_test_liquidateOsToken_zeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + contracts.osTokenVaultEscrow.liquidateOsToken(address(vault), exitPositionTicket, osTokenShares, address(0)); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_invalidReceivedAssets() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mint too many osToken shares to liquidator (much more than the position value) + uint256 excessiveShares = osTokenShares * 100; + _mintOsToken(liquidator, excessiveShares); + + // Try to liquidate with excessive shares + vm.prank(liquidator); + _startSnapshotGas("OsTokenLiquidationTest_test_liquidateOsToken_invalidReceivedAssets"); + vm.expectRevert(Errors.InvalidReceivedAssets.selector); + contracts.osTokenVaultEscrow.liquidateOsToken(address(vault), exitPositionTicket, excessiveShares, liquidator); + _stopSnapshotGas(); + } + + function test_liquidateOsToken_partialLiquidation() public { + // Setup a position in escrow + (uint256 exitPositionTicket,, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Make the position unhealthy for liquidation + _makePositionUnhealthy(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Get position details before liquidation + (address ownerBefore, uint256 exitedAssetsBefore, uint256 sharesBefore) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + // Only liquidate half of the position + uint256 liqBonusPercent = contracts.osTokenVaultEscrow.liqBonusPercent(); + uint256 halfExitedAssets = exitedAssetsBefore / 2; + uint256 halfLiquidationAssets = (halfExitedAssets * 1e18) / liqBonusPercent; + uint256 halfLiquidationShares = contracts.osTokenVaultController.convertToShares(halfLiquidationAssets); + + // Mint osToken shares to liquidator + _mintOsToken(liquidator, halfLiquidationShares); + + // Record liquidator balance before + uint256 liquidatorBalanceBefore = liquidator.balance; + + // Liquidate half the position + vm.prank(liquidator); + _startSnapshotGas("OsTokenLiquidationTest_test_liquidateOsToken_partialLiquidation"); + contracts.osTokenVaultEscrow.liquidateOsToken( + address(vault), exitPositionTicket, halfLiquidationShares, liquidator + ); + _stopSnapshotGas(); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Get position details after liquidation + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket_); + + // Verify partial liquidation results + assertEq(ownerAfter, ownerBefore, "Owner should not change"); + assertApproxEqAbs( + exitedAssetsAfter, + exitedAssetsBefore - halfExitedAssets, + 10, + "Exited assets should be reduced by approximately half" + ); + assertLt(sharesAfter, sharesBefore, "Shares should be reduced"); + + // Verify liquidator received assets + uint256 liquidatorBalanceAfter = liquidator.balance; + assertApproxEqAbs( + liquidatorBalanceAfter - liquidatorBalanceBefore, + halfExitedAssets, + 10, + "Liquidator should receive approximately half of the exited assets" + ); + } + + function test_redeemOsToken_success() public { + vm.prank(address(contracts.keeper)); + contracts.osTokenVaultController.setAvgRewardPerSecond(0); + + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Get position details before redemption + (address ownerBefore, uint256 exitedAssetsBefore,) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + uint256 expectedAssets = contracts.osTokenVaultController.convertToAssets(osTokenShares); + + // Mint osToken shares to the redeemer + address redeemer = makeAddr("redeemer"); + _mintOsToken(redeemer, osTokenShares); + + // set redeemer + vm.prank(Ownable(address(contracts.keeper)).owner()); + contracts.osTokenConfig.setRedeemer(redeemer); + + // Record redeemer balance before + address receiver = makeAddr("receiver"); + uint256 receiverBalanceBefore = receiver.balance; + + // Expect OsTokenRedeemed event + vm.expectEmit(true, true, true, true); + emit IOsTokenVaultEscrow.OsTokenRedeemed( + redeemer, address(vault), exitPositionTicket, receiver, osTokenShares, expectedAssets + ); + + // Redeem the position + vm.prank(redeemer); + _startSnapshotGas("OsTokenLiquidationTest_test_redeemOsToken_success"); + contracts.osTokenVaultEscrow.redeemOsToken(address(vault), exitPositionTicket, osTokenShares, receiver); + _stopSnapshotGas(); + + // Verify receiver received assets + uint256 receiverBalanceAfter = receiver.balance; + assertEq( + receiverBalanceAfter - receiverBalanceBefore, expectedAssets, "Receiver should receive all exited assets" + ); + + // push down the stack + uint256 exitPositionTicket_ = exitPositionTicket; + + // Get position details after redemption + (address ownerAfter, uint256 exitedAssetsAfter, uint256 sharesAfter) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket_); + + // Verify position was updated + assertEq(ownerAfter, ownerBefore, "Owner should not change"); + assertEq(exitedAssetsAfter, exitedAssetsBefore - expectedAssets, "Exited assets should be zero"); + assertEq(sharesAfter, 0, "Shares should be zero"); + } + + function test_redeemOsToken_notRedeemer() public { + // Setup a position in escrow + (uint256 exitPositionTicket, uint256 osTokenShares, uint256 timestamp) = _setupEscrowPosition(); + + // Process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(exitPositionTicket)); + + // Process exited assets + contracts.osTokenVaultEscrow.processExitedAssets(address(vault), exitPositionTicket, timestamp, exitQueueIndex); + + // Mock the osTokenConfig.redeemer call to return an official redeemer address + address officialRedeemer = makeAddr("officialRedeemer"); + vm.mockCall( + address(contracts.osTokenConfig), + abi.encodeWithSelector(bytes4(keccak256("redeemer()"))), + abi.encode(officialRedeemer) + ); + + // Try to redeem from an unauthorized address + address unauthorizedCaller = makeAddr("unauthorizedCaller"); + _mintOsToken(unauthorizedCaller, osTokenShares); + + vm.prank(unauthorizedCaller); + _startSnapshotGas("OsTokenLiquidationTest_test_redeemOsToken_notRedeemer"); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.osTokenVaultEscrow.redeemOsToken( + address(vault), exitPositionTicket, osTokenShares, unauthorizedCaller + ); + _stopSnapshotGas(); + + // Clear the mock + vm.clearMockedCalls(); + } + + function test_updateLiqConfig_success() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Define new values - using conservative values + uint64 newLiqThresholdPercent = 5e17; // 50% + uint256 newLiqBonusPercent = 1.1e18; // 110% + + // Expect LiqConfigUpdated event + vm.expectEmit(true, true, false, false); + emit IOsTokenVaultEscrow.LiqConfigUpdated(newLiqThresholdPercent, newLiqBonusPercent); + + // Call updateLiqConfig as owner + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_updateLiqConfig_success"); + contracts.osTokenVaultEscrow.updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent); + _stopSnapshotGas(); + + // Verify state was updated + assertEq( + contracts.osTokenVaultEscrow.liqThresholdPercent(), + newLiqThresholdPercent, + "liqThresholdPercent not updated correctly" + ); + assertEq( + contracts.osTokenVaultEscrow.liqBonusPercent(), newLiqBonusPercent, "liqBonusPercent not updated correctly" + ); + } + + function test_updateLiqConfig_onlyOwner() public { + // Define values + uint64 newLiqThresholdPercent = 5e17; // 50% + uint256 newLiqBonusPercent = 1.1e18; // 110% + + // Get a non-owner address + address nonOwner = makeAddr("nonOwner"); + + // Call updateLiqConfig as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_updateLiqConfig_onlyOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + contracts.osTokenVaultEscrow.updateLiqConfig(newLiqThresholdPercent, newLiqBonusPercent); + _stopSnapshotGas(); + } + + function test_updateLiqConfig_invalidThreshold() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Test with threshold = 0 + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_zero"); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(0, 1.1e18); + _stopSnapshotGas(); + + // Test with threshold = 1e18 (100%) + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_max"); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(1e18, 1.1e18); + _stopSnapshotGas(); + } + + function test_updateLiqConfig_invalidBonus() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Test with bonus < _maxPercent (1e18) + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_low"); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(5e17, 0.9e18); + _stopSnapshotGas(); + + // Test with bonus too high (threshold * bonus > _maxPercent) + // If threshold = 90% (0.9e18) and bonus = 112% (1.12e18), + // then 0.9e18 * 1.12e18 / 1e18 = 1.008e18 > 1e18 + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_high"); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + contracts.osTokenVaultEscrow.updateLiqConfig(9e17, 1.12e18); + _stopSnapshotGas(); + } + + function test_setAuthenticator_success() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Get current authenticator + address currentAuthenticator = contracts.osTokenVaultEscrow.authenticator(); + + // Create a new authenticator address + address newAuthenticator = makeAddr("newAuthenticator"); + + // Ensure it's different from the current one + if (newAuthenticator == currentAuthenticator) { + newAuthenticator = makeAddr("newAuthenticator2"); + } + + // Expect AuthenticatorUpdated event + vm.expectEmit(true, false, false, false); + emit IOsTokenVaultEscrow.AuthenticatorUpdated(newAuthenticator); + + // Call setAuthenticator as owner + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_setAuthenticator_success"); + contracts.osTokenVaultEscrow.setAuthenticator(newAuthenticator); + _stopSnapshotGas(); + + // Verify state was updated + assertEq(contracts.osTokenVaultEscrow.authenticator(), newAuthenticator, "Authenticator not updated correctly"); + } + + function test_setAuthenticator_onlyOwner() public { + // Create a new authenticator address + address newAuthenticator = makeAddr("newAuthenticator"); + + // Get a non-owner address + address nonOwner = makeAddr("nonOwner"); + + // Call setAuthenticator as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_setAuthenticator_onlyOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + contracts.osTokenVaultEscrow.setAuthenticator(newAuthenticator); + _stopSnapshotGas(); + } + + function test_setAuthenticator_valueNotChanged() public { + // Get the owner of the escrow contract + address escrowOwner = Ownable(address(contracts.osTokenVaultEscrow)).owner(); + + // Get current authenticator + address currentAuthenticator = contracts.osTokenVaultEscrow.authenticator(); + + // Call setAuthenticator with the same authenticator, should revert + vm.prank(escrowOwner); + _startSnapshotGas("EthOsTokenVaultEscrowTest_test_setAuthenticator_valueNotChanged"); + vm.expectRevert(Errors.ValueNotChanged.selector); + contracts.osTokenVaultEscrow.setAuthenticator(currentAuthenticator); + _stopSnapshotGas(); + } } diff --git a/test/EthPrivErc20Vault.t.sol b/test/EthPrivErc20Vault.t.sol index 2cdc6e42..177f22ce 100644 --- a/test/EthPrivErc20Vault.t.sol +++ b/test/EthPrivErc20Vault.t.sol @@ -1,457 +1,457 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; -import {EthPrivErc20Vault} from '../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; +import {EthPrivErc20Vault} from "../contracts/vaults/ethereum/EthPrivErc20Vault.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthPrivErc20VaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthPrivErc20Vault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public whitelister; - address public referrer = address(0); - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - whitelister = makeAddr('whitelister'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(other, 100 ether); - vm.deal(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthPrivErc20Vault, admin, initParams, false); - vault = EthPrivErc20Vault(payable(_vault)); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('EthPrivErc20Vault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 5); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_transfer() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(other, true); - vm.stopPrank(); - - // Deposit ETH to get vault tokens - _depositToVault(address(vault), amount, sender, sender); - - // Transfer tokens - vm.prank(sender); - _startSnapshotGas('EthPrivErc20VaultTest_test_transfer'); - vault.transfer(other, shares); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.balanceOf(sender), 0, 1); - assertEq(vault.balanceOf(other), shares); - } - - function test_cannotTransferToNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender but not other - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit ETH to get vault tokens - _depositToVault(address(vault), amount, sender, sender); - - // Try to transfer to non-whitelisted user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotTransferAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist other but not sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(other, true); - - // First whitelist sender temporarily to deposit - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit ETH to get vault tokens - _depositToVault(address(vault), amount, sender, sender); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Try to transfer from non-whitelisted user to whitelisted user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotDepositAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister but don't whitelist other - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Try to deposit as non-whitelisted user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit{value: amount}(receiver, referrer); - vm.stopPrank(); - } - - function test_cannotDepositToNotWhitelistedReceiver() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender but not receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Try to deposit to non-whitelisted receiver - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit{value: amount}(receiver, referrer); - vm.stopPrank(); - } + ForkContracts public contracts; + EthPrivErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + whitelister = makeAddr("whitelister"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthPrivErc20Vault, admin, initParams, false); + vault = EthPrivErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("EthPrivErc20Vault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_transfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(other, true); + vm.stopPrank(); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas("EthPrivErc20VaultTest_test_transfer"); + vault.transfer(other, shares); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(sender), 0, 1); + assertEq(vault.balanceOf(other), shares); + } + + function test_cannotTransferToNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not other + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Try to transfer to non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist other but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(other, true); + + // First whitelist sender temporarily to deposit + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to transfer from non-whitelisted user to whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit as non-whitelisted user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit{value: amount}(receiver, referrer); + vm.stopPrank(); + } - function test_canDepositAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 expectedShares = vault.convertToShares(amount); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit as whitelisted user to whitelisted receiver - _startSnapshotGas('EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser'); - _depositToVault(address(vault), amount, sender, receiver); - _stopSnapshotGas(); + function test_canDepositAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user to whitelisted receiver + _startSnapshotGas("EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser"); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); - // Check balances - assertApproxEqAbs(vault.balanceOf(receiver), expectedShares, 1); - } + // Check balances + assertApproxEqAbs(vault.balanceOf(receiver), expectedShares, 1); + } - function test_cannotDepositUsingReceiveAsNotWhitelistedUser() public { - uint256 amount = 1 ether; + function test_cannotDepositUsingReceiveAsNotWhitelistedUser() public { + uint256 amount = 1 ether; - // Set whitelister but don't whitelist other - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Try to deposit using receive() function as non-whitelisted user - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - (bool success, ) = address(vault).call{value: amount}(''); - require(success, 'Transfer failed'); - } - - function test_canDepositUsingReceiveAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // When depositing via the receive fallback, the vault should emit a Transfer event - // from address(0) to the sender - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(address(0), sender, shares); - - // Use low-level call to trigger the receive function - _startSnapshotGas('EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser'); - vm.prank(sender); - (bool success, ) = address(vault).call{value: amount}(''); - _stopSnapshotGas(); - - require(success, 'ETH transfer failed'); - - // Verify sender received the correct number of tokens - assertEq(vault.balanceOf(sender), shares, 'Sender should have received tokens'); - } - - function test_cannotUpdateStateAndDepositAsNotWhitelistedUser() public { - _collateralizeEthVault(address(vault)); - - // Set whitelister but don't whitelist other - vm.prank(admin); - vault.setWhitelister(whitelister); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Try to update state and deposit as non-whitelisted user - vm.startPrank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); - vm.stopPrank(); - } - - function test_cannotMintOsTokenAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister and temporarily whitelist sender to deposit - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit ETH to get vault tokens - _depositToVault(address(vault), amount, sender, sender); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Try to mint osToken as non-whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit ETH to get vault tokens - _depositToVault(address(vault), amount, sender, sender); - - // Mint osToken as whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_cannotDepositAndMintOsTokenAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister but don't whitelist other - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Try to deposit and mint osToken as non-whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.depositAndMintOsToken{value: amount}(other, osTokenShares, referrer); - } - - function test_canDepositAndMintOsTokenAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vm.stopPrank(); - - // Deposit and mint osToken as whitelisted user - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(amount / 2); - vm.prank(sender); - _startSnapshotGas('EthPrivErc20VaultTest_test_canDepositAndMintOsTokenAsWhitelistedUser'); - vault.depositAndMintOsToken{value: amount}(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check balances and osToken position - assertApproxEqAbs(vault.balanceOf(sender), shares, 1); - assertEq(vault.osTokenPositions(sender), osTokenShares); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('EthPrivErc20VaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.EthPrivErc20Vault, admin, initParams, true); - _stopSnapshotGas(); - EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = privErc20Vault.getExitQueueData(); - - assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); - assertEq(privErc20Vault.version(), 5); - assertEq(privErc20Vault.admin(), admin); - assertEq(privErc20Vault.whitelister(), admin); - assertEq(privErc20Vault.capacity(), 1000 ether); - assertEq(privErc20Vault.feePercent(), 1000); - assertEq(privErc20Vault.feeRecipient(), admin); - assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.totalShares(), _securityDeposit); - assertEq(privErc20Vault.totalAssets(), _securityDeposit); - assertEq(privErc20Vault.validatorsManagerNonce(), 0); - assertEq(privErc20Vault.totalSupply(), _securityDeposit); - assertEq(privErc20Vault.symbol(), 'SW-ETH-1'); - assertEq(privErc20Vault.name(), 'SW ETH Vault'); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.EthPrivErc20Vault, admin, initParams, true); - EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); - - // whitelist sender - vm.prank(privErc20Vault.whitelister()); - privErc20Vault.updateWhitelist(sender, true); - - _depositToVault(address(privErc20Vault), 95 ether, sender, sender); - _registerEthValidator(address(privErc20Vault), 32 ether, true); - - vm.prank(sender); - privErc20Vault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = privErc20Vault.totalShares(); - uint256 totalAssetsBefore = privErc20Vault.totalAssets(); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(privErc20Vault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV4(address(privErc20Vault)).queuedShares(); - uint256 senderBalanceBefore = privErc20Vault.getShares(sender); - - assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); - assertEq(privErc20Vault.version(), 4); - - _startSnapshotGas('EthPrivErc20VaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthPrivErc20Vault, address(privErc20Vault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); - assertEq(privErc20Vault.vaultId(), keccak256('EthPrivErc20Vault')); - assertEq(privErc20Vault.version(), 5); - assertEq(privErc20Vault.admin(), admin); - assertEq(privErc20Vault.whitelister(), admin); - assertEq(privErc20Vault.capacity(), 1000 ether); - assertEq(privErc20Vault.feePercent(), 1000); - assertEq(privErc20Vault.feeRecipient(), admin); - assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.totalShares(), totalSharesBefore); - assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); - assertEq(privErc20Vault.validatorsManagerNonce(), 0); - assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); - assertEq(privErc20Vault.totalSupply(), totalSharesBefore); - assertEq(privErc20Vault.symbol(), 'SW-ETH-1'); - assertEq(privErc20Vault.name(), 'SW ETH Vault'); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - } + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit using receive() function as non-whitelisted user + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + (bool success,) = address(vault).call{value: amount}(""); + require(success, "Transfer failed"); + } + + function test_canDepositUsingReceiveAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // When depositing via the receive fallback, the vault should emit a Transfer event + // from address(0) to the sender + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Use low-level call to trigger the receive function + _startSnapshotGas("EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser"); + vm.prank(sender); + (bool success,) = address(vault).call{value: amount}(""); + _stopSnapshotGas(); + + require(success, "ETH transfer failed"); + + // Verify sender received the correct number of tokens + assertEq(vault.balanceOf(sender), shares, "Sender should have received tokens"); + } + + function test_cannotUpdateStateAndDepositAsNotWhitelistedUser() public { + _collateralizeEthVault(address(vault)); + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to update state and deposit as non-whitelisted user + vm.startPrank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_cannotMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and temporarily whitelist sender to deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken as non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit ETH to get vault tokens + _depositToVault(address(vault), amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_cannotDepositAndMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit and mint osToken as non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.depositAndMintOsToken{value: amount}(other, osTokenShares, referrer); + } + + function test_canDepositAndMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vm.stopPrank(); + + // Deposit and mint osToken as whitelisted user + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(amount / 2); + vm.prank(sender); + _startSnapshotGas("EthPrivErc20VaultTest_test_canDepositAndMintOsTokenAsWhitelistedUser"); + vault.depositAndMintOsToken{value: amount}(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check balances and osToken position + assertApproxEqAbs(vault.balanceOf(sender), shares, 1); + assertEq(vault.osTokenPositions(sender), osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("EthPrivErc20VaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.EthPrivErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privErc20Vault.getExitQueueData(); + + assertEq(privErc20Vault.vaultId(), keccak256("EthPrivErc20Vault")); + assertEq(privErc20Vault.version(), 5); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.totalShares(), _securityDeposit); + assertEq(privErc20Vault.totalAssets(), _securityDeposit); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.totalSupply(), _securityDeposit); + assertEq(privErc20Vault.symbol(), "SW-ETH-1"); + assertEq(privErc20Vault.name(), "SW ETH Vault"); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthPrivErc20Vault, admin, initParams, true); + EthPrivErc20Vault privErc20Vault = EthPrivErc20Vault(payable(_vault)); + + // whitelist sender + vm.prank(privErc20Vault.whitelister()); + privErc20Vault.updateWhitelist(sender, true); + + _depositToVault(address(privErc20Vault), 95 ether, sender, sender); + _registerEthValidator(address(privErc20Vault), 32 ether, true); + + vm.prank(sender); + privErc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privErc20Vault.totalShares(); + uint256 totalAssetsBefore = privErc20Vault.totalAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(privErc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(privErc20Vault)).queuedShares(); + uint256 senderBalanceBefore = privErc20Vault.getShares(sender); + + assertEq(privErc20Vault.vaultId(), keccak256("EthPrivErc20Vault")); + assertEq(privErc20Vault.version(), 4); + + _startSnapshotGas("EthPrivErc20VaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthPrivErc20Vault, address(privErc20Vault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = privErc20Vault.getExitQueueData(); + assertEq(privErc20Vault.vaultId(), keccak256("EthPrivErc20Vault")); + assertEq(privErc20Vault.version(), 5); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.totalShares(), totalSharesBefore); + assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); + assertEq(privErc20Vault.totalSupply(), totalSharesBefore); + assertEq(privErc20Vault.symbol(), "SW-ETH-1"); + assertEq(privErc20Vault.name(), "SW ETH Vault"); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + } } diff --git a/test/EthPrivVault.t.sol b/test/EthPrivVault.t.sol index 133740a1..6a33abd1 100644 --- a/test/EthPrivVault.t.sol +++ b/test/EthPrivVault.t.sol @@ -1,490 +1,482 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {EthPrivVault} from '../contracts/vaults/ethereum/EthPrivVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {EthPrivVault} from "../contracts/vaults/ethereum/EthPrivVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthPrivVaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthPrivVault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public whitelister; - address public referrer = address(0); - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - whitelister = makeAddr('whitelister'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(other, 100 ether); - vm.deal(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.EthPrivVault, admin, initParams, false); - vault = EthPrivVault(payable(_vault)); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('EthPrivVault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 5); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_cannotDepositFromNotWhitelistedSender() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist receiver but not sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(receiver, true); - - // Try to deposit from non-whitelisted user - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - IEthVault(vault).deposit{value: amount}(receiver, address(0)); - vm.stopPrank(); - } - - function test_cannotDepositToNotWhitelistedReceiver() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender but not receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Try to deposit to non-whitelisted receiver - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - IEthVault(vault).deposit{value: amount}(receiver, referrer); - vm.stopPrank(); - } - - function test_canDepositAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit as whitelisted user - _startSnapshotGas('EthPrivVaultTest_test_canDepositAsWhitelistedUser'); - _depositToVault(address(vault), amount, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(receiver), shares, 1); - } - - function test_cannotDepositUsingReceiveAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister and don't whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Try to deposit using receive function as non-whitelisted user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - Address.sendValue(payable(vault), amount); - } - - function test_canDepositUsingReceiveAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit using receive function as whitelisted user - _startSnapshotGas('EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser'); - vm.prank(sender); - Address.sendValue(payable(vault), amount); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(sender), shares, 1); - } - - function test_cannotMintOsTokenFromNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister and whitelist user for initial deposit - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Try to mint osToken from non-whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - - // Mint osToken as whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_whitelistUpdateDoesNotAffectExistingFunds() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit ETH to get vault shares - _depositToVault(address(vault), amount, sender, sender); - uint256 initialBalance = vault.getShares(sender); - assertApproxEqAbs(initialBalance, shares, 1); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Verify share balance remains the same - assertEq( - vault.getShares(sender), - initialBalance, - 'Balance should not change when whitelisting is removed' - ); - - // Verify cannot make new deposits but still has existing shares - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - IEthVault(vault).deposit{value: amount}(sender, referrer); - vm.stopPrank(); - } - - function test_cannotUpdateStateAndDepositFromNotWhitelistedUser() public { - _collateralizeEthVault(address(vault)); - - // Set whitelister and don't whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Try to update state and deposit from non-whitelisted user - vm.startPrank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); - vm.stopPrank(); - } - - function test_canUpdateStateAndDepositAsWhitelistedUser() public { - _collateralizeEthVault(address(vault)); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Update state and deposit as whitelisted user - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - vm.prank(sender); - _startSnapshotGas('EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser'); - vault.updateStateAndDeposit{value: amount}(receiver, referrer, harvestParams); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(receiver), shares, 1); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('EthPrivVaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.EthPrivVault, admin, initParams, true); - _stopSnapshotGas(); - EthPrivVault privVault = EthPrivVault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = privVault.getExitQueueData(); - - assertEq(privVault.vaultId(), keccak256('EthPrivVault')); - assertEq(privVault.version(), 5); - assertEq(privVault.admin(), admin); - assertEq(privVault.whitelister(), admin); - assertEq(privVault.capacity(), 1000 ether); - assertEq(privVault.feePercent(), 1000); - assertEq(privVault.feeRecipient(), admin); - assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.totalShares(), _securityDeposit); - assertEq(privVault.totalAssets(), _securityDeposit); - assertEq(privVault.validatorsManagerNonce(), 0); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.EthPrivVault, admin, initParams, true); - EthPrivVault privVault = EthPrivVault(payable(_vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - privVault.setWhitelister(whitelister); - - vm.prank(whitelister); - privVault.updateWhitelist(sender, true); - - // Make a deposit - _depositToVault(address(privVault), 95 ether, sender, sender); - _registerEthValidator(address(privVault), 32 ether, true); - - vm.prank(sender); - privVault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = privVault.totalShares(); - uint256 totalAssetsBefore = privVault.totalAssets(); - uint256 senderSharesBefore = privVault.getShares(sender); - bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(privVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV4(address(privVault)).queuedShares(); - - assertEq(privVault.vaultId(), keccak256('EthPrivVault')); - assertEq(privVault.version(), 4); - - _startSnapshotGas('EthPrivVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthPrivVault, address(privVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); - assertEq(privVault.vaultId(), keccak256('EthPrivVault')); - assertEq(privVault.version(), 5); - assertEq(privVault.admin(), admin); - assertEq(privVault.whitelister(), whitelister); - assertEq(privVault.capacity(), 1000 ether); - assertEq(privVault.feePercent(), 1000); - assertEq(privVault.feeRecipient(), admin); - assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.totalShares(), totalSharesBefore); - assertEq(privVault.totalAssets(), totalAssetsBefore); - assertEq(privVault.validatorsManagerNonce(), 0); - assertEq(privVault.getShares(sender), senderSharesBefore); - assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq(queuedShares, queuedSharesBefore); - } - - function test_setWhitelister() public { - address newWhitelister = makeAddr('newWhitelister'); - - // Non-admin cannot set whitelister - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.setWhitelister(newWhitelister); - - // Admin can set whitelister - vm.prank(admin); - _startSnapshotGas('EthPrivVaultTest_test_setWhitelister'); - vault.setWhitelister(newWhitelister); - _stopSnapshotGas(); - - assertEq(vault.whitelister(), newWhitelister, 'Whitelister not set correctly'); - } - - function test_updateWhitelist() public { - // Set whitelister - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Non-whitelister cannot update whitelist - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.updateWhitelist(sender, true); - - // Whitelister can update whitelist - vm.prank(whitelister); - _startSnapshotGas('EthPrivVaultTest_test_updateWhitelist'); - vault.updateWhitelist(sender, true); - _stopSnapshotGas(); - - assertTrue(vault.whitelistedAccounts(sender), 'Account not whitelisted correctly'); - - // Whitelister can remove from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - assertFalse(vault.whitelistedAccounts(sender), 'Account not removed from whitelist correctly'); - } - - function test_depositAndMintOsTokenAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister and whitelist users - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit and mint osToken as whitelisted user - vm.prank(sender); - _startSnapshotGas('EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser'); - uint256 osTokenAssets = vault.depositAndMintOsToken{value: amount}( - sender, - type(uint256).max, - referrer - ); - _stopSnapshotGas(); - - // Check osToken position and vault shares - uint128 osTokenShares = vault.osTokenPositions(sender); - assertGt(osTokenShares, 0); - assertGt(osTokenAssets, 0); - assertApproxEqAbs(vault.getShares(sender), shares, 1); - } - - function test_cannotDepositAndMintOsTokenAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set whitelister without whitelisting sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(receiver, true); - - // Try to deposit and mint osToken as non-whitelisted user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.depositAndMintOsToken{value: amount}(receiver, type(uint256).max, referrer); - } + ForkContracts public contracts; + EthPrivVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + whitelister = makeAddr("whitelister"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(other, 100 ether); + vm.deal(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.EthPrivVault, admin, initParams, false); + vault = EthPrivVault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("EthPrivVault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 5); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_cannotDepositFromNotWhitelistedSender() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist receiver but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(receiver, true); + + // Try to deposit from non-whitelisted user + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(receiver, address(0)); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user + _startSnapshotGas("EthPrivVaultTest_test_canDepositAsWhitelistedUser"); + _depositToVault(address(vault), amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_cannotDepositUsingReceiveAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and don't whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit using receive function as non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + Address.sendValue(payable(vault), amount); + } + + function test_canDepositUsingReceiveAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit using receive function as whitelisted user + _startSnapshotGas("EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser"); + vm.prank(sender); + Address.sendValue(payable(vault), amount); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(sender), shares, 1); + } + + function test_cannotMintOsTokenFromNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist user for initial deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken from non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_whitelistUpdateDoesNotAffectExistingFunds() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit ETH to get vault shares + _depositToVault(address(vault), amount, sender, sender); + uint256 initialBalance = vault.getShares(sender); + assertApproxEqAbs(initialBalance, shares, 1); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Verify share balance remains the same + assertEq(vault.getShares(sender), initialBalance, "Balance should not change when whitelisting is removed"); + + // Verify cannot make new deposits but still has existing shares + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).deposit{value: amount}(sender, referrer); + vm.stopPrank(); + } + + function test_cannotUpdateStateAndDepositFromNotWhitelistedUser() public { + _collateralizeEthVault(address(vault)); + + // Set whitelister and don't whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Try to update state and deposit from non-whitelisted user + vm.startPrank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateStateAndDeposit{value: 1 ether}(receiver, referrer, harvestParams); + vm.stopPrank(); + } + + function test_canUpdateStateAndDepositAsWhitelistedUser() public { + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Update state and deposit as whitelisted user + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + vm.prank(sender); + _startSnapshotGas("EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser"); + vault.updateStateAndDeposit{value: amount}(receiver, referrer, harvestParams); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("EthPrivVaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.EthPrivVault, admin, initParams, true); + _stopSnapshotGas(); + EthPrivVault privVault = EthPrivVault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privVault.getExitQueueData(); + + assertEq(privVault.vaultId(), keccak256("EthPrivVault")); + assertEq(privVault.version(), 5); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), admin); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.totalShares(), _securityDeposit); + assertEq(privVault.totalAssets(), _securityDeposit); + assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.EthPrivVault, admin, initParams, true); + EthPrivVault privVault = EthPrivVault(payable(_vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + privVault.setWhitelister(whitelister); + + vm.prank(whitelister); + privVault.updateWhitelist(sender, true); + + // Make a deposit + _depositToVault(address(privVault), 95 ether, sender, sender); + _registerEthValidator(address(privVault), 32 ether, true); + + vm.prank(sender); + privVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privVault.totalShares(); + uint256 totalAssetsBefore = privVault.totalAssets(); + uint256 senderSharesBefore = privVault.getShares(sender); + bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(privVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV4(address(privVault)).queuedShares(); + + assertEq(privVault.vaultId(), keccak256("EthPrivVault")); + assertEq(privVault.version(), 4); + + _startSnapshotGas("EthPrivVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthPrivVault, address(privVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = privVault.getExitQueueData(); + assertEq(privVault.vaultId(), keccak256("EthPrivVault")); + assertEq(privVault.version(), 5); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), whitelister); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.totalShares(), totalSharesBefore); + assertEq(privVault.totalAssets(), totalAssetsBefore); + assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(privVault.getShares(sender), senderSharesBefore); + assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(queuedShares, queuedSharesBefore); + } + + function test_setWhitelister() public { + address newWhitelister = makeAddr("newWhitelister"); + + // Non-admin cannot set whitelister + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setWhitelister(newWhitelister); + + // Admin can set whitelister + vm.prank(admin); + _startSnapshotGas("EthPrivVaultTest_test_setWhitelister"); + vault.setWhitelister(newWhitelister); + _stopSnapshotGas(); + + assertEq(vault.whitelister(), newWhitelister, "Whitelister not set correctly"); + } + + function test_updateWhitelist() public { + // Set whitelister + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Non-whitelister cannot update whitelist + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateWhitelist(sender, true); + + // Whitelister can update whitelist + vm.prank(whitelister); + _startSnapshotGas("EthPrivVaultTest_test_updateWhitelist"); + vault.updateWhitelist(sender, true); + _stopSnapshotGas(); + + assertTrue(vault.whitelistedAccounts(sender), "Account not whitelisted correctly"); + + // Whitelister can remove from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + assertFalse(vault.whitelistedAccounts(sender), "Account not removed from whitelist correctly"); + } + + function test_depositAndMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister and whitelist users + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit and mint osToken as whitelisted user + vm.prank(sender); + _startSnapshotGas("EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser"); + uint256 osTokenAssets = vault.depositAndMintOsToken{value: amount}(sender, type(uint256).max, referrer); + _stopSnapshotGas(); + + // Check osToken position and vault shares + uint128 osTokenShares = vault.osTokenPositions(sender); + assertGt(osTokenShares, 0); + assertGt(osTokenAssets, 0); + assertApproxEqAbs(vault.getShares(sender), shares, 1); + } + + function test_cannotDepositAndMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set whitelister without whitelisting sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(receiver, true); + + // Try to deposit and mint osToken as non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.depositAndMintOsToken{value: amount}(receiver, type(uint256).max, referrer); + } } diff --git a/test/EthRewardSplitter.t.sol b/test/EthRewardSplitter.t.sol index 96f7063f..8f851d2b 100644 --- a/test/EthRewardSplitter.t.sol +++ b/test/EthRewardSplitter.t.sol @@ -1,522 +1,470 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {EthRewardSplitter} from '../contracts/misc/EthRewardSplitter.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {EthErc20Vault, IEthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {RewardSplitterFactory} from '../contracts/misc/RewardSplitterFactory.sol'; -import {IRewardSplitter} from '../contracts/interfaces/IRewardSplitter.sol'; -import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; -import {IVaultFee} from '../contracts/interfaces/IVaultFee.sol'; -import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; +import {Test} from "forge-std/Test.sol"; +import {EthRewardSplitter} from "../contracts/misc/EthRewardSplitter.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {EthErc20Vault, IEthErc20Vault} from "../contracts/vaults/ethereum/EthErc20Vault.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {RewardSplitterFactory} from "../contracts/misc/RewardSplitterFactory.sol"; +import {IRewardSplitter} from "../contracts/interfaces/IRewardSplitter.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {IVaultFee} from "../contracts/interfaces/IVaultFee.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; contract EthRewardSplitterTest is Test, EthHelpers { - ForkContracts public contracts; - EthErc20Vault public vault; - EthRewardSplitter public rewardSplitter; - RewardSplitterFactory public splitterFactory; - - address public admin; - address public shareholder1; - address public shareholder2; - address public depositor; - - uint128 public constant SHARE1 = 7000; // 70% - uint128 public constant SHARE2 = 3000; // 30% - uint256 public constant DEPOSIT_AMOUNT = 100 ether; - - function setUp() public { - // Get fork contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - shareholder1 = makeAddr('shareholder1'); - shareholder2 = makeAddr('shareholder2'); - depositor = makeAddr('depositor'); - - // Fund accounts - vm.deal(admin, 100 ether); - vm.deal(depositor, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - name: 'Test Vault', - symbol: 'TVLT', - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); - vault = EthErc20Vault(payable(vaultAddr)); - - // Deploy RewardSplitter implementation - EthRewardSplitter impl = new EthRewardSplitter(); - - // Deploy RewardSplitterFactory - splitterFactory = new RewardSplitterFactory(address(impl)); - - // Create RewardSplitter for the vault - vm.prank(admin); - address splitterAddr = splitterFactory.createRewardSplitter(address(vault)); - rewardSplitter = EthRewardSplitter(payable(splitterAddr)); - - // Set RewardSplitter as fee recipient - vm.prank(admin); - vault.setFeeRecipient(address(rewardSplitter)); - - // Configure shares in RewardSplitter - vm.startPrank(admin); - rewardSplitter.increaseShares(shareholder1, SHARE1); - rewardSplitter.increaseShares(shareholder2, SHARE2); - vm.stopPrank(); - - // Collateralize vault to enable rewards - _collateralizeEthVault(address(vault)); - } - - function test_initialization() public view { - assertEq(rewardSplitter.vault(), address(vault), 'Vault address not set correctly'); - assertEq(rewardSplitter.totalShares(), SHARE1 + SHARE2, 'Total shares not set correctly'); - assertEq( - rewardSplitter.sharesOf(shareholder1), - SHARE1, - 'Shareholder1 shares not set correctly' - ); - assertEq( - rewardSplitter.sharesOf(shareholder2), - SHARE2, - 'Shareholder2 shares not set correctly' - ); - } - - function test_generateAndDistributeRewards() public { - // Generate rewards by depositing and simulating profit - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - // Get initial vault shares of reward splitter - uint256 initialShares = vault.getShares(address(rewardSplitter)); - - // Simulate rewards/profit - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), // 1 ETH reward - 0 - ); - - // Update vault state to distribute rewards - vault.updateState(harvestParams); - - // Verify RewardSplitter has received vault shares as rewards - uint256 newShares = vault.getShares(address(rewardSplitter)); - assertGt(newShares, initialShares, 'RewardSplitter should have received vault shares'); - - // Sync rewards in the splitter - _startSnapshotGas('EthRewardSplitter_syncRewards'); - rewardSplitter.syncRewards(); - _stopSnapshotGas(); - - // Check available rewards - uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); - uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); - assertGt(rewards1, 0, 'Shareholder1 should have rewards'); - assertGt(rewards2, 0, 'Shareholder2 should have rewards'); - - // Record initial ETH balances - uint256 shareholder1BalanceBefore = shareholder1.balance; - - // Shareholder1 enters exit queue with their vault shares - vm.prank(shareholder1); - uint256 timestamp = vm.getBlockTimestamp(); - _startSnapshotGas('EthRewardSplitter_enterExitQueue'); - uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); - _stopSnapshotGas(); - - // Process the exit queue - harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); - vault.updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Shareholder1 claims exited assets - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - vm.prank(shareholder1); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - - // Verify shareholder1 received ETH rewards - assertGt( - shareholder1.balance - shareholder1BalanceBefore, - 0, - 'Shareholder1 should receive ETH rewards' - ); - - // Shareholder2 directly claims tokens without going through exit queue - vm.prank(shareholder2); - _startSnapshotGas('EthRewardSplitter_claimVaultTokens'); - address receiver = shareholder2; - rewardSplitter.claimVaultTokens(rewards2, receiver); - _stopSnapshotGas(); - - // Verify shareholder2 received vault tokens - assertGt(vault.getShares(receiver), 0, 'Shareholder2 should receive vault tokens directly'); - } - - function test_maxWithdrawal() public { - // Generate rewards - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), - 0 - ); - - vault.updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Get total rewards available - uint256 totalRewards = rewardSplitter.rewardsOf(shareholder1); - assertGt(totalRewards, 0, 'Should have rewards to withdraw'); - - // Withdraw using max value (should withdraw all available rewards) - vm.prank(shareholder1); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); - _startSnapshotGas('EthRewardSplitter_enterExitQueueMaxWithdrawal'); - rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); - _stopSnapshotGas(); - - // Check rewards were fully claimed - assertEq(rewardSplitter.rewardsOf(shareholder1), 0, 'All rewards should be withdrawn'); - } - - function test_notHarvestedInSyncRewards() public { - // Generate rewards - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - // Force vault to need harvesting without actually harvesting - // First set a reward to make it need harvesting - _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); - - // Mock the isStateUpdateRequired to return true - vm.mockCall( - address(vault), - abi.encodeWithSelector(IVaultState.isStateUpdateRequired.selector), - abi.encode(true) - ); - - // Attempt to sync rewards when vault needs harvesting - vm.expectRevert(IRewardSplitter.NotHarvested.selector); - rewardSplitter.syncRewards(); - } - - function test_exitRequestNotProcessedInClaimOnBehalf() public { - // Enable claim on behalf - vm.prank(admin); - rewardSplitter.setClaimOnBehalf(true); - - // Generate rewards - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), - 0 - ); - - vault.updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Enter exit queue on behalf of shareholder1 - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(admin); - uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - - // Try to claim without waiting for the delay period - // (Exit request is not yet processed) - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - - vm.prank(admin); - vm.expectRevert(Errors.ExitRequestNotProcessed.selector); - rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); - } - - function test_accessDeniedInEnterExitQueueOnBehalf() public { - // Generate rewards - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), - 0 - ); - - vault.updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Claim on behalf is disabled by default - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - - // Should fail with AccessDenied since claim-on-behalf is disabled - vm.prank(admin); - vm.expectRevert(Errors.AccessDenied.selector); - rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - } - - function test_claimOnBehalf() public { - // Enable claim on behalf - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); - _startSnapshotGas('EthRewardSplitter_setClaimOnBehalf'); - rewardSplitter.setClaimOnBehalf(true); - _stopSnapshotGas(); - - // Generate rewards - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), - 0 - ); - - vault.updateState(harvestParams); - - // Sync rewards - rewardSplitter.syncRewards(); - - // Check available rewards - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - assertGt(rewards, 0, 'Shareholder should have rewards'); - - // Someone else enters exit queue on behalf of shareholder1 - vm.prank(admin); - uint256 timestamp = vm.getBlockTimestamp(); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point - _startSnapshotGas('EthRewardSplitter_enterExitQueueOnBehalf'); - uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - _stopSnapshotGas(); - - // Verify position is tracked correctly - assertEq( - rewardSplitter.exitPositions(positionTicket), - shareholder1, - 'Exit position should be tracked' - ); - - // Process the exit queue - harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); - vault.updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Someone else claims on behalf of shareholder1 - uint256 shareholder1BalanceBefore = shareholder1.balance; - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - - // Expected reward amount to be claimed - (, , uint256 exitedAssets) = vault.calculateExitedAssets( - address(rewardSplitter), - positionTicket, - timestamp, - uint256(exitQueueIndex) - ); - - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); - _startSnapshotGas('EthRewardSplitter_claimExitedAssetsOnBehalf'); - rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // Verify shareholder1 received rewards - assertGt( - shareholder1.balance - shareholder1BalanceBefore, - 0, - 'Shareholder should receive claimed rewards' - ); - } - - function test_syncRewards() public { - // Generate rewards - vm.prank(depositor); - vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), - 0 - ); - - vault.updateState(harvestParams); - - // Initial state before sync - uint256 initialTotalRewards = rewardSplitter.totalRewards(); - - // Should be able to sync rewards - assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards'); - - // Sync rewards with event check - vm.expectEmit(false, false, false, false); // We don't know exact values - emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values - _startSnapshotGas('EthRewardSplitter_syncRewardsDetailed'); - rewardSplitter.syncRewards(); - _stopSnapshotGas(); - - // Verify rewards were synced - uint256 newTotalRewards = rewardSplitter.totalRewards(); - assertGt(newTotalRewards, initialTotalRewards, 'Total rewards should increase after sync'); - - // Verify each shareholder has rewards - uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); - uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); - - assertGt(rewards1, 0, 'Shareholder1 should have rewards after sync'); - assertGt(rewards2, 0, 'Shareholder2 should have rewards after sync'); - - // Verify proportional distribution - assertApproxEqRel( - rewards1, - (newTotalRewards * SHARE1) / (SHARE1 + SHARE2), - 0.0001e18, // 0.01% tolerance - 'Shareholder1 rewards should be proportional to shares' - ); - - assertApproxEqRel( - rewards2, - (newTotalRewards * SHARE2) / (SHARE1 + SHARE2), - 0.0001e18, // 0.01% tolerance - 'Shareholder2 rewards should be proportional to shares' - ); - } - - function test_manageShares() public { - // Test increase shares with event - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.SharesIncreased(shareholder1, 1000); - _startSnapshotGas('EthRewardSplitter_increaseShares'); - rewardSplitter.increaseShares(shareholder1, 1000); - _stopSnapshotGas(); - - assertEq( - rewardSplitter.sharesOf(shareholder1), - SHARE1 + 1000, - 'Shares should increase by 1000' - ); - - // Test decrease shares with event - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.SharesDecreased(shareholder1, 1000); - _startSnapshotGas('EthRewardSplitter_decreaseShares'); - rewardSplitter.decreaseShares(shareholder1, 1000); - _stopSnapshotGas(); - - assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1, 'Shares should decrease by 1000'); - } - - function test_updateVaultState() public { - // Generate rewards with a callback from reward splitter - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(1 ether)), - 0 - ); - - // Update vault state through reward splitter - _startSnapshotGas('EthRewardSplitter_updateVaultState'); - rewardSplitter.updateVaultState(harvestParams); - _stopSnapshotGas(); - - // Verify rewards can be synced - assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards after update'); - - // Sync and verify rewards - rewardSplitter.syncRewards(); - uint256 totalRewards = rewardSplitter.totalRewards(); - assertGt(totalRewards, 0, 'Total rewards should be greater than zero'); - } - - function test_receiveEth() public { - // Send ETH directly to RewardSplitter - uint256 amount = 1 ether; - uint256 initialBalance = address(rewardSplitter).balance; - - // Send ETH - _startSnapshotGas('EthRewardSplitter_receiveEth'); - (bool success, ) = address(rewardSplitter).call{value: amount}(''); - _stopSnapshotGas(); - assertTrue(success, 'ETH transfer should succeed'); - - // Verify balance increased - assertEq( - address(rewardSplitter).balance, - initialBalance + amount, - 'RewardSplitter balance should increase' - ); - } - - function test_accessControl() public { - // Non-admin tries to increase shares - vm.prank(shareholder1); - vm.expectRevert(Errors.AccessDenied.selector); - rewardSplitter.increaseShares(shareholder1, 1000); - - // Non-admin tries to decrease shares - vm.prank(shareholder1); - vm.expectRevert(Errors.AccessDenied.selector); - rewardSplitter.decreaseShares(shareholder1, 1000); - - // Non-admin tries to set claim on behalf - vm.prank(shareholder1); - vm.expectRevert(Errors.AccessDenied.selector); - rewardSplitter.setClaimOnBehalf(true); - } - - function test_invalidAccountInDecreaseShares() public { - // Try to decrease shares for the zero address - vm.prank(admin); - vm.expectRevert(IRewardSplitter.InvalidAccount.selector); - rewardSplitter.decreaseShares(address(0), 1000); - - // Also test non-zero but invalid account (one that has no shares) - address randomAccount = makeAddr('randomAccount'); - vm.prank(admin); - vm.expectRevert(); // This will revert when trying to decrease below zero, but the error type may vary - rewardSplitter.decreaseShares(randomAccount, 1000); - } - - function test_invalidParameters() public { - // Try to increase shares with invalid amount - vm.prank(admin); - vm.expectRevert(IRewardSplitter.InvalidAmount.selector); - rewardSplitter.increaseShares(shareholder1, 0); - - // Try to increase shares with invalid account - vm.prank(admin); - vm.expectRevert(IRewardSplitter.InvalidAccount.selector); - rewardSplitter.increaseShares(address(0), 1000); - - // Try to decrease shares with invalid amount - vm.prank(admin); - vm.expectRevert(IRewardSplitter.InvalidAmount.selector); - rewardSplitter.decreaseShares(shareholder1, 0); - } + ForkContracts public contracts; + EthErc20Vault public vault; + EthRewardSplitter public rewardSplitter; + RewardSplitterFactory public splitterFactory; + + address public admin; + address public shareholder1; + address public shareholder2; + address public depositor; + + uint128 public constant SHARE1 = 7000; // 70% + uint128 public constant SHARE2 = 3000; // 30% + uint256 public constant DEPOSIT_AMOUNT = 100 ether; + + function setUp() public { + // Get fork contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + shareholder1 = makeAddr("shareholder1"); + shareholder2 = makeAddr("shareholder2"); + depositor = makeAddr("depositor"); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(depositor, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + name: "Test Vault", + symbol: "TVLT", + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(vaultAddr)); + + // Deploy RewardSplitter implementation + EthRewardSplitter impl = new EthRewardSplitter(); + + // Deploy RewardSplitterFactory + splitterFactory = new RewardSplitterFactory(address(impl)); + + // Create RewardSplitter for the vault + vm.prank(admin); + address splitterAddr = splitterFactory.createRewardSplitter(address(vault)); + rewardSplitter = EthRewardSplitter(payable(splitterAddr)); + + // Set RewardSplitter as fee recipient + vm.prank(admin); + vault.setFeeRecipient(address(rewardSplitter)); + + // Configure shares in RewardSplitter + vm.startPrank(admin); + rewardSplitter.increaseShares(shareholder1, SHARE1); + rewardSplitter.increaseShares(shareholder2, SHARE2); + vm.stopPrank(); + + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + } + + function test_initialization() public view { + assertEq(rewardSplitter.vault(), address(vault), "Vault address not set correctly"); + assertEq(rewardSplitter.totalShares(), SHARE1 + SHARE2, "Total shares not set correctly"); + assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1, "Shareholder1 shares not set correctly"); + assertEq(rewardSplitter.sharesOf(shareholder2), SHARE2, "Shareholder2 shares not set correctly"); + } + + function test_generateAndDistributeRewards() public { + // Generate rewards by depositing and simulating profit + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + // Get initial vault shares of reward splitter + uint256 initialShares = vault.getShares(address(rewardSplitter)); + + // Simulate rewards/profit + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( + address(vault), + int160(int256(1 ether)), // 1 ETH reward + 0 + ); + + // Update vault state to distribute rewards + vault.updateState(harvestParams); + + // Verify RewardSplitter has received vault shares as rewards + uint256 newShares = vault.getShares(address(rewardSplitter)); + assertGt(newShares, initialShares, "RewardSplitter should have received vault shares"); + + // Sync rewards in the splitter + _startSnapshotGas("EthRewardSplitter_syncRewards"); + rewardSplitter.syncRewards(); + _stopSnapshotGas(); + + // Check available rewards + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + assertGt(rewards1, 0, "Shareholder1 should have rewards"); + assertGt(rewards2, 0, "Shareholder2 should have rewards"); + + // Record initial ETH balances + uint256 shareholder1BalanceBefore = shareholder1.balance; + + // Shareholder1 enters exit queue with their vault shares + vm.prank(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas("EthRewardSplitter_enterExitQueue"); + uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); + _stopSnapshotGas(); + + // Process the exit queue + harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Shareholder1 claims exited assets + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + vm.prank(shareholder1); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify shareholder1 received ETH rewards + assertGt(shareholder1.balance - shareholder1BalanceBefore, 0, "Shareholder1 should receive ETH rewards"); + + // Shareholder2 directly claims tokens without going through exit queue + vm.prank(shareholder2); + _startSnapshotGas("EthRewardSplitter_claimVaultTokens"); + address receiver = shareholder2; + rewardSplitter.claimVaultTokens(rewards2, receiver); + _stopSnapshotGas(); + + // Verify shareholder2 received vault tokens + assertGt(vault.getShares(receiver), 0, "Shareholder2 should receive vault tokens directly"); + } + + function test_maxWithdrawal() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + vault.updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Get total rewards available + uint256 totalRewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(totalRewards, 0, "Should have rewards to withdraw"); + + // Withdraw using max value (should withdraw all available rewards) + vm.prank(shareholder1); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); + _startSnapshotGas("EthRewardSplitter_enterExitQueueMaxWithdrawal"); + rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); + _stopSnapshotGas(); + + // Check rewards were fully claimed + assertEq(rewardSplitter.rewardsOf(shareholder1), 0, "All rewards should be withdrawn"); + } + + function test_notHarvestedInSyncRewards() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + // Force vault to need harvesting without actually harvesting + // First set a reward to make it need harvesting + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + // Mock the isStateUpdateRequired to return true + vm.mockCall( + address(vault), abi.encodeWithSelector(IVaultState.isStateUpdateRequired.selector), abi.encode(true) + ); + + // Attempt to sync rewards when vault needs harvesting + vm.expectRevert(IRewardSplitter.NotHarvested.selector); + rewardSplitter.syncRewards(); + } + + function test_exitRequestNotProcessedInClaimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + rewardSplitter.setClaimOnBehalf(true); + + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + vault.updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Enter exit queue on behalf of shareholder1 + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(admin); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + + // Try to claim without waiting for the delay period + // (Exit request is not yet processed) + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + + vm.prank(admin); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_accessDeniedInEnterExitQueueOnBehalf() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + vault.updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Claim on behalf is disabled by default + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + + // Should fail with AccessDenied since claim-on-behalf is disabled + vm.prank(admin); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + } + + function test_claimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); + _startSnapshotGas("EthRewardSplitter_setClaimOnBehalf"); + rewardSplitter.setClaimOnBehalf(true); + _stopSnapshotGas(); + + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + vault.updateState(harvestParams); + + // Sync rewards + rewardSplitter.syncRewards(); + + // Check available rewards + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(rewards, 0, "Shareholder should have rewards"); + + // Someone else enters exit queue on behalf of shareholder1 + vm.prank(admin); + uint256 timestamp = vm.getBlockTimestamp(); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point + _startSnapshotGas("EthRewardSplitter_enterExitQueueOnBehalf"); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + _stopSnapshotGas(); + + // Verify position is tracked correctly + assertEq(rewardSplitter.exitPositions(positionTicket), shareholder1, "Exit position should be tracked"); + + // Process the exit queue + harvestParams = _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + vault.updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Someone else claims on behalf of shareholder1 + uint256 shareholder1BalanceBefore = shareholder1.balance; + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + + // Expected reward amount to be claimed + (,, uint256 exitedAssets) = + vault.calculateExitedAssets(address(rewardSplitter), positionTicket, timestamp, uint256(exitQueueIndex)); + + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); + _startSnapshotGas("EthRewardSplitter_claimExitedAssetsOnBehalf"); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify shareholder1 received rewards + assertGt(shareholder1.balance - shareholder1BalanceBefore, 0, "Shareholder should receive claimed rewards"); + } + + function test_syncRewards() public { + // Generate rewards + vm.prank(depositor); + vault.deposit{value: DEPOSIT_AMOUNT}(depositor, address(0)); + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + vault.updateState(harvestParams); + + // Initial state before sync + uint256 initialTotalRewards = rewardSplitter.totalRewards(); + + // Should be able to sync rewards + assertTrue(rewardSplitter.canSyncRewards(), "Should be able to sync rewards"); + + // Sync rewards with event check + vm.expectEmit(false, false, false, false); // We don't know exact values + emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values + _startSnapshotGas("EthRewardSplitter_syncRewardsDetailed"); + rewardSplitter.syncRewards(); + _stopSnapshotGas(); + + // Verify rewards were synced + uint256 newTotalRewards = rewardSplitter.totalRewards(); + assertGt(newTotalRewards, initialTotalRewards, "Total rewards should increase after sync"); + + // Verify each shareholder has rewards + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + + assertGt(rewards1, 0, "Shareholder1 should have rewards after sync"); + assertGt(rewards2, 0, "Shareholder2 should have rewards after sync"); + + // Verify proportional distribution + assertApproxEqRel( + rewards1, + (newTotalRewards * SHARE1) / (SHARE1 + SHARE2), + 0.0001e18, // 0.01% tolerance + "Shareholder1 rewards should be proportional to shares" + ); + + assertApproxEqRel( + rewards2, + (newTotalRewards * SHARE2) / (SHARE1 + SHARE2), + 0.0001e18, // 0.01% tolerance + "Shareholder2 rewards should be proportional to shares" + ); + } + + function test_manageShares() public { + // Test increase shares with event + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesIncreased(shareholder1, 1000); + _startSnapshotGas("EthRewardSplitter_increaseShares"); + rewardSplitter.increaseShares(shareholder1, 1000); + _stopSnapshotGas(); + + assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1 + 1000, "Shares should increase by 1000"); + + // Test decrease shares with event + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesDecreased(shareholder1, 1000); + _startSnapshotGas("EthRewardSplitter_decreaseShares"); + rewardSplitter.decreaseShares(shareholder1, 1000); + _stopSnapshotGas(); + + assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1, "Shares should decrease by 1000"); + } + + function test_updateVaultState() public { + // Generate rewards with a callback from reward splitter + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(1 ether)), 0); + + // Update vault state through reward splitter + _startSnapshotGas("EthRewardSplitter_updateVaultState"); + rewardSplitter.updateVaultState(harvestParams); + _stopSnapshotGas(); + + // Verify rewards can be synced + assertTrue(rewardSplitter.canSyncRewards(), "Should be able to sync rewards after update"); + + // Sync and verify rewards + rewardSplitter.syncRewards(); + uint256 totalRewards = rewardSplitter.totalRewards(); + assertGt(totalRewards, 0, "Total rewards should be greater than zero"); + } + + function test_receiveEth() public { + // Send ETH directly to RewardSplitter + uint256 amount = 1 ether; + uint256 initialBalance = address(rewardSplitter).balance; + + // Send ETH + _startSnapshotGas("EthRewardSplitter_receiveEth"); + (bool success,) = address(rewardSplitter).call{value: amount}(""); + _stopSnapshotGas(); + assertTrue(success, "ETH transfer should succeed"); + + // Verify balance increased + assertEq(address(rewardSplitter).balance, initialBalance + amount, "RewardSplitter balance should increase"); + } + + function test_accessControl() public { + // Non-admin tries to increase shares + vm.prank(shareholder1); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.increaseShares(shareholder1, 1000); + + // Non-admin tries to decrease shares + vm.prank(shareholder1); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.decreaseShares(shareholder1, 1000); + + // Non-admin tries to set claim on behalf + vm.prank(shareholder1); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.setClaimOnBehalf(true); + } + + function test_invalidAccountInDecreaseShares() public { + // Try to decrease shares for the zero address + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAccount.selector); + rewardSplitter.decreaseShares(address(0), 1000); + + // Also test non-zero but invalid account (one that has no shares) + address randomAccount = makeAddr("randomAccount"); + vm.prank(admin); + vm.expectRevert(); // This will revert when trying to decrease below zero, but the error type may vary + rewardSplitter.decreaseShares(randomAccount, 1000); + } + + function test_invalidParameters() public { + // Try to increase shares with invalid amount + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAmount.selector); + rewardSplitter.increaseShares(shareholder1, 0); + + // Try to increase shares with invalid account + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAccount.selector); + rewardSplitter.increaseShares(address(0), 1000); + + // Try to decrease shares with invalid amount + vm.prank(admin); + vm.expectRevert(IRewardSplitter.InvalidAmount.selector); + rewardSplitter.decreaseShares(shareholder1, 0); + } } diff --git a/test/EthValidatorsChecker.t.sol b/test/EthValidatorsChecker.t.sol index 6496a0d7..90a11a4e 100644 --- a/test/EthValidatorsChecker.t.sol +++ b/test/EthValidatorsChecker.t.sol @@ -1,675 +1,619 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {EthValidatorsChecker} from '../contracts/validators/EthValidatorsChecker.sol'; -import {IValidatorsChecker} from '../contracts/interfaces/IValidatorsChecker.sol'; -import {IDepositDataRegistry} from '../contracts/interfaces/IDepositDataRegistry.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; -import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; -import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {EthValidatorsChecker} from "../contracts/validators/EthValidatorsChecker.sol"; +import {IValidatorsChecker} from "../contracts/interfaces/IValidatorsChecker.sol"; +import {IDepositDataRegistry} from "../contracts/interfaces/IDepositDataRegistry.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultValidators} from "../contracts/interfaces/IVaultValidators.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultValidatorsV1 { - function validatorsRoot() external view returns (bytes32); - function validatorIndex() external view returns (uint256); - function keysManager() external view returns (address); - function setValidatorsRoot(bytes32 root) external; + function validatorsRoot() external view returns (bytes32); + function validatorIndex() external view returns (uint256); + function keysManager() external view returns (address); + function setValidatorsRoot(bytes32 root) external; } contract EthValidatorsCheckerTest is Test, EthHelpers { - // Test contracts - ForkContracts public contracts; - EthValidatorsChecker public validatorsChecker; - address public vault; - address public emptyVault; - address public admin; - address public user; - bytes32 public validRegistryRoot; - - function setUp() public { - // Setup fork and contracts - contracts = _activateEthereumFork(); - - // Deploy a fresh EthValidatorsChecker - validatorsChecker = new EthValidatorsChecker( - address(contracts.validatorsRegistry), - address(contracts.keeper), - address(contracts.vaultsRegistry), - address(_depositDataRegistry) - ); - - // Setup accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - vm.deal(user, 100 ether); - - // Create and prepare a vault with sufficient funds - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - vault = _createVault(VaultType.EthVault, admin, initParams, false); - _depositToVault(vault, 33 ether, user, vault); // Deposit enough for 1 validator - _collateralizeEthVault(address(vault)); - - // Create another vault without sufficient funds - emptyVault = _createVault(VaultType.EthVault, admin, initParams, false); - - // Get valid registry root - validRegistryRoot = contracts.validatorsRegistry.get_deposit_root(); - } - - // Tests for checkValidatorsManagerSignature - - function testValidatorsManagerSignature_InvalidRegistryRoot() public view { - // Create invalid root - bytes32 invalidRoot = bytes32(uint256(validRegistryRoot) + 1); - - // Test with invalid root - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkValidatorsManagerSignature(vault, invalidRoot, '', ''); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_REGISTRY_ROOT)); - assertEq(blockNumber, block.number); - } - - function testValidatorsManagerSignature_InvalidVault() public { - // Use non-existent vault - address invalidVault = makeAddr('nonVault'); - - // Test with invalid vault - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkValidatorsManagerSignature(invalidVault, validRegistryRoot, '', ''); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VAULT)); - assertEq(blockNumber, block.number); - } - - function testValidatorsManagerSignature_InsufficientAssets() public view { - // Test with empty vault - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkValidatorsManagerSignature(emptyVault, validRegistryRoot, '', ''); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INSUFFICIENT_ASSETS)); - assertEq(blockNumber, block.number); - } - - function testValidatorsManagerSignature_InvalidSignature() public view { - // Get valid registry root - bytes32 validRoot = contracts.validatorsRegistry.get_deposit_root(); - - // Generate validator data - bytes memory validatorData = new bytes(184); // Valid length for one validator - - // Generate invalid signature - bytes memory invalidSignature = '0xdeadbeef'; - - // Check with invalid signature - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkValidatorsManagerSignature(vault, validRoot, validatorData, invalidSignature); - - // Verify expected result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_SIGNATURE)); - assertEq(blockNumber, block.number); - } - - // Tests for checkDepositDataRoot - - function testCheckDepositDataRoot_InvalidRegistryRoot() public view { - // Create invalid root - bytes32 invalidRoot = bytes32(uint256(validRegistryRoot) + 1); - - // Create params with invalid root - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: vault, - validatorsRegistryRoot: invalidRoot, - validators: '', - proof: new bytes32[](0), - proofFlags: new bool[](0), - proofIndexes: new uint256[](0) - }); - - // Test with invalid root - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_REGISTRY_ROOT)); - assertEq(blockNumber, block.number); - } - - function testCheckDepositDataRoot_InvalidVault() public { - // Use non-existent vault - address invalidVault = makeAddr('nonVault'); - - // Create params with invalid vault - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: invalidVault, - validatorsRegistryRoot: validRegistryRoot, - validators: '', - proof: new bytes32[](0), - proofFlags: new bool[](0), - proofIndexes: new uint256[](0) - }); - - // Test with invalid vault - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VAULT)); - assertEq(blockNumber, block.number); - } - - function testCheckDepositDataRoot_InsufficientAssets() public view { - // Create params with empty vault - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: emptyVault, - validatorsRegistryRoot: validRegistryRoot, - validators: '', - proof: new bytes32[](0), - proofFlags: new bool[](0), - proofIndexes: new uint256[](0) - }); - - // Test with empty vault - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INSUFFICIENT_ASSETS)); - assertEq(blockNumber, block.number); - } - - function testCheckDepositDataRoot_InvalidValidatorsCount() public view { - // Create valid validator data - bytes memory validators = new bytes(184); // Valid length for one validator - - // Create params with empty proof indexes - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: vault, - validatorsRegistryRoot: validRegistryRoot, - validators: validators, - proof: new bytes32[](1), - proofFlags: new bool[](1), - proofIndexes: new uint256[](0) // Empty proof indexes - }); - - // Test with empty proof indexes - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_COUNT)); - assertEq(blockNumber, block.number); - } - - function testCheckDepositDataRoot_InvalidValidatorsLength() public view { - // Create params with invalid validator length - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: vault, - validatorsRegistryRoot: validRegistryRoot, - validators: '', - proof: new bytes32[](1), - proofFlags: new bool[](1), - proofIndexes: new uint256[](1) - }); - - // Test with invalid validator length - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_LENGTH)); - assertEq(blockNumber, block.number); - } - - function testCheckDepositDataRoot_ValidatorsManager() public { - // Create a vault with a custom validators manager - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address customVault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - _depositToVault(customVault, 33 ether, user, customVault); - _collateralizeEthVault(address(customVault)); - - // Set a custom validators manager - address customManager = makeAddr('customManager'); - vm.prank(admin); - IVaultValidators(customVault).setValidatorsManager(customManager); - - // Create params - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: customVault, - validatorsRegistryRoot: validRegistryRoot, - validators: '', - proof: new bytes32[](0), - proofFlags: new bool[](0), - proofIndexes: new uint256[](0) - }); - - // Test - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // Verify result - assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_MANAGER)); - assertEq(blockNumber, block.number); - } - - function testCheckDepositDataRoot_InvalidProof() public { - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address v1Vault = _createV1EthVault(admin, initParams, false); - _depositToVault(v1Vault, 33 ether, user, user); - - // We need to be very precise with the validator data structure - // V2 validator has length of 184 bytes (48 + 96 + 32 + 8) - uint256 validatorLength = 184; - - // We'll create data for exactly one validator - bytes memory validators = new bytes(validatorLength); - for (uint i = 0; i < validators.length; i++) { - validators[i] = 0x01; // Non-zero values + // Test contracts + ForkContracts public contracts; + EthValidatorsChecker public validatorsChecker; + address public vault; + address public emptyVault; + address public admin; + address public user; + bytes32 public validRegistryRoot; + + function setUp() public { + // Setup fork and contracts + contracts = _activateEthereumFork(); + + // Deploy a fresh EthValidatorsChecker + validatorsChecker = new EthValidatorsChecker( + address(contracts.validatorsRegistry), + address(contracts.keeper), + address(contracts.vaultsRegistry), + address(_depositDataRegistry) + ); + + // Setup accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + vm.deal(user, 100 ether); + + // Create and prepare a vault with sufficient funds + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + vault = _createVault(VaultType.EthVault, admin, initParams, false); + _depositToVault(vault, 33 ether, user, vault); // Deposit enough for 1 validator + _collateralizeEthVault(address(vault)); + + // Create another vault without sufficient funds + emptyVault = _createVault(VaultType.EthVault, admin, initParams, false); + + // Get valid registry root + validRegistryRoot = contracts.validatorsRegistry.get_deposit_root(); } - // Set deposit data root for the vault - bytes32 fakeRoot = keccak256('fake_root'); - vm.prank(IVaultValidatorsV1(v1Vault).keysManager()); - IVaultValidatorsV1(v1Vault).setValidatorsRoot(fakeRoot); - - // Create a valid-looking proof structure - bytes32[] memory proof = new bytes32[](1); - proof[0] = bytes32(uint256(1)); // Invalid proof data - - // We need exactly one proof index to match our one validator - uint256[] memory proofIndexes = new uint256[](1); - proofIndexes[0] = 0; // First validator - - bool[] memory proofFlags = new bool[](1); - proofFlags[0] = true; - - // Create params with configurations that should reach proof validation - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: v1Vault, - validatorsRegistryRoot: validRegistryRoot, - validators: validators, - proof: proof, - proofFlags: proofFlags, - proofIndexes: proofIndexes - }); - - // Test with invalid proof - vm.expectRevert(abi.encodeWithSignature('MerkleProofInvalidMultiproof()')); - validatorsChecker.checkDepositDataRoot(params); - } - - // Test for V1 vault backward compatibility - function testDepositDataRoot_OldVaultFormat() public { - // Create a vault with previous version (for testing backwards compatibility) - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - // Create a V1 vault or mock one - address v1Vault = _createPrevVersionVault(VaultType.EthVault, admin, initParams, false); - _depositToVault(v1Vault, 33 ether, user, v1Vault); - _collateralizeEthVault(address(v1Vault)); - - // Create basic params for V1 vault - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: v1Vault, - validatorsRegistryRoot: validRegistryRoot, - validators: new bytes(184), // Valid length - proof: new bytes32[](1), - proofFlags: new bool[](1), - proofIndexes: new uint256[](1) - }); - - // Test with V1 vault format - (uint256 blockNumber, ) = validatorsChecker.checkDepositDataRoot(params); - - // We expect specific errors based on behavior with V1 vaults - // The actual expected status will depend on the implementation details - // This test mainly ensures the function doesn't revert unexpectedly - assertEq(blockNumber, block.number); - } - - function test_checkValidatorsManagerSignature_Success() public { - // 1. Get the validators manager - address validatorsManager = makeAddr('validatorsManager'); - uint256 validatorsManagerPrivKey = uint256( - keccak256(abi.encodePacked('validatorsManager_key')) - ); - validatorsManager = vm.addr(validatorsManagerPrivKey); - - // 2. Set the validators manager on the vault - vm.prank(admin); - IVaultValidators(vault).setValidatorsManager(validatorsManager); - - // 3. Create validator data (48 bytes pubkey + 96 bytes signature + 32 bytes root + 8 bytes amount) - bytes memory validatorData = new bytes(184); - for (uint i = 0; i < validatorData.length; i++) { - validatorData[i] = bytes1(uint8(i % 256)); // Fill with incremental data + // Tests for checkValidatorsManagerSignature + + function testValidatorsManagerSignature_InvalidRegistryRoot() public view { + // Create invalid root + bytes32 invalidRoot = bytes32(uint256(validRegistryRoot) + 1); + + // Test with invalid root + (uint256 blockNumber, IValidatorsChecker.Status status) = + validatorsChecker.checkValidatorsManagerSignature(vault, invalidRoot, "", ""); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_REGISTRY_ROOT)); + assertEq(blockNumber, block.number); + } + + function testValidatorsManagerSignature_InvalidVault() public { + // Use non-existent vault + address invalidVault = makeAddr("nonVault"); + + // Test with invalid vault + (uint256 blockNumber, IValidatorsChecker.Status status) = + validatorsChecker.checkValidatorsManagerSignature(invalidVault, validRegistryRoot, "", ""); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VAULT)); + assertEq(blockNumber, block.number); } - // 4. Get the domain separator from the contract - // This matches the domain separator calculation in ValidatorsChecker._computeVaultValidatorsDomain - bytes32 domainSeparator = keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes('VaultValidators')), - keccak256('1'), - block.chainid, - vault - ) - ); - - // 5. Create the message hash that matches the contract's implementation - bytes32 validatorsManagerTypeHash = keccak256( - 'VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)' - ); - bytes32 messageHash = keccak256( - abi.encode(validatorsManagerTypeHash, validRegistryRoot, keccak256(validatorData)) - ); - - // 6. Create the EIP-712 typed data hash exactly as the contract does - bytes32 typedDataHash = keccak256(abi.encodePacked('\x19\x01', domainSeparator, messageHash)); - - // 7. Sign the message with validators manager's private key - (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivKey, typedDataHash); - bytes memory signature = abi.encodePacked(r, s, v); - - // 8. Call checkValidatorsManagerSignature - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkValidatorsManagerSignature(vault, validRegistryRoot, validatorData, signature); - - // 9. Verify success result - assertEq( - uint256(status), - uint256(IValidatorsChecker.Status.SUCCEEDED), - 'Signature verification should succeed' - ); - assertEq(blockNumber, block.number); - } - - function test_checkDepositDataRoot_Success() public { - // 1. Set up the vault with the deposit data registry as the validators manager - vm.prank(admin); - IVaultValidators(vault).setValidatorsManager(_depositDataRegistry); - - // 2. Create valid validator data (48 bytes pubkey + 96 bytes signature + 32 bytes root + 8 bytes amount) - bytes memory validator = new bytes(184); - for (uint i = 0; i < validator.length; i++) { - validator[i] = bytes1(uint8(i % 256)); // Fill with incremental data + function testValidatorsManagerSignature_InsufficientAssets() public view { + // Test with empty vault + (uint256 blockNumber, IValidatorsChecker.Status status) = + validatorsChecker.checkValidatorsManagerSignature(emptyVault, validRegistryRoot, "", ""); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INSUFFICIENT_ASSETS)); + assertEq(blockNumber, block.number); } - // 3. Set up the deposit data root - // For a proper test, we need to create a real Merkle root from the validator data - // We'll create a mock Merkle tree with just one validator - - // First, create the leaf node data that will be used in the Merkle tree - // In the actual contract, this is calculated as: - // keccak256(bytes.concat(keccak256(abi.encode(validators[startIndex:endIndex], currentIndex)))) - uint256 validatorIndex = 0; // Current validator index - bytes32 leafNode = keccak256(bytes.concat(keccak256(abi.encode(validator, validatorIndex)))); - - // For a single validator, the Merkle root is the leaf node itself - bytes32 depositDataRoot = leafNode; - - // 4. Set the deposit data root in the registry - vm.prank(IDepositDataRegistry(_depositDataRegistry).getDepositDataManager(vault)); - IDepositDataRegistry(_depositDataRegistry).setDepositDataRoot(vault, depositDataRoot); - - // 5. Mock the deposit data index - vm.mockCall( - _depositDataRegistry, - abi.encodeWithSelector(bytes4(keccak256('depositDataIndexes(address)'))), - abi.encode(validatorIndex) - ); - - // 6. For a single validator Merkle tree, the proof is empty - // But we need to set up the arrays correctly for the function parameters - bytes32[] memory proof = new bytes32[](0); - bool[] memory proofFlags = new bool[](0); - uint256[] memory proofIndexes = new uint256[](1); - proofIndexes[0] = 0; // First (and only) validator - - // 7. Create the parameters for checkDepositDataRoot - IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker - .DepositDataRootCheckParams({ - vault: vault, - validatorsRegistryRoot: validRegistryRoot, - validators: validator, - proof: proof, - proofFlags: proofFlags, - proofIndexes: proofIndexes - }); - - // 8. Call checkDepositDataRoot - (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker - .checkDepositDataRoot(params); - - // 9. Verify success result - assertEq( - uint256(status), - uint256(IValidatorsChecker.Status.SUCCEEDED), - 'Deposit data root verification should succeed' - ); - assertEq(blockNumber, block.number); - } - - function testGetExitQueueCumulativeTickets_EmptyQueue() public view { - // Test with empty exit queue (new vault with no exit requests) - uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(emptyVault); - - // Verify expected values for empty queue - assertEq(cumulativeTickets, 0, 'Cumulative tickets should be 0 for empty vault'); - } - - function testGetExitQueueMissingAssets_EmptyQueue() public view { - // Test with empty exit queue and no pending assets - uint256 targetCumulativeTickets = 0; - uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( - emptyVault, - 0, // No pending assets - targetCumulativeTickets - ); - - // Verify expected values for empty queue - assertEq(missingAssets, 0, 'Missing assets should be 0 for empty queue with 0 target tickets'); - } - - function testGetExitQueueMissingAssets_WithPendingAssets() public { - // Setup: deposit funds and enter exit queue - _depositToVault(vault, 5 ether, user, user); - vm.deal(vault, 0); // Empty the vault balance - - // Enter exit queue with some shares - uint256 sharesToExit = IVaultState(vault).convertToShares(1 ether); - vm.prank(user); - IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); - - // Get current cumulative tickets - uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); - assertGt( - cumulativeTickets, - 0, - 'Cumulative tickets should be non-zero after entering exit queue' - ); - - // Test with no pending assets - uint256 missingAssetsNoPending = validatorsChecker.getExitQueueMissingAssets( - vault, - 0, // No pending assets - cumulativeTickets - ); - - // Test with some pending assets - uint256 pendingAssets = 0.5 ether; - uint256 missingAssetsWithPending = validatorsChecker.getExitQueueMissingAssets( - vault, - pendingAssets, - cumulativeTickets - ); - - // Pending assets should reduce missing assets - assertGt( - missingAssetsNoPending, - missingAssetsWithPending, - 'Pending assets should reduce missing assets' - ); - } - - function testGetExitQueueMissingAssets_WithMultipleExits() public { - // Setup multiple exit queue entries - _depositToVault(vault, 10 ether, user, user); - - // Enter exit queue with different amounts - uint256 user1Shares = IVaultState(vault).convertToShares(2 ether); - uint256 user2Shares = IVaultState(vault).convertToShares(3 ether); - - vm.startPrank(user); - IVaultEnterExit(vault).enterExitQueue(user1Shares, user); - IVaultEnterExit(vault).enterExitQueue(user2Shares, user); - vm.stopPrank(); - - // Get cumulative tickets - uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); - - // Empty the vault balance to force missing assets - vm.deal(vault, 0); - - // Get initial missing assets - uint256 initialMissingAssets = validatorsChecker.getExitQueueMissingAssets( - vault, - 0, // No pending assets - cumulativeTickets - ); - - // Add pending assets and check changes - uint256 pendingAssets = 4 ether; - uint256 updatedMissingAssets = validatorsChecker.getExitQueueMissingAssets( - vault, - pendingAssets, - cumulativeTickets - ); - - // Verify missing assets decrease with pending assets - assertLt( - updatedMissingAssets, - initialMissingAssets, - 'Missing assets should decrease with pending assets' - ); - } - - function testGetExitQueueMissingAssets_WithExcessPendingAssets() public { - // Setup: deposit and enter exit queue - _depositToVault(vault, 5 ether, user, user); - - uint256 sharesToExit = IVaultState(vault).convertToShares(1 ether); - vm.prank(user); - IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); - - // Get cumulative tickets - uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); - - // Get missing assets with no pending assets - uint256 missingAssetsBefore = validatorsChecker.getExitQueueMissingAssets( - vault, - 0, - cumulativeTickets - ); - - // Test with large amount of pending assets (more than missing) - uint256 excessPendingAssets = missingAssetsBefore * 2; - uint256 missingAssetsAfter = validatorsChecker.getExitQueueMissingAssets( - vault, - excessPendingAssets, - cumulativeTickets - ); - - // No missing assets with excess pending assets - assertEq(missingAssetsAfter, 0, 'No missing assets with excess pending assets'); - } - - function testGetExitQueueMissingAssets_ZeroAvailableAssets() public { - // Setup: Create exit queue entries but make available assets zero - _depositToVault(vault, 5 ether, user, user); - - uint256 sharesToExit = IVaultState(vault).convertToShares(2 ether); - vm.prank(user); - IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); - - // Get cumulative tickets - uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); - - // Set vault balance to zero - vm.deal(vault, 0); - - // With zero available assets and no pending assets, missing assets should be non-zero - uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( - vault, - 0, // No pending assets - cumulativeTickets - ); - - assertGt(missingAssets, 0, 'Missing assets should be non-zero with no available assets'); - } - - function testUpdateVaultState() public { - // Setup: Create rewards for the vault - int160 totalReward = int160(int256(0.5 ether)); - uint160 unlockedMevReward = 0.1 ether; - - uint256 totalAssetsBefore = IEthVault(vault).totalAssets(); - - // Create harvest params with the setup rewards - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - totalReward, - unlockedMevReward - ); - - // Call updateVaultState via the validatorsChecker - validatorsChecker.updateVaultState(vault, harvestParams); - - assertEq( - IEthVault(vault).totalAssets(), - totalAssetsBefore + 0.5 ether, - "Balance shouldn't change on second update" - ); - } + function testValidatorsManagerSignature_InvalidSignature() public view { + // Get valid registry root + bytes32 validRoot = contracts.validatorsRegistry.get_deposit_root(); + + // Generate validator data + bytes memory validatorData = new bytes(184); // Valid length for one validator + + // Generate invalid signature + bytes memory invalidSignature = "0xdeadbeef"; + + // Check with invalid signature + (uint256 blockNumber, IValidatorsChecker.Status status) = + validatorsChecker.checkValidatorsManagerSignature(vault, validRoot, validatorData, invalidSignature); + + // Verify expected result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_SIGNATURE)); + assertEq(blockNumber, block.number); + } + + // Tests for checkDepositDataRoot + + function testCheckDepositDataRoot_InvalidRegistryRoot() public view { + // Create invalid root + bytes32 invalidRoot = bytes32(uint256(validRegistryRoot) + 1); + + // Create params with invalid root + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: invalidRoot, + validators: "", + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test with invalid root + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_REGISTRY_ROOT)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidVault() public { + // Use non-existent vault + address invalidVault = makeAddr("nonVault"); + + // Create params with invalid vault + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: invalidVault, + validatorsRegistryRoot: validRegistryRoot, + validators: "", + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test with invalid vault + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VAULT)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InsufficientAssets() public view { + // Create params with empty vault + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: emptyVault, + validatorsRegistryRoot: validRegistryRoot, + validators: "", + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test with empty vault + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INSUFFICIENT_ASSETS)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidValidatorsCount() public view { + // Create valid validator data + bytes memory validators = new bytes(184); // Valid length for one validator + + // Create params with empty proof indexes + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: validRegistryRoot, + validators: validators, + proof: new bytes32[](1), + proofFlags: new bool[](1), + proofIndexes: new uint256[](0) // Empty proof indexes + }); + + // Test with empty proof indexes + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_COUNT)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidValidatorsLength() public view { + // Create params with invalid validator length + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: validRegistryRoot, + validators: "", + proof: new bytes32[](1), + proofFlags: new bool[](1), + proofIndexes: new uint256[](1) + }); + + // Test with invalid validator length + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_LENGTH)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_ValidatorsManager() public { + // Create a vault with a custom validators manager + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address customVault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + _depositToVault(customVault, 33 ether, user, customVault); + _collateralizeEthVault(address(customVault)); + + // Set a custom validators manager + address customManager = makeAddr("customManager"); + vm.prank(admin); + IVaultValidators(customVault).setValidatorsManager(customManager); + + // Create params + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: customVault, + validatorsRegistryRoot: validRegistryRoot, + validators: "", + proof: new bytes32[](0), + proofFlags: new bool[](0), + proofIndexes: new uint256[](0) + }); + + // Test + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // Verify result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.INVALID_VALIDATORS_MANAGER)); + assertEq(blockNumber, block.number); + } + + function testCheckDepositDataRoot_InvalidProof() public { + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address v1Vault = _createV1EthVault(admin, initParams, false); + _depositToVault(v1Vault, 33 ether, user, user); + + // We need to be very precise with the validator data structure + // V2 validator has length of 184 bytes (48 + 96 + 32 + 8) + uint256 validatorLength = 184; + + // We'll create data for exactly one validator + bytes memory validators = new bytes(validatorLength); + for (uint256 i = 0; i < validators.length; i++) { + validators[i] = 0x01; // Non-zero values + } + + // Set deposit data root for the vault + bytes32 fakeRoot = keccak256("fake_root"); + vm.prank(IVaultValidatorsV1(v1Vault).keysManager()); + IVaultValidatorsV1(v1Vault).setValidatorsRoot(fakeRoot); + + // Create a valid-looking proof structure + bytes32[] memory proof = new bytes32[](1); + proof[0] = bytes32(uint256(1)); // Invalid proof data + + // We need exactly one proof index to match our one validator + uint256[] memory proofIndexes = new uint256[](1); + proofIndexes[0] = 0; // First validator + + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + // Create params with configurations that should reach proof validation + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: v1Vault, + validatorsRegistryRoot: validRegistryRoot, + validators: validators, + proof: proof, + proofFlags: proofFlags, + proofIndexes: proofIndexes + }); + + // Test with invalid proof + vm.expectRevert(abi.encodeWithSignature("MerkleProofInvalidMultiproof()")); + validatorsChecker.checkDepositDataRoot(params); + } + + // Test for V1 vault backward compatibility + function testDepositDataRoot_OldVaultFormat() public { + // Create a vault with previous version (for testing backwards compatibility) + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + // Create a V1 vault or mock one + address v1Vault = _createPrevVersionVault(VaultType.EthVault, admin, initParams, false); + _depositToVault(v1Vault, 33 ether, user, v1Vault); + _collateralizeEthVault(address(v1Vault)); + + // Create basic params for V1 vault + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: v1Vault, + validatorsRegistryRoot: validRegistryRoot, + validators: new bytes(184), // Valid length + proof: new bytes32[](1), + proofFlags: new bool[](1), + proofIndexes: new uint256[](1) + }); + + // Test with V1 vault format + (uint256 blockNumber,) = validatorsChecker.checkDepositDataRoot(params); + + // We expect specific errors based on behavior with V1 vaults + // The actual expected status will depend on the implementation details + // This test mainly ensures the function doesn't revert unexpectedly + assertEq(blockNumber, block.number); + } + + function test_checkValidatorsManagerSignature_Success() public { + // 1. Get the validators manager + address validatorsManager = makeAddr("validatorsManager"); + uint256 validatorsManagerPrivKey = uint256(keccak256(abi.encodePacked("validatorsManager_key"))); + validatorsManager = vm.addr(validatorsManagerPrivKey); + + // 2. Set the validators manager on the vault + vm.prank(admin); + IVaultValidators(vault).setValidatorsManager(validatorsManager); + + // 3. Create validator data (48 bytes pubkey + 96 bytes signature + 32 bytes root + 8 bytes amount) + bytes memory validatorData = new bytes(184); + for (uint256 i = 0; i < validatorData.length; i++) { + validatorData[i] = bytes1(uint8(i % 256)); // Fill with incremental data + } + + // 4. Get the domain separator from the contract + // This matches the domain separator calculation in ValidatorsChecker._computeVaultValidatorsDomain + bytes32 domainSeparator = keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes("VaultValidators")), + keccak256("1"), + block.chainid, + vault + ) + ); + + // 5. Create the message hash that matches the contract's implementation + bytes32 validatorsManagerTypeHash = + keccak256("VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)"); + bytes32 messageHash = + keccak256(abi.encode(validatorsManagerTypeHash, validRegistryRoot, keccak256(validatorData))); + + // 6. Create the EIP-712 typed data hash exactly as the contract does + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, messageHash)); + + // 7. Sign the message with validators manager's private key + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivKey, typedDataHash); + bytes memory signature = abi.encodePacked(r, s, v); + + // 8. Call checkValidatorsManagerSignature + (uint256 blockNumber, IValidatorsChecker.Status status) = + validatorsChecker.checkValidatorsManagerSignature(vault, validRegistryRoot, validatorData, signature); + + // 9. Verify success result + assertEq(uint256(status), uint256(IValidatorsChecker.Status.SUCCEEDED), "Signature verification should succeed"); + assertEq(blockNumber, block.number); + } + + function test_checkDepositDataRoot_Success() public { + // 1. Set up the vault with the deposit data registry as the validators manager + vm.prank(admin); + IVaultValidators(vault).setValidatorsManager(_depositDataRegistry); + + // 2. Create valid validator data (48 bytes pubkey + 96 bytes signature + 32 bytes root + 8 bytes amount) + bytes memory validator = new bytes(184); + for (uint256 i = 0; i < validator.length; i++) { + validator[i] = bytes1(uint8(i % 256)); // Fill with incremental data + } + + // 3. Set up the deposit data root + // For a proper test, we need to create a real Merkle root from the validator data + // We'll create a mock Merkle tree with just one validator + + // First, create the leaf node data that will be used in the Merkle tree + // In the actual contract, this is calculated as: + // keccak256(bytes.concat(keccak256(abi.encode(validators[startIndex:endIndex], currentIndex)))) + uint256 validatorIndex = 0; // Current validator index + bytes32 leafNode = keccak256(bytes.concat(keccak256(abi.encode(validator, validatorIndex)))); + + // For a single validator, the Merkle root is the leaf node itself + bytes32 depositDataRoot = leafNode; + + // 4. Set the deposit data root in the registry + vm.prank(IDepositDataRegistry(_depositDataRegistry).getDepositDataManager(vault)); + IDepositDataRegistry(_depositDataRegistry).setDepositDataRoot(vault, depositDataRoot); + + // 5. Mock the deposit data index + vm.mockCall( + _depositDataRegistry, + abi.encodeWithSelector(bytes4(keccak256("depositDataIndexes(address)"))), + abi.encode(validatorIndex) + ); + + // 6. For a single validator Merkle tree, the proof is empty + // But we need to set up the arrays correctly for the function parameters + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + uint256[] memory proofIndexes = new uint256[](1); + proofIndexes[0] = 0; // First (and only) validator + + // 7. Create the parameters for checkDepositDataRoot + IValidatorsChecker.DepositDataRootCheckParams memory params = IValidatorsChecker.DepositDataRootCheckParams({ + vault: vault, + validatorsRegistryRoot: validRegistryRoot, + validators: validator, + proof: proof, + proofFlags: proofFlags, + proofIndexes: proofIndexes + }); + + // 8. Call checkDepositDataRoot + (uint256 blockNumber, IValidatorsChecker.Status status) = validatorsChecker.checkDepositDataRoot(params); + + // 9. Verify success result + assertEq( + uint256(status), + uint256(IValidatorsChecker.Status.SUCCEEDED), + "Deposit data root verification should succeed" + ); + assertEq(blockNumber, block.number); + } + + function testGetExitQueueCumulativeTickets_EmptyQueue() public view { + // Test with empty exit queue (new vault with no exit requests) + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(emptyVault); + + // Verify expected values for empty queue + assertEq(cumulativeTickets, 0, "Cumulative tickets should be 0 for empty vault"); + } + + function testGetExitQueueMissingAssets_EmptyQueue() public view { + // Test with empty exit queue and no pending assets + uint256 targetCumulativeTickets = 0; + uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( + emptyVault, + 0, // No pending assets + targetCumulativeTickets + ); + + // Verify expected values for empty queue + assertEq(missingAssets, 0, "Missing assets should be 0 for empty queue with 0 target tickets"); + } + + function testGetExitQueueMissingAssets_WithPendingAssets() public { + // Setup: deposit funds and enter exit queue + _depositToVault(vault, 5 ether, user, user); + vm.deal(vault, 0); // Empty the vault balance + + // Enter exit queue with some shares + uint256 sharesToExit = IVaultState(vault).convertToShares(1 ether); + vm.prank(user); + IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); + + // Get current cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + assertGt(cumulativeTickets, 0, "Cumulative tickets should be non-zero after entering exit queue"); + + // Test with no pending assets + uint256 missingAssetsNoPending = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, // No pending assets + cumulativeTickets + ); + + // Test with some pending assets + uint256 pendingAssets = 0.5 ether; + uint256 missingAssetsWithPending = + validatorsChecker.getExitQueueMissingAssets(vault, pendingAssets, cumulativeTickets); + + // Pending assets should reduce missing assets + assertGt(missingAssetsNoPending, missingAssetsWithPending, "Pending assets should reduce missing assets"); + } + + function testGetExitQueueMissingAssets_WithMultipleExits() public { + // Setup multiple exit queue entries + _depositToVault(vault, 10 ether, user, user); + + // Enter exit queue with different amounts + uint256 user1Shares = IVaultState(vault).convertToShares(2 ether); + uint256 user2Shares = IVaultState(vault).convertToShares(3 ether); + + vm.startPrank(user); + IVaultEnterExit(vault).enterExitQueue(user1Shares, user); + IVaultEnterExit(vault).enterExitQueue(user2Shares, user); + vm.stopPrank(); + + // Get cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + + // Empty the vault balance to force missing assets + vm.deal(vault, 0); + + // Get initial missing assets + uint256 initialMissingAssets = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, // No pending assets + cumulativeTickets + ); + + // Add pending assets and check changes + uint256 pendingAssets = 4 ether; + uint256 updatedMissingAssets = + validatorsChecker.getExitQueueMissingAssets(vault, pendingAssets, cumulativeTickets); + + // Verify missing assets decrease with pending assets + assertLt(updatedMissingAssets, initialMissingAssets, "Missing assets should decrease with pending assets"); + } + + function testGetExitQueueMissingAssets_WithExcessPendingAssets() public { + // Setup: deposit and enter exit queue + _depositToVault(vault, 5 ether, user, user); + + uint256 sharesToExit = IVaultState(vault).convertToShares(1 ether); + vm.prank(user); + IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); + + // Get cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + + // Get missing assets with no pending assets + uint256 missingAssetsBefore = validatorsChecker.getExitQueueMissingAssets(vault, 0, cumulativeTickets); + + // Test with large amount of pending assets (more than missing) + uint256 excessPendingAssets = missingAssetsBefore * 2; + uint256 missingAssetsAfter = + validatorsChecker.getExitQueueMissingAssets(vault, excessPendingAssets, cumulativeTickets); + + // No missing assets with excess pending assets + assertEq(missingAssetsAfter, 0, "No missing assets with excess pending assets"); + } + + function testGetExitQueueMissingAssets_ZeroAvailableAssets() public { + // Setup: Create exit queue entries but make available assets zero + _depositToVault(vault, 5 ether, user, user); + + uint256 sharesToExit = IVaultState(vault).convertToShares(2 ether); + vm.prank(user); + IVaultEnterExit(vault).enterExitQueue(sharesToExit, user); + + // Get cumulative tickets + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(vault); + + // Set vault balance to zero + vm.deal(vault, 0); + + // With zero available assets and no pending assets, missing assets should be non-zero + uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( + vault, + 0, // No pending assets + cumulativeTickets + ); + + assertGt(missingAssets, 0, "Missing assets should be non-zero with no available assets"); + } + + function testUpdateVaultState() public { + // Setup: Create rewards for the vault + int160 totalReward = int160(int256(0.5 ether)); + uint160 unlockedMevReward = 0.1 ether; + + uint256 totalAssetsBefore = IEthVault(vault).totalAssets(); + + // Create harvest params with the setup rewards + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), totalReward, unlockedMevReward); + + // Call updateVaultState via the validatorsChecker + validatorsChecker.updateVaultState(vault, harvestParams); + + assertEq( + IEthVault(vault).totalAssets(), totalAssetsBefore + 0.5 ether, "Balance shouldn't change on second update" + ); + } } diff --git a/test/EthVault.t.sol b/test/EthVault.t.sol index 6f8567ac..10e457af 100644 --- a/test/EthVault.t.sol +++ b/test/EthVault.t.sol @@ -1,444 +1,406 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Address} from '@openzeppelin/contracts/utils/Address.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; interface IVaultStateV4 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract EthVaultTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - - address public sender; - address public receiver; - address public admin; - address public referrer; - address public validatorsManager; - uint256 public exitingAssets; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - referrer = makeAddr('referrer'); - validatorsManager = makeAddr('validatorsManager'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(admin, 100 ether); - vm.deal(validatorsManager, 1 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Set validatorsManager for the vault - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = IEthVault(vault).getExitQueueData(); - exitingAssets = - totalExitingAssets + - IEthVault(vault).convertToAssets(queuedShares) + - vaultAddr.balance; - } - - function test_cannotInitializeTwice() public { - // Try to initialize the vault again, which should fail - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_deploysCorrectly() public { - // Create a new vault to test deployment - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('EthVaultTest_test_deploysCorrectly'); - address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - _stopSnapshotGas(); - - EthVault newVault = EthVault(payable(vaultAddr)); - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = newVault.getExitQueueData(); - - // Verify the vault was deployed correctly - assertEq(newVault.vaultId(), keccak256('EthVault')); - assertEq(newVault.version(), 5); - assertEq(newVault.admin(), admin); - assertEq(newVault.capacity(), 1000 ether); - assertEq(newVault.feePercent(), 1000); - assertEq(newVault.feeRecipient(), admin); - assertEq(newVault.validatorsManager(), _depositDataRegistry); - assertEq(queuedShares, 0); - assertEq(totalTickets, 0); - assertEq(unclaimedAssets, 0); - assertEq(newVault.totalShares(), _securityDeposit); - assertEq(newVault.totalAssets(), _securityDeposit); - assertEq(totalExitingAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(newVault.validatorsManagerNonce(), 0); - } - - function test_upgradesCorrectly() public { - // Create a v4 vault (previous version) - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createPrevVersionVault(VaultType.EthVault, admin, initParams, false); - EthVault prevVault = EthVault(payable(vaultAddr)); - - // Deposit some ETH - _depositToVault(address(prevVault), exitingAssets + 32 ether, sender, sender); - - // Register a validator - _registerEthValidator(address(prevVault), 32 ether, true); - - // Enter exit queue with some shares - vm.prank(sender); - prevVault.enterExitQueue(10 ether, sender); - - // Record state before upgrade - uint256 totalSharesBefore = prevVault.totalShares(); - uint256 totalAssetsBefore = prevVault.totalAssets(); - uint256 senderBalanceBefore = prevVault.getShares(sender); - uint256 queuedSharesBefore = IVaultStateV4(address(prevVault)).queuedShares(); - uint256 totalExitingAssetsBefore = IVaultStateV4(address(prevVault)).totalExitingAssets(); - - // Verify current version - assertEq(prevVault.vaultId(), keccak256('EthVault')); - assertEq(prevVault.version(), 4); - - // Upgrade the vault - _startSnapshotGas('EthVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.EthVault, address(prevVault)); - _stopSnapshotGas(); - - // Check that the vault was upgraded correctly - (uint128 queuedShares, , uint128 totalExitingAssets, , ) = prevVault.getExitQueueData(); - assertEq(prevVault.vaultId(), keccak256('EthVault')); - assertEq(prevVault.version(), 5); - assertEq(prevVault.admin(), admin); - assertEq(prevVault.capacity(), 1000 ether); - assertEq(prevVault.feePercent(), 1000); - assertEq(prevVault.feeRecipient(), admin); - assertEq(prevVault.validatorsManager(), _depositDataRegistry); - - // State should be preserved - assertEq(prevVault.totalShares(), totalSharesBefore); - assertEq(prevVault.totalAssets(), totalAssetsBefore); - assertEq(prevVault.validatorsManagerNonce(), 0); - assertEq(prevVault.getShares(sender), senderBalanceBefore); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - } - - function test_exitQueue_works() public { - // Collateralize the vault first - _collateralizeEthVault(address(vault)); - - // Deposit ETH into the vault - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, sender, sender); - - // Get initial state - uint256 senderSharesBefore = vault.getShares(sender); - ( - uint128 queuedSharesBefore, - uint128 unclaimedAssetsBefore, - , - uint128 totalExitingAssetsBefore, - uint256 totalTicketsBefore - ) = vault.getExitQueueData(); - - // Amount to exit with - uint256 exitAmount = senderSharesBefore / 2; - - // Enter exit queue - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(sender); - _startSnapshotGas('EthVaultTest_test_exitQueue_works'); - uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); - _stopSnapshotGas(); - - ( - uint128 queuedSharesAfter, - uint128 unclaimedAssetsAfter, - , - uint128 totalExitingAssetsAfter, - uint256 totalTicketsAfter - ) = vault.getExitQueueData(); - - // Check state after entering exit queue - assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, 'Sender shares not reduced'); - assertEq(queuedSharesAfter, queuedSharesBefore + exitAmount, 'Queued shares not increased'); - assertEq(unclaimedAssetsAfter, unclaimedAssetsBefore, 'Unclaimed assets should not change'); - assertEq( - totalExitingAssetsAfter, - totalExitingAssetsBefore, - 'Total exiting assets should not change' - ); - assertEq(totalTicketsAfter, totalTicketsBefore, 'Total tickets should not change'); - - queuedSharesBefore = queuedSharesAfter; - unclaimedAssetsBefore = unclaimedAssetsAfter; - totalExitingAssetsBefore = totalExitingAssetsAfter; - totalTicketsBefore = totalTicketsAfter; - - // Process exit queue by updating state - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - (queuedSharesAfter, unclaimedAssetsAfter, , totalExitingAssetsAfter, totalTicketsAfter) = vault - .getExitQueueData(); - assertLt( - queuedSharesAfter, - queuedSharesBefore, - 'Queued shares should be reduced after processing exit queue' - ); - assertGt( - unclaimedAssetsAfter, - unclaimedAssetsBefore, - 'Unclaimed assets should increase after processing exit queue' - ); - assertEq( - totalExitingAssetsAfter, - totalExitingAssetsBefore, - 'Total exiting assets should not change after processing exit queue' - ); - assertGt( - totalTicketsAfter, - totalTicketsBefore, - 'Total tickets should increase after processing exit queue' - ); - - // Check that position can be found in exit queue - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Wait for the claiming delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Verify exited assets can be calculated - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault - .calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); - - // Assets should be exited and claimable - assertApproxEqAbs(leftTickets, 0, 1, 'All tickets should be processed'); - assertGt(exitedTickets, 0, 'No tickets exited'); - assertGt(exitedAssets, 0, 'No assets exited'); - - // Claim exited assets - uint256 receiverBalanceBefore = receiver.balance; - - vm.prank(receiver); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - - // Verify receiver got their ETH - uint256 receiverBalanceAfter = receiver.balance; - assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver didn't get ETH"); - assertEq( - receiverBalanceAfter, - receiverBalanceBefore + exitedAssets, - 'Incorrect amount received' - ); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('EthVault'); - assertEq(vault.vaultId(), expectedId, 'Invalid vault ID'); - } - - function test_vaultVersion() public view { - assertEq(vault.version(), 5, 'Invalid vault version'); - } - - function test_withdrawValidator_validatorsManager() public { - // First deposit and register a validator - _depositToVault(address(vault), 40 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // Execute withdrawal as validatorsManager - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - - vm.prank(validatorsManager); - _startSnapshotGas('EthVaultTest_test_withdrawValidator_validatorsManager'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - - // Verify no error - test passes if the transaction completes successfully - } - - function test_withdrawValidator_osTokenRedeemer() public { - // Set osToken redeemer - address osTokenRedeemer = makeAddr('osTokenRedeemer'); - vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); - contracts.osTokenConfig.setRedeemer(osTokenRedeemer); - - // Fund the redeemer account - uint256 withdrawFee = 0.1 ether; - vm.deal(osTokenRedeemer, withdrawFee); - - // First deposit and register a validator - _depositToVault(address(vault), 40 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // Execute withdrawal as osTokenRedeemer - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - - vm.prank(osTokenRedeemer); - _startSnapshotGas('EthVaultTest_test_withdrawValidator_osTokenRedeemer'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - - // Verify no error - test passes if the transaction completes successfully - } - - function test_withdrawValidator_unknown() public { - // Create an unknown address - address unknown = makeAddr('unknown'); - - // Fund the unknown account - uint256 withdrawFee = 0.1 ether; - vm.deal(unknown, withdrawFee); - - // First deposit and register a validator - _depositToVault(address(vault), 40 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // Execute withdrawal as an unknown address - should fail - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - - vm.prank(unknown); - _startSnapshotGas('EthVaultTest_test_withdrawValidator_unknown'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_depositAndMintOsToken() public { - // Collateralize the vault first - _collateralizeEthVault(address(vault)); - - // Set up parameters - uint256 depositAmount = 10 ether; - uint256 shares = vault.convertToShares(depositAmount); - uint256 osTokenSharesToMint = 5 ether; // Half the deposit - - // Perform depositAndMintOsToken - vm.prank(sender); - _startSnapshotGas('EthVaultTest_test_depositAndMintOsToken'); - uint256 mintedAssets = vault.depositAndMintOsToken{value: depositAmount}( - sender, - osTokenSharesToMint, - referrer - ); - _stopSnapshotGas(); - - // Verify sender got vault shares - assertApproxEqAbs(vault.getShares(sender), shares, 1, 'Incorrect amount of vault shares'); - - // Verify osToken position - uint128 osTokenShares = vault.osTokenPositions(sender); - assertEq(osTokenShares, osTokenSharesToMint, 'Incorrect amount of osToken shares'); - assertGt(mintedAssets, 0, 'No osToken assets minted'); - } - - function test_updateStateAndDepositAndMintOsToken() public { - // Collateralize the vault first - _collateralizeEthVault(address(vault)); - - // Set up parameters - uint256 depositAssets = 10 ether; - uint256 osTokenAssetsToMint = 5 ether; // Half the deposit - - uint256 depositShares = vault.convertToShares(depositAssets); - uint256 osTokenSharesToMint = vault.convertToShares(osTokenAssetsToMint); - - // Set up harvest params - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Perform updateStateAndDepositAndMintOsToken - vm.prank(sender); - _startSnapshotGas('EthVaultTest_test_updateStateAndDepositAndMintOsToken'); - uint256 mintedAssets = vault.updateStateAndDepositAndMintOsToken{value: depositAssets}( - sender, - osTokenSharesToMint, - referrer, - harvestParams - ); - _stopSnapshotGas(); - - // Verify sender got vault shares - assertApproxEqAbs( - vault.getShares(sender), - depositShares, - 1, - 'Incorrect amount of vault shares' - ); - - // Verify osToken position - uint128 osTokenShares = vault.osTokenPositions(sender); - assertEq(osTokenShares, osTokenSharesToMint, 'Incorrect amount of osToken shares'); - assertGt(mintedAssets, 0, 'No osToken assets minted'); - } - - function test_fallbackDeposit() public { - // Test direct ETH transfer to vault - uint256 depositAmount = 5 ether; - uint256 depositShares = vault.convertToShares(depositAmount); - uint256 senderBalanceBefore = vault.getShares(sender); - - vm.prank(sender); - _startSnapshotGas('EthVaultTest_test_fallbackDeposit'); - Address.sendValue(payable(address(vault)), depositAmount); - _stopSnapshotGas(); - - // Verify sender got vault shares - assertApproxEqAbs( - vault.getShares(sender), - senderBalanceBefore + depositShares, - 1, - 'Shares not increased' - ); - } + ForkContracts public contracts; + EthVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + uint256 public exitingAssets; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + referrer = makeAddr("referrer"); + validatorsManager = makeAddr("validatorsManager"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(validatorsManager, 1 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Set validatorsManager for the vault + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = IEthVault(vault).getExitQueueData(); + exitingAssets = totalExitingAssets + IEthVault(vault).convertToAssets(queuedShares) + vaultAddr.balance; + } + + function test_cannotInitializeTwice() public { + // Try to initialize the vault again, which should fail + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_deploysCorrectly() public { + // Create a new vault to test deployment + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("EthVaultTest_test_deploysCorrectly"); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + _stopSnapshotGas(); + + EthVault newVault = EthVault(payable(vaultAddr)); + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = newVault.getExitQueueData(); + + // Verify the vault was deployed correctly + assertEq(newVault.vaultId(), keccak256("EthVault")); + assertEq(newVault.version(), 5); + assertEq(newVault.admin(), admin); + assertEq(newVault.capacity(), 1000 ether); + assertEq(newVault.feePercent(), 1000); + assertEq(newVault.feeRecipient(), admin); + assertEq(newVault.validatorsManager(), _depositDataRegistry); + assertEq(queuedShares, 0); + assertEq(totalTickets, 0); + assertEq(unclaimedAssets, 0); + assertEq(newVault.totalShares(), _securityDeposit); + assertEq(newVault.totalAssets(), _securityDeposit); + assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(newVault.validatorsManagerNonce(), 0); + } + + function test_upgradesCorrectly() public { + // Create a v4 vault (previous version) + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createPrevVersionVault(VaultType.EthVault, admin, initParams, false); + EthVault prevVault = EthVault(payable(vaultAddr)); + + // Deposit some ETH + _depositToVault(address(prevVault), exitingAssets + 32 ether, sender, sender); + + // Register a validator + _registerEthValidator(address(prevVault), 32 ether, true); + + // Enter exit queue with some shares + vm.prank(sender); + prevVault.enterExitQueue(10 ether, sender); + + // Record state before upgrade + uint256 totalSharesBefore = prevVault.totalShares(); + uint256 totalAssetsBefore = prevVault.totalAssets(); + uint256 senderBalanceBefore = prevVault.getShares(sender); + uint256 queuedSharesBefore = IVaultStateV4(address(prevVault)).queuedShares(); + uint256 totalExitingAssetsBefore = IVaultStateV4(address(prevVault)).totalExitingAssets(); + + // Verify current version + assertEq(prevVault.vaultId(), keccak256("EthVault")); + assertEq(prevVault.version(), 4); + + // Upgrade the vault + _startSnapshotGas("EthVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.EthVault, address(prevVault)); + _stopSnapshotGas(); + + // Check that the vault was upgraded correctly + (uint128 queuedShares,, uint128 totalExitingAssets,,) = prevVault.getExitQueueData(); + assertEq(prevVault.vaultId(), keccak256("EthVault")); + assertEq(prevVault.version(), 5); + assertEq(prevVault.admin(), admin); + assertEq(prevVault.capacity(), 1000 ether); + assertEq(prevVault.feePercent(), 1000); + assertEq(prevVault.feeRecipient(), admin); + assertEq(prevVault.validatorsManager(), _depositDataRegistry); + + // State should be preserved + assertEq(prevVault.totalShares(), totalSharesBefore); + assertEq(prevVault.totalAssets(), totalAssetsBefore); + assertEq(prevVault.validatorsManagerNonce(), 0); + assertEq(prevVault.getShares(sender), senderBalanceBefore); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + } + + function test_exitQueue_works() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Deposit ETH into the vault + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, sender, sender); + + // Get initial state + uint256 senderSharesBefore = vault.getShares(sender); + ( + uint128 queuedSharesBefore, + uint128 unclaimedAssetsBefore, + , + uint128 totalExitingAssetsBefore, + uint256 totalTicketsBefore + ) = vault.getExitQueueData(); + + // Amount to exit with + uint256 exitAmount = senderSharesBefore / 2; + + // Enter exit queue + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(sender); + _startSnapshotGas("EthVaultTest_test_exitQueue_works"); + uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); + _stopSnapshotGas(); + + ( + uint128 queuedSharesAfter, + uint128 unclaimedAssetsAfter, + , + uint128 totalExitingAssetsAfter, + uint256 totalTicketsAfter + ) = vault.getExitQueueData(); + + // Check state after entering exit queue + assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, "Sender shares not reduced"); + assertEq(queuedSharesAfter, queuedSharesBefore + exitAmount, "Queued shares not increased"); + assertEq(unclaimedAssetsAfter, unclaimedAssetsBefore, "Unclaimed assets should not change"); + assertEq(totalExitingAssetsAfter, totalExitingAssetsBefore, "Total exiting assets should not change"); + assertEq(totalTicketsAfter, totalTicketsBefore, "Total tickets should not change"); + + queuedSharesBefore = queuedSharesAfter; + unclaimedAssetsBefore = unclaimedAssetsAfter; + totalExitingAssetsBefore = totalExitingAssetsAfter; + totalTicketsBefore = totalTicketsAfter; + + // Process exit queue by updating state + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + (queuedSharesAfter, unclaimedAssetsAfter,, totalExitingAssetsAfter, totalTicketsAfter) = + vault.getExitQueueData(); + assertLt(queuedSharesAfter, queuedSharesBefore, "Queued shares should be reduced after processing exit queue"); + assertGt( + unclaimedAssetsAfter, unclaimedAssetsBefore, "Unclaimed assets should increase after processing exit queue" + ); + assertEq( + totalExitingAssetsAfter, + totalExitingAssetsBefore, + "Total exiting assets should not change after processing exit queue" + ); + assertGt(totalTicketsAfter, totalTicketsBefore, "Total tickets should increase after processing exit queue"); + + // Check that position can be found in exit queue + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Wait for the claiming delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Verify exited assets can be calculated + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = + vault.calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // Assets should be exited and claimable + assertApproxEqAbs(leftTickets, 0, 1, "All tickets should be processed"); + assertGt(exitedTickets, 0, "No tickets exited"); + assertGt(exitedAssets, 0, "No assets exited"); + + // Claim exited assets + uint256 receiverBalanceBefore = receiver.balance; + + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify receiver got their ETH + uint256 receiverBalanceAfter = receiver.balance; + assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver didn't get ETH"); + assertEq(receiverBalanceAfter, receiverBalanceBefore + exitedAssets, "Incorrect amount received"); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("EthVault"); + assertEq(vault.vaultId(), expectedId, "Invalid vault ID"); + } + + function test_vaultVersion() public view { + assertEq(vault.version(), 5, "Invalid vault version"); + } + + function test_withdrawValidator_validatorsManager() public { + // First deposit and register a validator + _depositToVault(address(vault), 40 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // Execute withdrawal as validatorsManager + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(validatorsManager); + _startSnapshotGas("EthVaultTest_test_withdrawValidator_validatorsManager"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_osTokenRedeemer() public { + // Set osToken redeemer + address osTokenRedeemer = makeAddr("osTokenRedeemer"); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + // Fund the redeemer account + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 40 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // Execute withdrawal as osTokenRedeemer + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(osTokenRedeemer); + _startSnapshotGas("EthVaultTest_test_withdrawValidator_osTokenRedeemer"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_unknown() public { + // Create an unknown address + address unknown = makeAddr("unknown"); + + // Fund the unknown account + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 40 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // Execute withdrawal as an unknown address - should fail + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(unknown); + _startSnapshotGas("EthVaultTest_test_withdrawValidator_unknown"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_depositAndMintOsToken() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Set up parameters + uint256 depositAmount = 10 ether; + uint256 shares = vault.convertToShares(depositAmount); + uint256 osTokenSharesToMint = 5 ether; // Half the deposit + + // Perform depositAndMintOsToken + vm.prank(sender); + _startSnapshotGas("EthVaultTest_test_depositAndMintOsToken"); + uint256 mintedAssets = vault.depositAndMintOsToken{value: depositAmount}(sender, osTokenSharesToMint, referrer); + _stopSnapshotGas(); + + // Verify sender got vault shares + assertApproxEqAbs(vault.getShares(sender), shares, 1, "Incorrect amount of vault shares"); + + // Verify osToken position + uint128 osTokenShares = vault.osTokenPositions(sender); + assertEq(osTokenShares, osTokenSharesToMint, "Incorrect amount of osToken shares"); + assertGt(mintedAssets, 0, "No osToken assets minted"); + } + + function test_updateStateAndDepositAndMintOsToken() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Set up parameters + uint256 depositAssets = 10 ether; + uint256 osTokenAssetsToMint = 5 ether; // Half the deposit + + uint256 depositShares = vault.convertToShares(depositAssets); + uint256 osTokenSharesToMint = vault.convertToShares(osTokenAssetsToMint); + + // Set up harvest params + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Perform updateStateAndDepositAndMintOsToken + vm.prank(sender); + _startSnapshotGas("EthVaultTest_test_updateStateAndDepositAndMintOsToken"); + uint256 mintedAssets = vault.updateStateAndDepositAndMintOsToken{value: depositAssets}( + sender, osTokenSharesToMint, referrer, harvestParams + ); + _stopSnapshotGas(); + + // Verify sender got vault shares + assertApproxEqAbs(vault.getShares(sender), depositShares, 1, "Incorrect amount of vault shares"); + + // Verify osToken position + uint128 osTokenShares = vault.osTokenPositions(sender); + assertEq(osTokenShares, osTokenSharesToMint, "Incorrect amount of osToken shares"); + assertGt(mintedAssets, 0, "No osToken assets minted"); + } + + function test_fallbackDeposit() public { + // Test direct ETH transfer to vault + uint256 depositAmount = 5 ether; + uint256 depositShares = vault.convertToShares(depositAmount); + uint256 senderBalanceBefore = vault.getShares(sender); + + vm.prank(sender); + _startSnapshotGas("EthVaultTest_test_fallbackDeposit"); + Address.sendValue(payable(address(vault)), depositAmount); + _stopSnapshotGas(); + + // Verify sender got vault shares + assertApproxEqAbs(vault.getShares(sender), senderBalanceBefore + depositShares, 1, "Shares not increased"); + } } diff --git a/test/KeeperOracles.t.sol b/test/KeeperOracles.t.sol index 9f5aded9..b4796970 100644 --- a/test/KeeperOracles.t.sol +++ b/test/KeeperOracles.t.sol @@ -1,211 +1,211 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperOracles} from '../contracts/interfaces/IKeeperOracles.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {Keeper} from '../contracts/keeper/Keeper.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperOracles} from "../contracts/interfaces/IKeeperOracles.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {Keeper} from "../contracts/keeper/Keeper.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract KeeperOraclesTest is Test, EthHelpers { - // Setup contracts and variables - ForkContracts public contracts; - Keeper public keeper; - - address public owner; - address public newOracle; - address public nonOwner; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - keeper = contracts.keeper; - - // Set up test accounts - owner = keeper.owner(); - newOracle = makeAddr('newOracle'); - nonOwner = makeAddr('nonOwner'); - } - - // Test cases for addOracle - function test_addOracle_success() public { - // Remove oracle first if already added - if (keeper.isOracle(newOracle)) { - vm.prank(owner); - keeper.removeOracle(newOracle); + // Setup contracts and variables + ForkContracts public contracts; + Keeper public keeper; + + address public owner; + address public newOracle; + address public nonOwner; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + keeper = contracts.keeper; + + // Set up test accounts + owner = keeper.owner(); + newOracle = makeAddr("newOracle"); + nonOwner = makeAddr("nonOwner"); } - // Initial state check - assertFalse(keeper.isOracle(newOracle), 'Oracle should not be added initially'); - uint256 initialTotalOracles = keeper.totalOracles(); - - // Expect OracleAdded event - vm.expectEmit(true, false, false, false); - emit IKeeperOracles.OracleAdded(newOracle); - - // Add the oracle - vm.prank(owner); - _startSnapshotGas('KeeperOraclesTest_test_addOracle_success'); - keeper.addOracle(newOracle); - _stopSnapshotGas(); - - // Verify oracle was added - assertTrue(keeper.isOracle(newOracle), 'Oracle should be added'); - assertEq(keeper.totalOracles(), initialTotalOracles + 1, 'Total oracles should be incremented'); - } - - function test_addOracle_alreadyAdded() public { - // Add oracle first (or ensure it's added) - if (!keeper.isOracle(newOracle)) { - vm.prank(owner); - keeper.addOracle(newOracle); + // Test cases for addOracle + function test_addOracle_success() public { + // Remove oracle first if already added + if (keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.removeOracle(newOracle); + } + + // Initial state check + assertFalse(keeper.isOracle(newOracle), "Oracle should not be added initially"); + uint256 initialTotalOracles = keeper.totalOracles(); + + // Expect OracleAdded event + vm.expectEmit(true, false, false, false); + emit IKeeperOracles.OracleAdded(newOracle); + + // Add the oracle + vm.prank(owner); + _startSnapshotGas("KeeperOraclesTest_test_addOracle_success"); + keeper.addOracle(newOracle); + _stopSnapshotGas(); + + // Verify oracle was added + assertTrue(keeper.isOracle(newOracle), "Oracle should be added"); + assertEq(keeper.totalOracles(), initialTotalOracles + 1, "Total oracles should be incremented"); + } + + function test_addOracle_alreadyAdded() public { + // Add oracle first (or ensure it's added) + if (!keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.addOracle(newOracle); + } + + // Try to add again and expect revert + vm.prank(owner); + _startSnapshotGas("KeeperOraclesTest_test_addOracle_alreadyAdded"); + vm.expectRevert(Errors.AlreadyAdded.selector); + keeper.addOracle(newOracle); + _stopSnapshotGas(); + } + + function test_addOracle_maxOraclesExceeded() public { + // Get the current number of oracles + uint256 currentOracles = keeper.totalOracles(); + uint256 maxOracles = 30; // From the contract + + // Skip test if already at max oracles + if (currentOracles >= maxOracles) { + // In a forked environment, we might already have max oracles + // In that case, we can't properly test the max oracles exceeded error + return; + } + + // Add oracles until we reach the maximum + for (uint256 i = 0; i < maxOracles - currentOracles; i++) { + address oracle = makeAddr(string(abi.encodePacked("oracle", i))); + if (!keeper.isOracle(oracle)) { + vm.prank(owner); + keeper.addOracle(oracle); + } + } + + // Verify we've reached the max + assertEq(keeper.totalOracles(), maxOracles, "Total oracles should equal max oracles"); + + // Try to add one more and expect revert + vm.prank(owner); + _startSnapshotGas("KeeperOraclesTest_test_addOracle_maxOraclesExceeded"); + vm.expectRevert(Errors.MaxOraclesExceeded.selector); + keeper.addOracle(makeAddr("oneMoreOracle")); + _stopSnapshotGas(); + } + + // Test cases for removeOracle + function test_removeOracle_success() public { + // Add oracle first if not already added + if (!keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.addOracle(newOracle); + } + + // Initial state check + assertTrue(keeper.isOracle(newOracle), "Oracle should be added initially"); + uint256 initialTotalOracles = keeper.totalOracles(); + + // Expect OracleRemoved event + vm.expectEmit(true, false, false, false); + emit IKeeperOracles.OracleRemoved(newOracle); + + // Remove the oracle + vm.prank(owner); + _startSnapshotGas("KeeperOraclesTest_test_removeOracle_success"); + keeper.removeOracle(newOracle); + _stopSnapshotGas(); + + // Verify oracle was removed + assertFalse(keeper.isOracle(newOracle), "Oracle should be removed"); + assertEq(keeper.totalOracles(), initialTotalOracles - 1, "Total oracles should be decremented"); } - // Try to add again and expect revert - vm.prank(owner); - _startSnapshotGas('KeeperOraclesTest_test_addOracle_alreadyAdded'); - vm.expectRevert(Errors.AlreadyAdded.selector); - keeper.addOracle(newOracle); - _stopSnapshotGas(); - } - - function test_addOracle_maxOraclesExceeded() public { - // Get the current number of oracles - uint256 currentOracles = keeper.totalOracles(); - uint256 maxOracles = 30; // From the contract - - // Skip test if already at max oracles - if (currentOracles >= maxOracles) { - // In a forked environment, we might already have max oracles - // In that case, we can't properly test the max oracles exceeded error - return; + function test_removeOracle_alreadyRemoved() public { + // Ensure oracle is not added + if (keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.removeOracle(newOracle); + } + + // Try to remove and expect revert + vm.prank(owner); + _startSnapshotGas("KeeperOraclesTest_test_removeOracle_alreadyRemoved"); + vm.expectRevert(Errors.AlreadyRemoved.selector); + keeper.removeOracle(newOracle); + _stopSnapshotGas(); } - // Add oracles until we reach the maximum - for (uint256 i = 0; i < maxOracles - currentOracles; i++) { - address oracle = makeAddr(string(abi.encodePacked('oracle', i))); - if (!keeper.isOracle(oracle)) { + // Test cases for updateConfig + function test_updateConfig_success() public { + string memory configIpfsHash = "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u"; + + // Expect ConfigUpdated event + vm.expectEmit(true, false, false, false); + emit IKeeperOracles.ConfigUpdated(configIpfsHash); + + // Update config vm.prank(owner); - keeper.addOracle(oracle); - } + _startSnapshotGas("KeeperOraclesTest_test_updateConfig_success"); + keeper.updateConfig(configIpfsHash); + _stopSnapshotGas(); } - // Verify we've reached the max - assertEq(keeper.totalOracles(), maxOracles, 'Total oracles should equal max oracles'); - - // Try to add one more and expect revert - vm.prank(owner); - _startSnapshotGas('KeeperOraclesTest_test_addOracle_maxOraclesExceeded'); - vm.expectRevert(Errors.MaxOraclesExceeded.selector); - keeper.addOracle(makeAddr('oneMoreOracle')); - _stopSnapshotGas(); - } - - // Test cases for removeOracle - function test_removeOracle_success() public { - // Add oracle first if not already added - if (!keeper.isOracle(newOracle)) { - vm.prank(owner); - keeper.addOracle(newOracle); + // Test access control + function test_addOracle_onlyOwner() public { + vm.prank(nonOwner); + _startSnapshotGas("KeeperOraclesTest_test_addOracle_onlyOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + keeper.addOracle(newOracle); + _stopSnapshotGas(); } - // Initial state check - assertTrue(keeper.isOracle(newOracle), 'Oracle should be added initially'); - uint256 initialTotalOracles = keeper.totalOracles(); - - // Expect OracleRemoved event - vm.expectEmit(true, false, false, false); - emit IKeeperOracles.OracleRemoved(newOracle); - - // Remove the oracle - vm.prank(owner); - _startSnapshotGas('KeeperOraclesTest_test_removeOracle_success'); - keeper.removeOracle(newOracle); - _stopSnapshotGas(); - - // Verify oracle was removed - assertFalse(keeper.isOracle(newOracle), 'Oracle should be removed'); - assertEq(keeper.totalOracles(), initialTotalOracles - 1, 'Total oracles should be decremented'); - } - - function test_removeOracle_alreadyRemoved() public { - // Ensure oracle is not added - if (keeper.isOracle(newOracle)) { - vm.prank(owner); - keeper.removeOracle(newOracle); + function test_removeOracle_onlyOwner() public { + // Add oracle first if not already added + if (!keeper.isOracle(newOracle)) { + vm.prank(owner); + keeper.addOracle(newOracle); + } + + vm.prank(nonOwner); + _startSnapshotGas("KeeperOraclesTest_test_removeOracle_onlyOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + keeper.removeOracle(newOracle); + _stopSnapshotGas(); } - // Try to remove and expect revert - vm.prank(owner); - _startSnapshotGas('KeeperOraclesTest_test_removeOracle_alreadyRemoved'); - vm.expectRevert(Errors.AlreadyRemoved.selector); - keeper.removeOracle(newOracle); - _stopSnapshotGas(); - } - - // Test cases for updateConfig - function test_updateConfig_success() public { - string memory configIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u'; - - // Expect ConfigUpdated event - vm.expectEmit(true, false, false, false); - emit IKeeperOracles.ConfigUpdated(configIpfsHash); - - // Update config - vm.prank(owner); - _startSnapshotGas('KeeperOraclesTest_test_updateConfig_success'); - keeper.updateConfig(configIpfsHash); - _stopSnapshotGas(); - } - - // Test access control - function test_addOracle_onlyOwner() public { - vm.prank(nonOwner); - _startSnapshotGas('KeeperOraclesTest_test_addOracle_onlyOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - keeper.addOracle(newOracle); - _stopSnapshotGas(); - } - - function test_removeOracle_onlyOwner() public { - // Add oracle first if not already added - if (!keeper.isOracle(newOracle)) { - vm.prank(owner); - keeper.addOracle(newOracle); + function test_updateConfig_onlyOwner() public { + string memory configIpfsHash = "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u"; + + vm.prank(nonOwner); + _startSnapshotGas("KeeperOraclesTest_test_updateConfig_onlyOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + keeper.updateConfig(configIpfsHash); + _stopSnapshotGas(); } - vm.prank(nonOwner); - _startSnapshotGas('KeeperOraclesTest_test_removeOracle_onlyOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - keeper.removeOracle(newOracle); - _stopSnapshotGas(); - } - - function test_updateConfig_onlyOwner() public { - string memory configIpfsHash = 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u'; - - vm.prank(nonOwner); - _startSnapshotGas('KeeperOraclesTest_test_updateConfig_onlyOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - keeper.updateConfig(configIpfsHash); - _stopSnapshotGas(); - } - - // Test signature verification through KeeperRewards.updateRewards - function test_verifySignatures_throughKeeperRewards() public { - // Setup oracle for impersonation - _startOracleImpersonate(address(keeper)); - - // Use the _setEthVaultReward helper which generates and verifies signatures - // Use a known valid vault address from the forked environment - address genesisVault = _getForkVault(VaultType.EthGenesisVault); - - // Perform rewards update which uses _verifySignatures internally - _startSnapshotGas('KeeperOraclesTest_test_verifySignatures_throughKeeperRewards'); - _setEthVaultReward(genesisVault, int160(int256(1 ether)), 0); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(keeper)); - } + // Test signature verification through KeeperRewards.updateRewards + function test_verifySignatures_throughKeeperRewards() public { + // Setup oracle for impersonation + _startOracleImpersonate(address(keeper)); + + // Use the _setEthVaultReward helper which generates and verifies signatures + // Use a known valid vault address from the forked environment + address genesisVault = _getForkVault(VaultType.EthGenesisVault); + + // Perform rewards update which uses _verifySignatures internally + _startSnapshotGas("KeeperOraclesTest_test_verifySignatures_throughKeeperRewards"); + _setEthVaultReward(genesisVault, int160(int256(1 ether)), 0); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(keeper)); + } } diff --git a/test/KeeperRewards.t.sol b/test/KeeperRewards.t.sol index 14bba23d..67b967d9 100644 --- a/test/KeeperRewards.t.sol +++ b/test/KeeperRewards.t.sol @@ -1,585 +1,538 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; -import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {Keeper} from '../contracts/keeper/Keeper.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IKeeperValidators} from "../contracts/interfaces/IKeeperValidators.sol"; +import {IOsTokenVaultController} from "../contracts/interfaces/IOsTokenVaultController.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {Keeper} from "../contracts/keeper/Keeper.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; contract KeeperRewardsTest is Test, EthHelpers { - // Fork contracts - ForkContracts public contracts; - - // Test vaults and accounts - EthVault public vault; - address public admin; - address public user; - - // Constants for testing - uint256 public depositAmount = 10 ether; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - - // Fund accounts - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Deposit ETH to the vault - _depositToVault(address(vault), depositAmount, user, user); - } - - // Test rewards update functionality - function test_updateRewards() public { - // Arrange: Start oracle impersonation for signing - _startOracleImpersonate(address(contracts.keeper)); - - // Get current nonce before update - uint64 initialNonce = contracts.keeper.rewardsNonce(); - uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); - bytes32 root = contracts.keeper.rewardsRoot(); - - // Create a simple rewards root for testing - bytes32 rewardsRoot = keccak256(abi.encode('test rewards root')); - string memory ipfsHash = 'rewardsIpfsHash'; - uint256 avgRewardPerSecond = 868240800; - - // Create the update parameters - IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ - rewardsRoot: rewardsRoot, - rewardsIpfsHash: ipfsHash, - avgRewardPerSecond: avgRewardPerSecond, - updateTimestamp: uint64(block.timestamp), - signatures: bytes('') - }); - - // Create a valid signature from the oracle - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' - ), - rewardsRoot, - keccak256(bytes(ipfsHash)), - avgRewardPerSecond, - updateParams.updateTimestamp, - initialNonce - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - updateParams.signatures = abi.encodePacked(r, s, v); - - // Move time forward to allow update - vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() + 1); - - // Act: Call updateRewards - _startSnapshotGas('KeeperRewardsTest_test_updateRewards'); - contracts.keeper.updateRewards(updateParams); - _stopSnapshotGas(); - - // Assert: Verify state has changed correctly - assertEq(contracts.keeper.rewardsRoot(), rewardsRoot, 'Rewards root not updated correctly'); - assertEq( - contracts.keeper.prevRewardsRoot(), - root, - 'Previous rewards root should be zero for first update' - ); - assertEq(contracts.keeper.rewardsNonce(), initialNonce + 1, 'Nonce should be incremented'); - assertEq( - contracts.keeper.lastRewardsTimestamp(), - block.timestamp, - 'Last rewards timestamp not updated' - ); - - // Verify OsTokenVaultController was updated with the new avgRewardPerSecond - assertEq( - contracts.osTokenVaultController.avgRewardPerSecond(), - avgRewardPerSecond, - 'avgRewardPerSecond not updated in OsTokenVaultController' - ); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test updating rewards fails when called too early - function test_updateRewards_tooEarly() public { - // Arrange: Start oracle impersonation for signing - _startOracleImpersonate(address(contracts.keeper)); - - // Get current nonce and timestamp - uint64 initialNonce = contracts.keeper.rewardsNonce(); - uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); - - // Create rewards update parameters - bytes32 rewardsRoot = keccak256(abi.encode('test rewards root')); - IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ - rewardsRoot: rewardsRoot, - rewardsIpfsHash: 'rewardsIpfsHash', - avgRewardPerSecond: 1e15, - updateTimestamp: uint64(block.timestamp), - signatures: bytes('') - }); - - // Create valid signature - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' - ), - updateParams.rewardsRoot, - keccak256(bytes(updateParams.rewardsIpfsHash)), - updateParams.avgRewardPerSecond, - updateParams.updateTimestamp, - initialNonce - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - updateParams.signatures = abi.encodePacked(r, s, v); - - // Move time forward but not enough to allow an update - vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() - 1); - - // Act & Assert: Call should revert as it's too early - _startSnapshotGas('KeeperRewardsTest_test_updateRewards_tooEarly'); - vm.expectRevert(Errors.TooEarlyUpdate.selector); - contracts.keeper.updateRewards(updateParams); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test setting minimum oracles for rewards updates - function test_setRewardsMinOracles() public { - // Arrange: Get the Keeper owner - address keeperOwner = contracts.keeper.owner(); - uint256 currentMinOracles = contracts.keeper.rewardsMinOracles(); - uint256 newMinOracles = currentMinOracles + 1; - - // Make sure we add enough oracles - while (contracts.keeper.totalOracles() < newMinOracles) { - address newOracle = makeAddr('newOracle'); - vm.prank(keeperOwner); - contracts.keeper.addOracle(newOracle); + // Fork contracts + ForkContracts public contracts; + + // Test vaults and accounts + EthVault public vault; + address public admin; + address public user; + + // Constants for testing + uint256 public depositAmount = 10 ether; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deposit ETH to the vault + _depositToVault(address(vault), depositAmount, user, user); } - // Act: Set new min oracles - vm.prank(keeperOwner); - _startSnapshotGas('KeeperRewardsTest_test_setRewardsMinOracles'); - contracts.keeper.setRewardsMinOracles(newMinOracles); - _stopSnapshotGas(); - - // Assert - assertEq( - contracts.keeper.rewardsMinOracles(), - newMinOracles, - 'Min oracles not updated correctly' - ); - } - - // Test setting min oracles fails when value is invalid - function test_setRewardsMinOracles_invalidValue() public { - // Arrange: Get the Keeper owner and total oracles - address keeperOwner = contracts.keeper.owner(); - uint256 totalOracles = contracts.keeper.totalOracles(); - - // Act & Assert: Set to zero (should fail) - vm.prank(keeperOwner); - _startSnapshotGas('KeeperRewardsTest_test_setRewardsMinOracles_zero'); - vm.expectRevert(Errors.InvalidOracles.selector); - contracts.keeper.setRewardsMinOracles(0); - _stopSnapshotGas(); - - // Act & Assert: Set to more than total oracles (should fail) - vm.prank(keeperOwner); - _startSnapshotGas('KeeperRewardsTest_test_setRewardsMinOracles_tooMany'); - vm.expectRevert(Errors.InvalidOracles.selector); - contracts.keeper.setRewardsMinOracles(totalOracles + 1); - _stopSnapshotGas(); - } - - // Test harvest functionality - function test_harvest() public { - // Collateralize the vault first - _collateralizeEthVault(address(vault)); - - // Set up a reward for the vault - int160 totalReward = int160(int256(0.5 ether)); - uint160 unlockedMevReward = 0.1 ether; - - // Create harvest params with a valid reward setup - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - totalReward, - unlockedMevReward - ); - - // Record initial state - uint256 initialBalance = address(vault).balance; - - // Act: Update state (harvests rewards) - _startSnapshotGas('KeeperRewardsTest_test_harvest'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Assert: Check rewards were harvested - uint256 finalBalance = address(vault).balance; - assertGt(finalBalance, initialBalance, 'Vault balance should increase after harvest'); - - // Get reward struct to verify nonce update - (int192 assets, uint64 nonce) = contracts.keeper.rewards(address(vault)); - uint64 currentNonce = contracts.keeper.rewardsNonce(); - assertEq(nonce, currentNonce, 'Reward nonce should match current nonce'); - assertEq(assets, totalReward, 'Recorded assets should match the reward'); - - // Check MEV reward - if (unlockedMevReward > 0) { - (uint192 mevAssets, uint64 mevNonce) = contracts.keeper.unlockedMevRewards(address(vault)); - assertEq(mevNonce, currentNonce, 'MEV reward nonce should match current nonce'); - assertEq(mevAssets, unlockedMevReward, 'Recorded MEV assets should match the reward'); + // Test rewards update functionality + function test_updateRewards() public { + // Arrange: Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Get current nonce before update + uint64 initialNonce = contracts.keeper.rewardsNonce(); + uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); + bytes32 root = contracts.keeper.rewardsRoot(); + + // Create a simple rewards root for testing + bytes32 rewardsRoot = keccak256(abi.encode("test rewards root")); + string memory ipfsHash = "rewardsIpfsHash"; + uint256 avgRewardPerSecond = 868240800; + + // Create the update parameters + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: ipfsHash, + avgRewardPerSecond: avgRewardPerSecond, + updateTimestamp: uint64(block.timestamp), + signatures: bytes("") + }); + + // Create a valid signature from the oracle + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)" + ), + rewardsRoot, + keccak256(bytes(ipfsHash)), + avgRewardPerSecond, + updateParams.updateTimestamp, + initialNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + updateParams.signatures = abi.encodePacked(r, s, v); + + // Move time forward to allow update + vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() + 1); + + // Act: Call updateRewards + _startSnapshotGas("KeeperRewardsTest_test_updateRewards"); + contracts.keeper.updateRewards(updateParams); + _stopSnapshotGas(); + + // Assert: Verify state has changed correctly + assertEq(contracts.keeper.rewardsRoot(), rewardsRoot, "Rewards root not updated correctly"); + assertEq(contracts.keeper.prevRewardsRoot(), root, "Previous rewards root should be zero for first update"); + assertEq(contracts.keeper.rewardsNonce(), initialNonce + 1, "Nonce should be incremented"); + assertEq(contracts.keeper.lastRewardsTimestamp(), block.timestamp, "Last rewards timestamp not updated"); + + // Verify OsTokenVaultController was updated with the new avgRewardPerSecond + assertEq( + contracts.osTokenVaultController.avgRewardPerSecond(), + avgRewardPerSecond, + "avgRewardPerSecond not updated in OsTokenVaultController" + ); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); } - } - - // Test harvesting with invalid reward root - function test_harvest_invalidRewardsRoot() public { - // Collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set up valid reward parameters - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.5 ether)), - 0.1 ether - ); - - // Modify the rewards root to make it invalid - harvestParams.rewardsRoot = keccak256(abi.encode('invalid root')); - - // Act & Assert: Expect failure when rewards root doesn't match - _startSnapshotGas('KeeperRewardsTest_test_harvest_invalidRewardsRoot'); - vm.expectRevert(Errors.InvalidRewardsRoot.selector); - vault.updateState(harvestParams); - _stopSnapshotGas(); - } - - // Test harvest with invalid proof - function test_harvest_invalidProof() public { - // Collateralize the vault - _collateralizeEthVault(address(vault)); - - // Set up reward parameters - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.5 ether)), - 0.1 ether - ); - - // Create an invalid proof - bytes32[] memory invalidProof = new bytes32[](1); - invalidProof[0] = keccak256(abi.encode('invalid proof')); - harvestParams.proof = invalidProof; - - // Act & Assert: Expect failure with invalid proof - _startSnapshotGas('KeeperRewardsTest_test_harvest_invalidProof'); - vm.expectRevert(Errors.InvalidProof.selector); - vault.updateState(harvestParams); - _stopSnapshotGas(); - } - - // Test isHarvestRequired functionality - function test_isHarvestRequired() public { - // Arrange: Collateralize vault - _collateralizeEthVault(address(vault)); - - // Initially, vault should not require harvest after collateralization - assertFalse( - contracts.keeper.isHarvestRequired(address(vault)), - 'Vault should not require harvest initially' - ); - - // Update rewards twice to make the vault need harvesting - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - - // Act & Assert: Now the vault should require harvesting - _startSnapshotGas('KeeperRewardsTest_test_isHarvestRequired'); - bool harvestRequired = contracts.keeper.isHarvestRequired(address(vault)); - _stopSnapshotGas(); - - assertTrue(harvestRequired, 'Vault should require harvest after two reward updates'); - } - - // Test canHarvest functionality - function test_canHarvest() public { - // Arrange: Collateralize vault - _collateralizeEthVault(address(vault)); - - // Update rewards once - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - - // Act & Assert: Vault should be able to harvest - _startSnapshotGas('KeeperRewardsTest_test_canHarvest'); - bool canHarvest = contracts.keeper.canHarvest(address(vault)); - _stopSnapshotGas(); - - assertTrue(canHarvest, 'Vault should be able to harvest after reward update'); - - // Now harvest the vault - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - vault.updateState(harvestParams); - - // Vault should no longer need harvesting - assertFalse( - contracts.keeper.canHarvest(address(vault)), - 'Vault should not need harvesting after update' - ); - } - - // Test isCollateralized functionality - function test_isCollateralized() public { - // Arrange: Initially, vault should not be collateralized - assertFalse( - contracts.keeper.isCollateralized(address(vault)), - 'Vault should not be collateralized initially' - ); - - // Act: Collateralize the vault - _collateralizeEthVault(address(vault)); - - // Assert: Vault should now be collateralized - _startSnapshotGas('KeeperRewardsTest_test_isCollateralized'); - bool isCollateralized = contracts.keeper.isCollateralized(address(vault)); - _stopSnapshotGas(); - - assertTrue(isCollateralized, 'Vault should be collateralized after collateralization'); - } - - // Test handling negative rewards (penalties) - function test_harvestWithPenalties() public { - // Arrange: Collateralize vault and deposit a larger amount - _depositToVault(address(vault), 1 ether, user, user); - _collateralizeEthVault(address(vault)); - - // Set up a negative reward (penalty) - int160 totalReward = int160(int256(-0.1 ether)); - uint160 unlockedMevReward = 0; - - // Create harvest params with a penalty - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - totalReward, - unlockedMevReward - ); - - // Record initial state - uint256 initialTotalAssets = vault.totalAssets(); - - // Act: Update state (applies penalty) - _startSnapshotGas('KeeperRewardsTest_test_harvestWithPenalties'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Assert: Check that assets decreased due to penalty - uint256 finalTotalAssets = vault.totalAssets(); - assertLt(finalTotalAssets, initialTotalAssets, 'Total assets should decrease after penalty'); - - // Check the difference matches the penalty - assertApproxEqAbs( - int256(initialTotalAssets) - int256(finalTotalAssets), - -totalReward, - 1e9, // Allow small rounding difference - 'Asset difference should approximately match the penalty' - ); - } - - // Test updating rewards with an excessive avgRewardPerSecond - function test_updateRewards_invalidAvgRewardPerSecond() public { - // Arrange: Start oracle impersonation - _startOracleImpersonate(address(contracts.keeper)); - - // Get current nonce - uint64 initialNonce = contracts.keeper.rewardsNonce(); - uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); - - // Get the maximum allowed reward per second - // This is an immutable value so we need to get it indirectly - // Set up excessive reward rate (we know the max should be 1e10 or 10%) - uint256 excessiveRewardRate = 1e11; // 100% per second, definitely too high - - // Create params with excessive rate - bytes32 rewardsRoot = keccak256(abi.encode('test rewards root')); - IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ - rewardsRoot: rewardsRoot, - rewardsIpfsHash: 'rewardsIpfsHash', - avgRewardPerSecond: excessiveRewardRate, - updateTimestamp: uint64(block.timestamp), - signatures: bytes('') - }); - - // Create valid signature - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' - ), - updateParams.rewardsRoot, - keccak256(bytes(updateParams.rewardsIpfsHash)), - updateParams.avgRewardPerSecond, - updateParams.updateTimestamp, - initialNonce - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - updateParams.signatures = abi.encodePacked(r, s, v); - - // Move time forward to allow update - vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() + 1); - - // Act & Assert: Call should revert due to excessive reward rate - _startSnapshotGas('KeeperRewardsTest_test_updateRewards_invalidAvgRewardPerSecond'); - vm.expectRevert(Errors.InvalidAvgRewardPerSecond.selector); - contracts.keeper.updateRewards(updateParams); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test calling harvest directly from a non-vault address - function test_harvest_nonVault() public { - // Arrange: Create generic harvest params - IKeeperRewards.HarvestParams memory harvestParams = IKeeperRewards.HarvestParams({ - rewardsRoot: keccak256(abi.encode('test')), - reward: int160(int256(0.5 ether)), - unlockedMevReward: 0.1 ether, - proof: new bytes32[](0) - }); - - // Act & Assert: Call harvest directly from a non-vault address - _startSnapshotGas('KeeperRewardsTest_test_harvest_nonVault'); - vm.expectRevert(Errors.AccessDenied.selector); - contracts.keeper.harvest(harvestParams); - _stopSnapshotGas(); - } - - // Test calling harvest when rewards nonce hasn't changed - function test_harvest_alreadyHarvested() public { - // Arrange: Collateralize and harvest once - _collateralizeEthVault(address(vault)); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.5 ether)), - 0.1 ether - ); - vault.updateState(harvestParams); - - // Try to harvest with the same nonce (not updated yet) - bool canHarvest = contracts.keeper.canHarvest(address(vault)); - assertFalse(canHarvest, 'Vault should not be able to harvest without rewards update'); - - // Act & Assert: Harvesting should succeed but make no changes - int256 totalAssetsBefore = int256(vault.totalAssets()); - _startSnapshotGas('KeeperRewardsTest_test_harvest_alreadyHarvested'); - vault.updateState(harvestParams); // This should be a no-op - _stopSnapshotGas(); - int256 totalAssetsAfter = int256(vault.totalAssets()); - - // Assert no changes occurred - assertEq( - totalAssetsAfter, - totalAssetsBefore, - 'Assets should not change when harvesting already harvested rewards' - ); - } - - // Test multiple reward updates and harvests in sequence - function test_multipleRewardUpdatesAndHarvests() public { - // Arrange: Collateralize vault - _collateralizeEthVault(address(vault)); - - // Record initial state - uint256 initialTotalAssets = vault.totalAssets(); - - // Perform multiple reward updates and harvests - uint256 expectedTotalReward = 0; - for (uint i = 0; i < 3; i++) { - // Set reward for this round - int160 cumRoundReward = int160(int256(0.1 ether * (i + 1))); - uint160 cumRoundMevReward = uint160(0.02 ether * (i + 1)); - int160 roundTotalReward = cumRoundReward + int160(int256(uint256(cumRoundMevReward))); - expectedTotalReward += 0.12 ether; - - // Update and harvest - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - roundTotalReward, - cumRoundMevReward - ); - - _startSnapshotGas( - string.concat( - 'KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_', - vm.toString(i + 1) - ) - ); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify reward was applied - use direct field access - (int192 rewardAssets, uint64 rewardNonce) = contracts.keeper.rewards(address(vault)); - assertEq(rewardNonce, contracts.keeper.rewardsNonce(), 'Reward nonce should be updated'); - assertEq(rewardAssets, roundTotalReward, 'Reward assets should be updated'); - - // MEV rewards check - (uint192 mevAssets, uint64 mevNonce) = contracts.keeper.unlockedMevRewards(address(vault)); - assertEq(mevNonce, contracts.keeper.rewardsNonce(), 'MEV nonce should be updated'); - assertEq(mevAssets, cumRoundMevReward, 'MEV assets should be updated'); + + // Test updating rewards fails when called too early + function test_updateRewards_tooEarly() public { + // Arrange: Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Get current nonce and timestamp + uint64 initialNonce = contracts.keeper.rewardsNonce(); + uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); + + // Create rewards update parameters + bytes32 rewardsRoot = keccak256(abi.encode("test rewards root")); + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: "rewardsIpfsHash", + avgRewardPerSecond: 1e15, + updateTimestamp: uint64(block.timestamp), + signatures: bytes("") + }); + + // Create valid signature + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)" + ), + updateParams.rewardsRoot, + keccak256(bytes(updateParams.rewardsIpfsHash)), + updateParams.avgRewardPerSecond, + updateParams.updateTimestamp, + initialNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + updateParams.signatures = abi.encodePacked(r, s, v); + + // Move time forward but not enough to allow an update + vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() - 1); + + // Act & Assert: Call should revert as it's too early + _startSnapshotGas("KeeperRewardsTest_test_updateRewards_tooEarly"); + vm.expectRevert(Errors.TooEarlyUpdate.selector); + contracts.keeper.updateRewards(updateParams); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test setting minimum oracles for rewards updates + function test_setRewardsMinOracles() public { + // Arrange: Get the Keeper owner + address keeperOwner = contracts.keeper.owner(); + uint256 currentMinOracles = contracts.keeper.rewardsMinOracles(); + uint256 newMinOracles = currentMinOracles + 1; + + // Make sure we add enough oracles + while (contracts.keeper.totalOracles() < newMinOracles) { + address newOracle = makeAddr("newOracle"); + vm.prank(keeperOwner); + contracts.keeper.addOracle(newOracle); + } + + // Act: Set new min oracles + vm.prank(keeperOwner); + _startSnapshotGas("KeeperRewardsTest_test_setRewardsMinOracles"); + contracts.keeper.setRewardsMinOracles(newMinOracles); + _stopSnapshotGas(); + + // Assert + assertEq(contracts.keeper.rewardsMinOracles(), newMinOracles, "Min oracles not updated correctly"); } - // Assert final state includes all rewards - uint256 finalTotalAssets = vault.totalAssets(); - assertApproxEqAbs( - finalTotalAssets - initialTotalAssets, - expectedTotalReward, - 1e9, // Allow small rounding difference - 'Total reward accumulated should match expected sum' - ); - } + // Test setting min oracles fails when value is invalid + function test_setRewardsMinOracles_invalidValue() public { + // Arrange: Get the Keeper owner and total oracles + address keeperOwner = contracts.keeper.owner(); + uint256 totalOracles = contracts.keeper.totalOracles(); + + // Act & Assert: Set to zero (should fail) + vm.prank(keeperOwner); + _startSnapshotGas("KeeperRewardsTest_test_setRewardsMinOracles_zero"); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setRewardsMinOracles(0); + _stopSnapshotGas(); + + // Act & Assert: Set to more than total oracles (should fail) + vm.prank(keeperOwner); + _startSnapshotGas("KeeperRewardsTest_test_setRewardsMinOracles_tooMany"); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setRewardsMinOracles(totalOracles + 1); + _stopSnapshotGas(); + } + + // Test harvest functionality + function test_harvest() public { + // Collateralize the vault first + _collateralizeEthVault(address(vault)); + + // Set up a reward for the vault + int160 totalReward = int160(int256(0.5 ether)); + uint160 unlockedMevReward = 0.1 ether; + + // Create harvest params with a valid reward setup + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), totalReward, unlockedMevReward); + + // Record initial state + uint256 initialBalance = address(vault).balance; + + // Act: Update state (harvests rewards) + _startSnapshotGas("KeeperRewardsTest_test_harvest"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Assert: Check rewards were harvested + uint256 finalBalance = address(vault).balance; + assertGt(finalBalance, initialBalance, "Vault balance should increase after harvest"); + + // Get reward struct to verify nonce update + (int192 assets, uint64 nonce) = contracts.keeper.rewards(address(vault)); + uint64 currentNonce = contracts.keeper.rewardsNonce(); + assertEq(nonce, currentNonce, "Reward nonce should match current nonce"); + assertEq(assets, totalReward, "Recorded assets should match the reward"); + + // Check MEV reward + if (unlockedMevReward > 0) { + (uint192 mevAssets, uint64 mevNonce) = contracts.keeper.unlockedMevRewards(address(vault)); + assertEq(mevNonce, currentNonce, "MEV reward nonce should match current nonce"); + assertEq(mevAssets, unlockedMevReward, "Recorded MEV assets should match the reward"); + } + } + + // Test harvesting with invalid reward root + function test_harvest_invalidRewardsRoot() public { + // Collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set up valid reward parameters + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0.1 ether); + + // Modify the rewards root to make it invalid + harvestParams.rewardsRoot = keccak256(abi.encode("invalid root")); + + // Act & Assert: Expect failure when rewards root doesn't match + _startSnapshotGas("KeeperRewardsTest_test_harvest_invalidRewardsRoot"); + vm.expectRevert(Errors.InvalidRewardsRoot.selector); + vault.updateState(harvestParams); + _stopSnapshotGas(); + } + + // Test harvest with invalid proof + function test_harvest_invalidProof() public { + // Collateralize the vault + _collateralizeEthVault(address(vault)); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0.1 ether); + + // Create an invalid proof + bytes32[] memory invalidProof = new bytes32[](1); + invalidProof[0] = keccak256(abi.encode("invalid proof")); + harvestParams.proof = invalidProof; + + // Act & Assert: Expect failure with invalid proof + _startSnapshotGas("KeeperRewardsTest_test_harvest_invalidProof"); + vm.expectRevert(Errors.InvalidProof.selector); + vault.updateState(harvestParams); + _stopSnapshotGas(); + } + + // Test isHarvestRequired functionality + function test_isHarvestRequired() public { + // Arrange: Collateralize vault + _collateralizeEthVault(address(vault)); + + // Initially, vault should not require harvest after collateralization + assertFalse(contracts.keeper.isHarvestRequired(address(vault)), "Vault should not require harvest initially"); + + // Update rewards twice to make the vault need harvesting + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Act & Assert: Now the vault should require harvesting + _startSnapshotGas("KeeperRewardsTest_test_isHarvestRequired"); + bool harvestRequired = contracts.keeper.isHarvestRequired(address(vault)); + _stopSnapshotGas(); + + assertTrue(harvestRequired, "Vault should require harvest after two reward updates"); + } + + // Test canHarvest functionality + function test_canHarvest() public { + // Arrange: Collateralize vault + _collateralizeEthVault(address(vault)); + + // Update rewards once + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Act & Assert: Vault should be able to harvest + _startSnapshotGas("KeeperRewardsTest_test_canHarvest"); + bool canHarvest = contracts.keeper.canHarvest(address(vault)); + _stopSnapshotGas(); + + assertTrue(canHarvest, "Vault should be able to harvest after reward update"); + + // Now harvest the vault + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + vault.updateState(harvestParams); + + // Vault should no longer need harvesting + assertFalse(contracts.keeper.canHarvest(address(vault)), "Vault should not need harvesting after update"); + } + + // Test isCollateralized functionality + function test_isCollateralized() public { + // Arrange: Initially, vault should not be collateralized + assertFalse(contracts.keeper.isCollateralized(address(vault)), "Vault should not be collateralized initially"); + + // Act: Collateralize the vault + _collateralizeEthVault(address(vault)); + + // Assert: Vault should now be collateralized + _startSnapshotGas("KeeperRewardsTest_test_isCollateralized"); + bool isCollateralized = contracts.keeper.isCollateralized(address(vault)); + _stopSnapshotGas(); + + assertTrue(isCollateralized, "Vault should be collateralized after collateralization"); + } + + // Test handling negative rewards (penalties) + function test_harvestWithPenalties() public { + // Arrange: Collateralize vault and deposit a larger amount + _depositToVault(address(vault), 1 ether, user, user); + _collateralizeEthVault(address(vault)); + + // Set up a negative reward (penalty) + int160 totalReward = int160(int256(-0.1 ether)); + uint160 unlockedMevReward = 0; + + // Create harvest params with a penalty + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), totalReward, unlockedMevReward); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + + // Act: Update state (applies penalty) + _startSnapshotGas("KeeperRewardsTest_test_harvestWithPenalties"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Assert: Check that assets decreased due to penalty + uint256 finalTotalAssets = vault.totalAssets(); + assertLt(finalTotalAssets, initialTotalAssets, "Total assets should decrease after penalty"); + + // Check the difference matches the penalty + assertApproxEqAbs( + int256(initialTotalAssets) - int256(finalTotalAssets), + -totalReward, + 1e9, // Allow small rounding difference + "Asset difference should approximately match the penalty" + ); + } + + // Test updating rewards with an excessive avgRewardPerSecond + function test_updateRewards_invalidAvgRewardPerSecond() public { + // Arrange: Start oracle impersonation + _startOracleImpersonate(address(contracts.keeper)); + + // Get current nonce + uint64 initialNonce = contracts.keeper.rewardsNonce(); + uint64 initialTimestamp = contracts.keeper.lastRewardsTimestamp(); + + // Get the maximum allowed reward per second + // This is an immutable value so we need to get it indirectly + // Set up excessive reward rate (we know the max should be 1e10 or 10%) + uint256 excessiveRewardRate = 1e11; // 100% per second, definitely too high + + // Create params with excessive rate + bytes32 rewardsRoot = keccak256(abi.encode("test rewards root")); + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: "rewardsIpfsHash", + avgRewardPerSecond: excessiveRewardRate, + updateTimestamp: uint64(block.timestamp), + signatures: bytes("") + }); + + // Create valid signature + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)" + ), + updateParams.rewardsRoot, + keccak256(bytes(updateParams.rewardsIpfsHash)), + updateParams.avgRewardPerSecond, + updateParams.updateTimestamp, + initialNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + updateParams.signatures = abi.encodePacked(r, s, v); + + // Move time forward to allow update + vm.warp(initialTimestamp + contracts.keeper.rewardsDelay() + 1); + + // Act & Assert: Call should revert due to excessive reward rate + _startSnapshotGas("KeeperRewardsTest_test_updateRewards_invalidAvgRewardPerSecond"); + vm.expectRevert(Errors.InvalidAvgRewardPerSecond.selector); + contracts.keeper.updateRewards(updateParams); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test calling harvest directly from a non-vault address + function test_harvest_nonVault() public { + // Arrange: Create generic harvest params + IKeeperRewards.HarvestParams memory harvestParams = IKeeperRewards.HarvestParams({ + rewardsRoot: keccak256(abi.encode("test")), + reward: int160(int256(0.5 ether)), + unlockedMevReward: 0.1 ether, + proof: new bytes32[](0) + }); + + // Act & Assert: Call harvest directly from a non-vault address + _startSnapshotGas("KeeperRewardsTest_test_harvest_nonVault"); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.keeper.harvest(harvestParams); + _stopSnapshotGas(); + } + + // Test calling harvest when rewards nonce hasn't changed + function test_harvest_alreadyHarvested() public { + // Arrange: Collateralize and harvest once + _collateralizeEthVault(address(vault)); + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0.1 ether); + vault.updateState(harvestParams); + + // Try to harvest with the same nonce (not updated yet) + bool canHarvest = contracts.keeper.canHarvest(address(vault)); + assertFalse(canHarvest, "Vault should not be able to harvest without rewards update"); + + // Act & Assert: Harvesting should succeed but make no changes + int256 totalAssetsBefore = int256(vault.totalAssets()); + _startSnapshotGas("KeeperRewardsTest_test_harvest_alreadyHarvested"); + vault.updateState(harvestParams); // This should be a no-op + _stopSnapshotGas(); + int256 totalAssetsAfter = int256(vault.totalAssets()); + + // Assert no changes occurred + assertEq( + totalAssetsAfter, totalAssetsBefore, "Assets should not change when harvesting already harvested rewards" + ); + } + + // Test multiple reward updates and harvests in sequence + function test_multipleRewardUpdatesAndHarvests() public { + // Arrange: Collateralize vault + _collateralizeEthVault(address(vault)); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + + // Perform multiple reward updates and harvests + uint256 expectedTotalReward = 0; + for (uint256 i = 0; i < 3; i++) { + // Set reward for this round + int160 cumRoundReward = int160(int256(0.1 ether * (i + 1))); + uint160 cumRoundMevReward = uint160(0.02 ether * (i + 1)); + int160 roundTotalReward = cumRoundReward + int160(int256(uint256(cumRoundMevReward))); + expectedTotalReward += 0.12 ether; + + // Update and harvest + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), roundTotalReward, cumRoundMevReward); + + _startSnapshotGas( + string.concat("KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_", vm.toString(i + 1)) + ); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify reward was applied - use direct field access + (int192 rewardAssets, uint64 rewardNonce) = contracts.keeper.rewards(address(vault)); + assertEq(rewardNonce, contracts.keeper.rewardsNonce(), "Reward nonce should be updated"); + assertEq(rewardAssets, roundTotalReward, "Reward assets should be updated"); + + // MEV rewards check + (uint192 mevAssets, uint64 mevNonce) = contracts.keeper.unlockedMevRewards(address(vault)); + assertEq(mevNonce, contracts.keeper.rewardsNonce(), "MEV nonce should be updated"); + assertEq(mevAssets, cumRoundMevReward, "MEV assets should be updated"); + } + + // Assert final state includes all rewards + uint256 finalTotalAssets = vault.totalAssets(); + assertApproxEqAbs( + finalTotalAssets - initialTotalAssets, + expectedTotalReward, + 1e9, // Allow small rounding difference + "Total reward accumulated should match expected sum" + ); + } } diff --git a/test/KeeperValidators.t.sol b/test/KeeperValidators.t.sol index b57454b1..2ccc9a46 100644 --- a/test/KeeperValidators.t.sol +++ b/test/KeeperValidators.t.sol @@ -1,480 +1,436 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {Keeper} from '../contracts/keeper/Keeper.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperValidators} from "../contracts/interfaces/IKeeperValidators.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {Keeper} from "../contracts/keeper/Keeper.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; contract KeeperValidatorsTest is Test, EthHelpers { - // Fork contracts - ForkContracts public contracts; - - // Test vault and accounts - EthVault public vault; - address public admin; - address public user; - address public owner; - - // Constants for testing - uint256 public depositAmount = 32 ether; // Full validator amount - uint256 public validatorsDeadline; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - owner = contracts.keeper.owner(); - - // Fund accounts - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Deposit ETH to the vault - _depositToVault(address(vault), depositAmount, user, user); - - // Set validators deadline - validatorsDeadline = block.timestamp + 100000; - } - - function test_approveValidators_success() public { - // Start oracle impersonation for signature generation - _startOracleImpersonate(address(contracts.keeper)); - - // Prepare approval parameters - string memory ipfsHash = 'ipfsHash'; - uint256[] memory depositAmounts = new uint256[](1); - depositAmounts[0] = 32 ether / 1 gwei; - IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - address(vault), - ipfsHash, - depositAmounts, - false - ); - - // Set up event expectations - vm.expectEmit(true, true, true, true); - emit IKeeperValidators.ValidatorsApproval(address(vault), ipfsHash); - - // Call approveValidators as the vault - vm.prank(address(vault)); - _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_success'); - contracts.keeper.approveValidators(approvalParams); - _stopSnapshotGas(); - - // Assert: Verify vault is now collateralized - assertTrue( - contracts.keeper.isCollateralized(address(vault)), - 'Vault should be collateralized after validator approval' - ); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_approveValidators_accessDenied() public { - // Create a mock validator approval params directly - // This avoids the complexities of signature generation - IKeeperValidators.ApprovalParams memory approvalParams = IKeeperValidators.ApprovalParams({ - validatorsRegistryRoot: contracts.validatorsRegistry.get_deposit_root(), - validators: new bytes(176), // Empty validator data - signatures: new bytes(65), // Empty signature - exitSignaturesIpfsHash: 'ipfsHash', - deadline: block.timestamp + 1000 - }); - - // Act & Assert: Call from non-vault address should fail because of access control - // This should fail before signature validation - _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_accessDenied'); - vm.expectRevert(Errors.AccessDenied.selector); - contracts.keeper.approveValidators(approvalParams); - _stopSnapshotGas(); - } - - function test_approveValidators_invalidRegistry() public { - // Start by collateralizing with valid parameters - _startOracleImpersonate(address(contracts.keeper)); - - // Get the approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - depositAmount, - 'ipfsHash', - false - ); - - // Change validators registry root to an invalid value - approvalParams.validatorsRegistryRoot = keccak256(abi.encode('invalid registry root')); - - // Stop oracle impersonation - _stopOracleImpersonate(address(contracts.keeper)); - - // Start impersonating the vault - vm.prank(address(vault)); - - // Act & Assert: Call should fail due to invalid registry root - // This happens before signature validation - _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_invalidRegistry'); - vm.expectRevert(Errors.InvalidValidatorsRegistryRoot.selector); - contracts.keeper.approveValidators(approvalParams); - _stopSnapshotGas(); - } - - function test_approveValidators_invalidDeadline() public { - // Start oracle impersonation for signature generation - _startOracleImpersonate(address(contracts.keeper)); - - // Arrange: Prepare validation approval parameters with an expired deadline - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - depositAmount, - 'ipfsHash', - false - ); - - // Stop oracle impersonation - _stopOracleImpersonate(address(contracts.keeper)); - - // Set expired deadline - approvalParams.deadline = block.timestamp - 1; // Expired - - // Start impersonating the vault - this test will check deadline before signature validation - vm.prank(address(vault)); - - // Act & Assert: Call should fail due to expired deadline - _startSnapshotGas('KeeperValidatorsTest_test_approveValidators_invalidDeadline'); - vm.expectRevert(Errors.DeadlineExpired.selector); - contracts.keeper.approveValidators(approvalParams); - _stopSnapshotGas(); - } - - // Test updateExitSignatures functionality - function test_updateExitSignatures_success() public { - // Arrange: First collateralize the vault - _collateralizeEthVault(address(vault)); - - // Start oracle impersonation for signing - _startOracleImpersonate(address(contracts.keeper)); - - // Create parameters for exit signatures update - string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; - uint256 deadline = block.timestamp + 10000; - uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); - - // Create signature for exit signatures update - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' - ), - address(vault), - keccak256(bytes(exitSignaturesIpfsHash)), - initialNonce, - deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - bytes memory signatures = abi.encodePacked(r, s, v); - - // Set up event expectations - vm.expectEmit(true, true, false, true); - emit IKeeperValidators.ExitSignaturesUpdated( - address(this), - address(vault), - initialNonce, - exitSignaturesIpfsHash - ); - - // Act: Update exit signatures - _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_success'); - contracts.keeper.updateExitSignatures( - address(vault), - deadline, - exitSignaturesIpfsHash, - signatures - ); - _stopSnapshotGas(); - - // Assert: Check that nonce was incremented - assertEq( - contracts.keeper.exitSignaturesNonces(address(vault)), - initialNonce + 1, - 'Exit signatures nonce should be incremented' - ); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_updateExitSignatures_invalidVault() public { - // Arrange: Start oracle impersonation for signing - _startOracleImpersonate(address(contracts.keeper)); - - // Create parameters for exit signatures update - string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; - uint256 deadline = block.timestamp + 10000; - uint256 initialNonce = 0; - - // Create signature for exit signatures update - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' - ), - address(contracts.keeper), // Using Keeper as vault (invalid) - keccak256(bytes(exitSignaturesIpfsHash)), - initialNonce, - deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - bytes memory signatures = abi.encodePacked(r, s, v); - - // Act & Assert: Call should fail due to invalid vault - _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_invalidVault'); - vm.expectRevert(Errors.InvalidVault.selector); - contracts.keeper.updateExitSignatures( - address(contracts.keeper), // Using Keeper as vault (invalid) - deadline, - exitSignaturesIpfsHash, - signatures - ); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_updateExitSignatures_notCollateralized() public { - // Arrange: Vault is not collateralized yet - assertFalse( - contracts.keeper.isCollateralized(address(vault)), - 'Vault should not be collateralized initially' - ); - - _startOracleImpersonate(address(contracts.keeper)); - - // Create parameters for exit signatures update - string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; - uint256 deadline = block.timestamp + 10000; - uint256 initialNonce = 0; - - // Create signature for exit signatures update - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' - ), - address(vault), - keccak256(bytes(exitSignaturesIpfsHash)), - initialNonce, - deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - bytes memory signatures = abi.encodePacked(r, s, v); - - // Act & Assert: Call should fail due to non-collateralized vault - _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_notCollateralized'); - vm.expectRevert(Errors.InvalidVault.selector); - contracts.keeper.updateExitSignatures( - address(vault), - deadline, - exitSignaturesIpfsHash, - signatures - ); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_updateExitSignatures_expiredDeadline() public { - // Arrange: First collateralize the vault - _collateralizeEthVault(address(vault)); - - _startOracleImpersonate(address(contracts.keeper)); - - // Create parameters for exit signatures update with expired deadline - string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; - uint256 deadline = block.timestamp - 1; // Expired - uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); - - // Create signature for exit signatures update - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' - ), - address(vault), - keccak256(bytes(exitSignaturesIpfsHash)), - initialNonce, - deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - bytes memory signatures = abi.encodePacked(r, s, v); - - // Act & Assert: Call should fail due to expired deadline - _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_expiredDeadline'); - vm.expectRevert(Errors.DeadlineExpired.selector); - contracts.keeper.updateExitSignatures( - address(vault), - deadline, - exitSignaturesIpfsHash, - signatures - ); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_updateExitSignatures_duplicateUpdate() public { - // Arrange: First collateralize the vault - _collateralizeEthVault(address(vault)); - - _startOracleImpersonate(address(contracts.keeper)); - - // Create parameters for exit signatures update - string memory exitSignaturesIpfsHash = 'exitSignaturesIpfsHash'; - uint256 deadline = block.timestamp + 10000; - uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); - - // Create signature for exit signatures update - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' - ), - address(vault), - keccak256(bytes(exitSignaturesIpfsHash)), - initialNonce, - deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - bytes memory signatures = abi.encodePacked(r, s, v); - - // First update should succeed - contracts.keeper.updateExitSignatures( - address(vault), - deadline, - exitSignaturesIpfsHash, - signatures - ); - - // Act & Assert: Second update with same params should fail due to nonce mismatch - _startSnapshotGas('KeeperValidatorsTest_test_updateExitSignatures_duplicateUpdate'); - vm.expectRevert(Errors.InvalidOracle.selector); - contracts.keeper.updateExitSignatures( - address(vault), - deadline, - exitSignaturesIpfsHash, - signatures - ); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test setValidatorsMinOracles functionality - function test_setValidatorsMinOracles_success() public { - // Arrange: Get current min oracles - uint256 currentMinOracles = contracts.keeper.validatorsMinOracles(); - uint256 totalOracles = contracts.keeper.totalOracles(); - - // Ensure we set to a valid value (not exceeding total oracles) - uint256 newMinOracles = totalOracles > 1 ? totalOracles - 1 : 1; - - // Skip if we're already at target value - if (currentMinOracles == newMinOracles) { - newMinOracles = totalOracles; + // Fork contracts + ForkContracts public contracts; + + // Test vault and accounts + EthVault public vault; + address public admin; + address public user; + address public owner; + + // Constants for testing + uint256 public depositAmount = 32 ether; // Full validator amount + uint256 public validatorsDeadline; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + owner = contracts.keeper.owner(); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deposit ETH to the vault + _depositToVault(address(vault), depositAmount, user, user); + + // Set validators deadline + validatorsDeadline = block.timestamp + 100000; } - // Set up event expectations - vm.expectEmit(true, false, false, false); - emit IKeeperValidators.ValidatorsMinOraclesUpdated(newMinOracles); - - // Act: Set new min oracles - vm.prank(owner); - _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_success'); - contracts.keeper.setValidatorsMinOracles(newMinOracles); - _stopSnapshotGas(); - - // Assert: Check value was updated - assertEq( - contracts.keeper.validatorsMinOracles(), - newMinOracles, - 'Min oracles should be updated' - ); - } - - function test_setValidatorsMinOracles_unauthorized() public { - // Arrange: Get current min oracles - uint256 currentMinOracles = contracts.keeper.validatorsMinOracles(); - - // Act & Assert: Call from non-owner should fail - address nonOwner = makeAddr('nonOwner'); - vm.prank(nonOwner); - _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_unauthorized'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - contracts.keeper.setValidatorsMinOracles(currentMinOracles + 1); - _stopSnapshotGas(); - } - - function test_setValidatorsMinOracles_invalidValue() public { - // Arrange: Get total oracles - uint256 totalOracles = contracts.keeper.totalOracles(); - - // Act & Assert: Setting to zero should fail - vm.prank(owner); - _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_zero'); - vm.expectRevert(Errors.InvalidOracles.selector); - contracts.keeper.setValidatorsMinOracles(0); - _stopSnapshotGas(); - - // Act & Assert: Setting above total oracles should fail - vm.prank(owner); - _startSnapshotGas('KeeperValidatorsTest_test_setValidatorsMinOracles_tooHigh'); - vm.expectRevert(Errors.InvalidOracles.selector); - contracts.keeper.setValidatorsMinOracles(totalOracles + 1); - _stopSnapshotGas(); - } + function test_approveValidators_success() public { + // Start oracle impersonation for signature generation + _startOracleImpersonate(address(contracts.keeper)); + + // Prepare approval parameters + string memory ipfsHash = "ipfsHash"; + uint256[] memory depositAmounts = new uint256[](1); + depositAmounts[0] = 32 ether / 1 gwei; + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + ipfsHash, + depositAmounts, + false + ); + + // Set up event expectations + vm.expectEmit(true, true, true, true); + emit IKeeperValidators.ValidatorsApproval(address(vault), ipfsHash); + + // Call approveValidators as the vault + vm.prank(address(vault)); + _startSnapshotGas("KeeperValidatorsTest_test_approveValidators_success"); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + + // Assert: Verify vault is now collateralized + assertTrue( + contracts.keeper.isCollateralized(address(vault)), "Vault should be collateralized after validator approval" + ); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_approveValidators_accessDenied() public { + // Create a mock validator approval params directly + // This avoids the complexities of signature generation + IKeeperValidators.ApprovalParams memory approvalParams = IKeeperValidators.ApprovalParams({ + validatorsRegistryRoot: contracts.validatorsRegistry.get_deposit_root(), + validators: new bytes(176), // Empty validator data + signatures: new bytes(65), // Empty signature + exitSignaturesIpfsHash: "ipfsHash", + deadline: block.timestamp + 1000 + }); + + // Act & Assert: Call from non-vault address should fail because of access control + // This should fail before signature validation + _startSnapshotGas("KeeperValidatorsTest_test_approveValidators_accessDenied"); + vm.expectRevert(Errors.AccessDenied.selector); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + } + + function test_approveValidators_invalidRegistry() public { + // Start by collateralizing with valid parameters + _startOracleImpersonate(address(contracts.keeper)); + + // Get the approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), depositAmount, "ipfsHash", false); + + // Change validators registry root to an invalid value + approvalParams.validatorsRegistryRoot = keccak256(abi.encode("invalid registry root")); + + // Stop oracle impersonation + _stopOracleImpersonate(address(contracts.keeper)); + + // Start impersonating the vault + vm.prank(address(vault)); + + // Act & Assert: Call should fail due to invalid registry root + // This happens before signature validation + _startSnapshotGas("KeeperValidatorsTest_test_approveValidators_invalidRegistry"); + vm.expectRevert(Errors.InvalidValidatorsRegistryRoot.selector); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + } + + function test_approveValidators_invalidDeadline() public { + // Start oracle impersonation for signature generation + _startOracleImpersonate(address(contracts.keeper)); + + // Arrange: Prepare validation approval parameters with an expired deadline + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), depositAmount, "ipfsHash", false); + + // Stop oracle impersonation + _stopOracleImpersonate(address(contracts.keeper)); + + // Set expired deadline + approvalParams.deadline = block.timestamp - 1; // Expired + + // Start impersonating the vault - this test will check deadline before signature validation + vm.prank(address(vault)); + + // Act & Assert: Call should fail due to expired deadline + _startSnapshotGas("KeeperValidatorsTest_test_approveValidators_invalidDeadline"); + vm.expectRevert(Errors.DeadlineExpired.selector); + contracts.keeper.approveValidators(approvalParams); + _stopSnapshotGas(); + } + + // Test updateExitSignatures functionality + function test_updateExitSignatures_success() public { + // Arrange: First collateralize the vault + _collateralizeEthVault(address(vault)); + + // Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = "exitSignaturesIpfsHash"; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)" + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Set up event expectations + vm.expectEmit(true, true, false, true); + emit IKeeperValidators.ExitSignaturesUpdated( + address(this), address(vault), initialNonce, exitSignaturesIpfsHash + ); + + // Act: Update exit signatures + _startSnapshotGas("KeeperValidatorsTest_test_updateExitSignatures_success"); + contracts.keeper.updateExitSignatures(address(vault), deadline, exitSignaturesIpfsHash, signatures); + _stopSnapshotGas(); + + // Assert: Check that nonce was incremented + assertEq( + contracts.keeper.exitSignaturesNonces(address(vault)), + initialNonce + 1, + "Exit signatures nonce should be incremented" + ); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_invalidVault() public { + // Arrange: Start oracle impersonation for signing + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = "exitSignaturesIpfsHash"; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = 0; + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)" + ), + address(contracts.keeper), // Using Keeper as vault (invalid) + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Act & Assert: Call should fail due to invalid vault + _startSnapshotGas("KeeperValidatorsTest_test_updateExitSignatures_invalidVault"); + vm.expectRevert(Errors.InvalidVault.selector); + contracts.keeper.updateExitSignatures( + address(contracts.keeper), // Using Keeper as vault (invalid) + deadline, + exitSignaturesIpfsHash, + signatures + ); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_notCollateralized() public { + // Arrange: Vault is not collateralized yet + assertFalse(contracts.keeper.isCollateralized(address(vault)), "Vault should not be collateralized initially"); + + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = "exitSignaturesIpfsHash"; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = 0; + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)" + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Act & Assert: Call should fail due to non-collateralized vault + _startSnapshotGas("KeeperValidatorsTest_test_updateExitSignatures_notCollateralized"); + vm.expectRevert(Errors.InvalidVault.selector); + contracts.keeper.updateExitSignatures(address(vault), deadline, exitSignaturesIpfsHash, signatures); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_expiredDeadline() public { + // Arrange: First collateralize the vault + _collateralizeEthVault(address(vault)); + + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update with expired deadline + string memory exitSignaturesIpfsHash = "exitSignaturesIpfsHash"; + uint256 deadline = block.timestamp - 1; // Expired + uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)" + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // Act & Assert: Call should fail due to expired deadline + _startSnapshotGas("KeeperValidatorsTest_test_updateExitSignatures_expiredDeadline"); + vm.expectRevert(Errors.DeadlineExpired.selector); + contracts.keeper.updateExitSignatures(address(vault), deadline, exitSignaturesIpfsHash, signatures); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_updateExitSignatures_duplicateUpdate() public { + // Arrange: First collateralize the vault + _collateralizeEthVault(address(vault)); + + _startOracleImpersonate(address(contracts.keeper)); + + // Create parameters for exit signatures update + string memory exitSignaturesIpfsHash = "exitSignaturesIpfsHash"; + uint256 deadline = block.timestamp + 10000; + uint256 initialNonce = contracts.keeper.exitSignaturesNonces(address(vault)); + + // Create signature for exit signatures update + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)" + ), + address(vault), + keccak256(bytes(exitSignaturesIpfsHash)), + initialNonce, + deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory signatures = abi.encodePacked(r, s, v); + + // First update should succeed + contracts.keeper.updateExitSignatures(address(vault), deadline, exitSignaturesIpfsHash, signatures); + + // Act & Assert: Second update with same params should fail due to nonce mismatch + _startSnapshotGas("KeeperValidatorsTest_test_updateExitSignatures_duplicateUpdate"); + vm.expectRevert(Errors.InvalidOracle.selector); + contracts.keeper.updateExitSignatures(address(vault), deadline, exitSignaturesIpfsHash, signatures); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test setValidatorsMinOracles functionality + function test_setValidatorsMinOracles_success() public { + // Arrange: Get current min oracles + uint256 currentMinOracles = contracts.keeper.validatorsMinOracles(); + uint256 totalOracles = contracts.keeper.totalOracles(); + + // Ensure we set to a valid value (not exceeding total oracles) + uint256 newMinOracles = totalOracles > 1 ? totalOracles - 1 : 1; + + // Skip if we're already at target value + if (currentMinOracles == newMinOracles) { + newMinOracles = totalOracles; + } + + // Set up event expectations + vm.expectEmit(true, false, false, false); + emit IKeeperValidators.ValidatorsMinOraclesUpdated(newMinOracles); + + // Act: Set new min oracles + vm.prank(owner); + _startSnapshotGas("KeeperValidatorsTest_test_setValidatorsMinOracles_success"); + contracts.keeper.setValidatorsMinOracles(newMinOracles); + _stopSnapshotGas(); + + // Assert: Check value was updated + assertEq(contracts.keeper.validatorsMinOracles(), newMinOracles, "Min oracles should be updated"); + } + + function test_setValidatorsMinOracles_unauthorized() public { + // Arrange: Get current min oracles + uint256 currentMinOracles = contracts.keeper.validatorsMinOracles(); + + // Act & Assert: Call from non-owner should fail + address nonOwner = makeAddr("nonOwner"); + vm.prank(nonOwner); + _startSnapshotGas("KeeperValidatorsTest_test_setValidatorsMinOracles_unauthorized"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + contracts.keeper.setValidatorsMinOracles(currentMinOracles + 1); + _stopSnapshotGas(); + } + + function test_setValidatorsMinOracles_invalidValue() public { + // Arrange: Get total oracles + uint256 totalOracles = contracts.keeper.totalOracles(); + + // Act & Assert: Setting to zero should fail + vm.prank(owner); + _startSnapshotGas("KeeperValidatorsTest_test_setValidatorsMinOracles_zero"); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setValidatorsMinOracles(0); + _stopSnapshotGas(); + + // Act & Assert: Setting above total oracles should fail + vm.prank(owner); + _startSnapshotGas("KeeperValidatorsTest_test_setValidatorsMinOracles_tooHigh"); + vm.expectRevert(Errors.InvalidOracles.selector); + contracts.keeper.setValidatorsMinOracles(totalOracles + 1); + _stopSnapshotGas(); + } } diff --git a/test/Multicall.t.sol b/test/Multicall.t.sol index ca564d6c..04229a1a 100644 --- a/test/Multicall.t.sol +++ b/test/Multicall.t.sol @@ -1,146 +1,141 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {MulticallMock} from '../contracts/mocks/MulticallMock.sol'; +import {Test} from "forge-std/Test.sol"; +import {MulticallMock} from "../contracts/mocks/MulticallMock.sol"; contract MulticallTest is Test { - MulticallMock public multicall; - - function setUp() public { - multicall = new MulticallMock(); - } - - function test_multipleSuccessfulCalls() public { - bytes[] memory data = new bytes[](3); - data[0] = abi.encodeWithSelector(multicall.setValue.selector, 123); - data[1] = abi.encodeWithSelector(multicall.setMessage.selector, 'Hello, Multicall'); - data[2] = abi.encodeWithSelector(multicall.setFlag.selector, true); - - bytes[] memory results = multicall.multicall(data); - - assertEq(results.length, 3); - assertEq(abi.decode(results[0], (uint256)), 123); - assertEq(abi.decode(results[1], (string)), 'Hello, Multicall'); - assertEq(abi.decode(results[2], (bool)), true); - - assertEq(multicall.value(), 123); - assertEq(multicall.message(), 'Hello, Multicall'); - assertEq(multicall.flag(), true); - } - - function test_emptyCallsArray() public { - bytes[] memory data = new bytes[](0); - bytes[] memory results = multicall.multicall(data); - - assertEq(results.length, 0); - } - - function test_multipleParams() public { - bytes[] memory data = new bytes[](1); - data[0] = abi.encodeWithSelector( - multicall.multipleParams.selector, - 456, - 'Multiple params', - false - ); - - bytes[] memory results = multicall.multicall(data); - - assertEq(results.length, 1); - (uint256 a, string memory b, bool c) = abi.decode(results[0], (uint256, string, bool)); - assertEq(a, 456); - assertEq(b, 'Multiple params'); - assertEq(c, false); - - assertEq(multicall.value(), 456); - assertEq(multicall.message(), 'Multiple params'); - assertEq(multicall.flag(), false); - } - - function test_revertWithMessage() public { - bytes[] memory data = new bytes[](1); - data[0] = abi.encodeWithSelector(multicall.revertWithMessage.selector); - - vm.expectRevert('Intentional revert with message'); - multicall.multicall(data); - } - - function test_revertWithoutMessage() public { - bytes[] memory data = new bytes[](1); - data[0] = abi.encodeWithSelector(multicall.revertWithoutMessage.selector); - - vm.expectRevert(); - multicall.multicall(data); - } - - function test_invalidCalldata() public { - bytes[] memory data = new bytes[](1); - data[0] = abi.encodePacked('invalidCalldata'); - - vm.expectRevert(); - multicall.multicall(data); - } - - function test_mixSuccessAndFailure() public { - // First set a value that should remain after the revert - multicall.setValue(42); - - bytes[] memory data = new bytes[](3); - data[0] = abi.encodeWithSelector(multicall.setValue.selector, 789); - data[1] = abi.encodeWithSelector(multicall.revertWithMessage.selector); - data[2] = abi.encodeWithSelector(multicall.setFlag.selector, true); - - vm.expectRevert('Intentional revert with message'); - multicall.multicall(data); - - // Check that the initial value remains since the entire multicall reverted - assertEq(multicall.value(), 42); - // The flag should not be set either - assertEq(multicall.flag(), false); - } - - function test_delegateCall() public { - bytes[] memory data = new bytes[](1); - data[0] = abi.encodeWithSelector(multicall.checkCaller.selector); - - bytes[] memory results = multicall.multicall(data); - - // The caller should be this test contract, not the multicall contract - assertEq(abi.decode(results[0], (address)), address(this)); - assertEq(multicall.caller(), address(this)); - } - - function testSequentialExecution() public { - // Add a function to the mock contract that increments the current value - bytes[] memory data = new bytes[](2); - data[0] = abi.encodeWithSelector(multicall.setValue.selector, 100); - // For the second call, we'll manually encode a call that adds 50 to whatever the current value is - data[1] = abi.encodeWithSignature('addToValue(uint256)', 50); - - bytes[] memory results = multicall.multicall(data); - - assertEq(abi.decode(results[0], (uint256)), 100); - assertEq(abi.decode(results[1], (uint256)), 150); - assertEq(multicall.value(), 150); - } - - function test_largeNumberOfCalls() public { - uint256 numCalls = 20; - bytes[] memory data = new bytes[](numCalls); - - for (uint256 i = 0; i < numCalls; i++) { - data[i] = abi.encodeWithSelector(multicall.setValue.selector, i); + MulticallMock public multicall; + + function setUp() public { + multicall = new MulticallMock(); + } + + function test_multipleSuccessfulCalls() public { + bytes[] memory data = new bytes[](3); + data[0] = abi.encodeWithSelector(multicall.setValue.selector, 123); + data[1] = abi.encodeWithSelector(multicall.setMessage.selector, "Hello, Multicall"); + data[2] = abi.encodeWithSelector(multicall.setFlag.selector, true); + + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, 3); + assertEq(abi.decode(results[0], (uint256)), 123); + assertEq(abi.decode(results[1], (string)), "Hello, Multicall"); + assertEq(abi.decode(results[2], (bool)), true); + + assertEq(multicall.value(), 123); + assertEq(multicall.message(), "Hello, Multicall"); + assertEq(multicall.flag(), true); + } + + function test_emptyCallsArray() public { + bytes[] memory data = new bytes[](0); + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, 0); + } + + function test_multipleParams() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.multipleParams.selector, 456, "Multiple params", false); + + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, 1); + (uint256 a, string memory b, bool c) = abi.decode(results[0], (uint256, string, bool)); + assertEq(a, 456); + assertEq(b, "Multiple params"); + assertEq(c, false); + + assertEq(multicall.value(), 456); + assertEq(multicall.message(), "Multiple params"); + assertEq(multicall.flag(), false); + } + + function test_revertWithMessage() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.revertWithMessage.selector); + + vm.expectRevert("Intentional revert with message"); + multicall.multicall(data); + } + + function test_revertWithoutMessage() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.revertWithoutMessage.selector); + + vm.expectRevert(); + multicall.multicall(data); + } + + function test_invalidCalldata() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodePacked("invalidCalldata"); + + vm.expectRevert(); + multicall.multicall(data); + } + + function test_mixSuccessAndFailure() public { + // First set a value that should remain after the revert + multicall.setValue(42); + + bytes[] memory data = new bytes[](3); + data[0] = abi.encodeWithSelector(multicall.setValue.selector, 789); + data[1] = abi.encodeWithSelector(multicall.revertWithMessage.selector); + data[2] = abi.encodeWithSelector(multicall.setFlag.selector, true); + + vm.expectRevert("Intentional revert with message"); + multicall.multicall(data); + + // Check that the initial value remains since the entire multicall reverted + assertEq(multicall.value(), 42); + // The flag should not be set either + assertEq(multicall.flag(), false); } - bytes[] memory results = multicall.multicall(data); + function test_delegateCall() public { + bytes[] memory data = new bytes[](1); + data[0] = abi.encodeWithSelector(multicall.checkCaller.selector); + + bytes[] memory results = multicall.multicall(data); - assertEq(results.length, numCalls); - for (uint256 i = 0; i < numCalls; i++) { - assertEq(abi.decode(results[i], (uint256)), i); + // The caller should be this test contract, not the multicall contract + assertEq(abi.decode(results[0], (address)), address(this)); + assertEq(multicall.caller(), address(this)); } - // Value should be set to the last call's argument - assertEq(multicall.value(), numCalls - 1); - } + function testSequentialExecution() public { + // Add a function to the mock contract that increments the current value + bytes[] memory data = new bytes[](2); + data[0] = abi.encodeWithSelector(multicall.setValue.selector, 100); + // For the second call, we'll manually encode a call that adds 50 to whatever the current value is + data[1] = abi.encodeWithSignature("addToValue(uint256)", 50); + + bytes[] memory results = multicall.multicall(data); + + assertEq(abi.decode(results[0], (uint256)), 100); + assertEq(abi.decode(results[1], (uint256)), 150); + assertEq(multicall.value(), 150); + } + + function test_largeNumberOfCalls() public { + uint256 numCalls = 20; + bytes[] memory data = new bytes[](numCalls); + + for (uint256 i = 0; i < numCalls; i++) { + data[i] = abi.encodeWithSelector(multicall.setValue.selector, i); + } + + bytes[] memory results = multicall.multicall(data); + + assertEq(results.length, numCalls); + for (uint256 i = 0; i < numCalls; i++) { + assertEq(abi.decode(results[i], (uint256)), i); + } + + // Value should be set to the last call's argument + assertEq(multicall.value(), numCalls - 1); + } } diff --git a/test/OsToken.t.sol b/test/OsToken.t.sol index dc1fef21..3747def2 100644 --- a/test/OsToken.t.sol +++ b/test/OsToken.t.sol @@ -1,400 +1,366 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {OsToken} from '../contracts/tokens/OsToken.sol'; -import {IOsToken} from '../contracts/interfaces/IOsToken.sol'; -import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {OsToken} from "../contracts/tokens/OsToken.sol"; +import {IOsToken} from "../contracts/interfaces/IOsToken.sol"; +import {IOsTokenVaultController} from "../contracts/interfaces/IOsTokenVaultController.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract OsTokenTest is Test, EthHelpers { - // Testing contracts - ForkContracts public contracts; - OsToken public osToken; - - // Test addresses - address public owner; - address public user; - address public controller; - - function setUp() public { - // Activate Ethereum fork - contracts = _activateEthereumFork(); - - // Get the existing OsToken contract from the fork - osToken = OsToken(_osToken); - - // Setup test addresses - owner = makeAddr('owner'); - user = makeAddr('user'); - controller = makeAddr('controller'); - - // Fund user account for transactions - vm.deal(user, 100 ether); - } - - // Test initialization and basic properties - function test_initialization() public view { - // Check name and symbol - assertEq(osToken.name(), 'Staked ETH', 'Wrong token name'); - assertEq(osToken.symbol(), 'osETH', 'Wrong token symbol'); - } - - // Test controller management - function test_setController() public { - // Get current owner - address currentOwner = osToken.owner(); - vm.startPrank(currentOwner); - - // Add new controller - _startSnapshotGas('OsTokenTest_test_setController_add'); - osToken.setController(controller, true); - _stopSnapshotGas(); - - // Verify controller was added - assertTrue(osToken.controllers(controller), 'Controller should be enabled'); - - // Remove controller - _startSnapshotGas('OsTokenTest_test_setController_remove'); - osToken.setController(controller, false); - _stopSnapshotGas(); - - // Verify controller was removed - assertFalse(osToken.controllers(controller), 'Controller should be disabled'); - - vm.stopPrank(); - } - - // Test controller management access control - function test_setController_onlyOwner() public { - vm.prank(user); - _startSnapshotGas('OsTokenTest_test_setController_onlyOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', user)); - osToken.setController(controller, true); - _stopSnapshotGas(); - } - - // Test setController with zero address - function test_setController_zeroAddress() public { - address currentOwner = osToken.owner(); - vm.prank(currentOwner); - _startSnapshotGas('OsTokenTest_test_setController_zeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - osToken.setController(address(0), true); - _stopSnapshotGas(); - } - - // Test minting - function test_mint() public { - // Setup controller - address currentOwner = osToken.owner(); - vm.prank(currentOwner); - osToken.setController(controller, true); - - uint256 amount = 100 ether; - uint256 initialBalance = osToken.balanceOf(user); - - // Mint tokens - vm.prank(controller); - _startSnapshotGas('OsTokenTest_test_mint'); - osToken.mint(user, amount); - _stopSnapshotGas(); - - // Verify balance increased - assertEq( - osToken.balanceOf(user), - initialBalance + amount, - 'Balance should increase by minted amount' - ); - } - - // Test minting access control - function test_mint_onlyController() public { - uint256 amount = 100 ether; - - // Try to mint without being a controller - vm.prank(user); - _startSnapshotGas('OsTokenTest_test_mint_onlyController'); - vm.expectRevert(Errors.AccessDenied.selector); - osToken.mint(user, amount); - _stopSnapshotGas(); - } - - // Test burning - function test_burn() public { - // Setup controller and mint tokens first - address currentOwner = osToken.owner(); - vm.prank(currentOwner); - osToken.setController(controller, true); - - uint256 amount = 100 ether; - vm.prank(controller); - osToken.mint(user, amount); - - uint256 initialBalance = osToken.balanceOf(user); - - // Burn tokens - vm.prank(controller); - _startSnapshotGas('OsTokenTest_test_burn'); - osToken.burn(user, amount); - _stopSnapshotGas(); - - // Verify balance decreased - assertEq( - osToken.balanceOf(user), - initialBalance - amount, - 'Balance should decrease by burned amount' - ); - } - - // Test burning access control - function test_burn_onlyController() public { - // Mint tokens first using the _mintOsToken helper - uint256 amount = 100 ether; - _mintOsToken(user, amount); - - // Try to burn without being a controller - vm.prank(user); - _startSnapshotGas('OsTokenTest_test_burn_onlyController'); - vm.expectRevert(Errors.AccessDenied.selector); - osToken.burn(user, amount); - _stopSnapshotGas(); - } - - // Test integration with OsTokenVaultController - function test_controllerIntegration() public { - // Test that the OsTokenVaultController can mint tokens - uint256 amount = 10 ether; - uint256 initialBalance = osToken.balanceOf(user); - - // Use the vault controller to mint tokens - _startSnapshotGas('OsTokenTest_test_controllerIntegration_mint'); - _mintOsToken(user, amount); - _stopSnapshotGas(); - - // Verify balance increased - assertEq( - osToken.balanceOf(user), - initialBalance + amount, - 'Balance should increase by minted amount' - ); - - // Test burning from the controller - vm.prank(address(contracts.osTokenVaultController)); - _startSnapshotGas('OsTokenTest_test_controllerIntegration_burn'); - osToken.burn(user, amount); - _stopSnapshotGas(); - - // Verify balance decreased back to initial - assertEq( - osToken.balanceOf(user), - initialBalance, - 'Balance should decrease back to initial amount' - ); - } - - // Test token permit functionality - function test_permit() public { - uint256 ownerPrivateKey = 123456; // Sample private key for testing - address tokenOwner = vm.addr(ownerPrivateKey); - - // Mint tokens to the token owner - _mintOsToken(tokenOwner, 100 ether); - - // Create permit data - uint256 value = 10 ether; - uint256 deadline = block.timestamp + 1 hours; - uint256 nonceBefore = osToken.nonces(tokenOwner); - - // Generate signature - bytes32 domainSeparator = osToken.DOMAIN_SEPARATOR(); - bytes32 permitTypehash = keccak256( - 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' - ); - - bytes32 structHash = keccak256( - abi.encode(permitTypehash, tokenOwner, user, value, nonceBefore, deadline) - ); - - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); - - // Execute permit - _startSnapshotGas('OsTokenTest_test_permit'); - osToken.permit(tokenOwner, user, value, deadline, v, r, s); - _stopSnapshotGas(); - - // Verify allowance was set - assertEq(osToken.allowance(tokenOwner, user), value, 'Allowance should be set to permit value'); - - // Verify nonce was incremented - assertEq(osToken.nonces(tokenOwner), nonceBefore + 1, 'Nonce should be incremented'); - } - - // Test permit with expired deadline - function test_permit_expiredDeadline() public { - uint256 ownerPrivateKey = 123456; - address tokenOwner = vm.addr(ownerPrivateKey); - - // Create permit with expired deadline - uint256 expiredDeadline = block.timestamp - 1 hours; - - // Generate signature (exact signature doesn't matter as we'll hit the deadline check first) - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, bytes32(0)); - - // Execute permit with expired deadline - _startSnapshotGas('OsTokenTest_test_permit_expiredDeadline'); - vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 - osToken.permit(tokenOwner, user, 1 ether, expiredDeadline, v, r, s); - _stopSnapshotGas(); - } - - // Test permit with invalid signature - function test_permit_invalidSignature() public { - uint256 ownerPrivateKey = 123456; - address tokenOwner = vm.addr(ownerPrivateKey); - uint256 wrongPrivateKey = 654321; - - // Create valid permit data - uint256 value = 10 ether; - uint256 deadline = block.timestamp + 1 hours; - uint256 nonce = osToken.nonces(tokenOwner); - - // Generate invalid signature (using wrong private key) - bytes32 domainSeparator = osToken.DOMAIN_SEPARATOR(); - bytes32 permitTypehash = keccak256( - 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' - ); - - bytes32 structHash = keccak256( - abi.encode(permitTypehash, tokenOwner, user, value, nonce, deadline) - ); - - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, digest); - - // Execute permit with invalid signature - _startSnapshotGas('OsTokenTest_test_permit_invalidSignature'); - vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 - osToken.permit(tokenOwner, user, value, deadline, v, r, s); - _stopSnapshotGas(); - } - - // Test permit with zero address spender - function test_permit_zeroAddress() public { - uint256 ownerPrivateKey = 123456; - address tokenOwner = vm.addr(ownerPrivateKey); - - // Create permit with zero address - uint256 deadline = block.timestamp + 1 hours; - - // Generate signature (exact signature doesn't matter as we'll hit the zero address check first) - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, bytes32(0)); - - // Execute permit with zero address - _startSnapshotGas('OsTokenTest_test_permit_zeroAddress'); - vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 - osToken.permit(tokenOwner, address(0), 1 ether, deadline, v, r, s); - _stopSnapshotGas(); - } - - // Test ERC20 transfer and transferFrom functionality - function test_erc20_transfers() public { - // Mint tokens to the user - uint256 amount = 50 ether; - _mintOsToken(user, amount); - - address recipient = makeAddr('recipient'); - uint256 transferAmount = 10 ether; - - // Test transfer function - vm.prank(user); - _startSnapshotGas('OsTokenTest_test_erc20_transfer'); - bool transferSuccess = osToken.transfer(recipient, transferAmount); - _stopSnapshotGas(); - - assertTrue(transferSuccess, 'Transfer should succeed'); - assertEq(osToken.balanceOf(recipient), transferAmount, 'Recipient should receive tokens'); - assertEq(osToken.balanceOf(user), amount - transferAmount, "User's balance should be reduced"); - - // Test transferFrom function - address spender = makeAddr('spender'); - uint256 approvalAmount = 20 ether; - - // Approve spender - vm.prank(user); - osToken.approve(spender, approvalAmount); - - // Use transferFrom - vm.prank(spender); - _startSnapshotGas('OsTokenTest_test_erc20_transferFrom'); - bool transferFromSuccess = osToken.transferFrom(user, recipient, 5 ether); - _stopSnapshotGas(); - - assertTrue(transferFromSuccess, 'TransferFrom should succeed'); - assertEq( - osToken.balanceOf(recipient), - transferAmount + 5 ether, - 'Recipient should receive additional tokens' - ); - assertEq( - osToken.balanceOf(user), - amount - transferAmount - 5 ether, - "User's balance should be further reduced" - ); - assertEq( - osToken.allowance(user, spender), - approvalAmount - 5 ether, - 'Allowance should be reduced' - ); - } - - // Test integration with full deposit flow - function test_fullDepositFlow() public { - // Create a vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createVault(VaultType.EthVault, user, initParams, false); - - // Collateralize vault - _collateralizeEthVault(vaultAddr); - - // Deposit ETH to mint vault tokens - uint256 depositAmount = 10 ether; - uint256 initialOsTokenBalance = osToken.balanceOf(user); - - // Deposit and mint osToken in one transaction - vm.deal(user, user.balance + depositAmount); - vm.prank(user); - _startSnapshotGas('OsTokenTest_test_fullDepositFlow'); - uint256 mintedOsTokenShares = IEthVault(vaultAddr).depositAndMintOsToken{value: depositAmount}( - user, - type(uint256).max, // max possible amount - address(0) - ); - _stopSnapshotGas(); - - // Verify osToken was minted - assertGt(osToken.balanceOf(user), initialOsTokenBalance, 'osToken balance should increase'); - - // Due to conversion rates and fees, the exact amounts may not match perfectly - // We verify the amounts are close enough (within 5%) - uint256 actualIncrease = osToken.balanceOf(user) - initialOsTokenBalance; - assertApproxEqRel( - actualIncrease, - mintedOsTokenShares, - 0.05e18, // 5% tolerance - 'Minted osToken amount too far from expected' - ); - } + // Testing contracts + ForkContracts public contracts; + OsToken public osToken; + + // Test addresses + address public owner; + address public user; + address public controller; + + function setUp() public { + // Activate Ethereum fork + contracts = _activateEthereumFork(); + + // Get the existing OsToken contract from the fork + osToken = OsToken(_osToken); + + // Setup test addresses + owner = makeAddr("owner"); + user = makeAddr("user"); + controller = makeAddr("controller"); + + // Fund user account for transactions + vm.deal(user, 100 ether); + } + + // Test initialization and basic properties + function test_initialization() public view { + // Check name and symbol + assertEq(osToken.name(), "Staked ETH", "Wrong token name"); + assertEq(osToken.symbol(), "osETH", "Wrong token symbol"); + } + + // Test controller management + function test_setController() public { + // Get current owner + address currentOwner = osToken.owner(); + vm.startPrank(currentOwner); + + // Add new controller + _startSnapshotGas("OsTokenTest_test_setController_add"); + osToken.setController(controller, true); + _stopSnapshotGas(); + + // Verify controller was added + assertTrue(osToken.controllers(controller), "Controller should be enabled"); + + // Remove controller + _startSnapshotGas("OsTokenTest_test_setController_remove"); + osToken.setController(controller, false); + _stopSnapshotGas(); + + // Verify controller was removed + assertFalse(osToken.controllers(controller), "Controller should be disabled"); + + vm.stopPrank(); + } + + // Test controller management access control + function test_setController_onlyOwner() public { + vm.prank(user); + _startSnapshotGas("OsTokenTest_test_setController_onlyOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", user)); + osToken.setController(controller, true); + _stopSnapshotGas(); + } + + // Test setController with zero address + function test_setController_zeroAddress() public { + address currentOwner = osToken.owner(); + vm.prank(currentOwner); + _startSnapshotGas("OsTokenTest_test_setController_zeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + osToken.setController(address(0), true); + _stopSnapshotGas(); + } + + // Test minting + function test_mint() public { + // Setup controller + address currentOwner = osToken.owner(); + vm.prank(currentOwner); + osToken.setController(controller, true); + + uint256 amount = 100 ether; + uint256 initialBalance = osToken.balanceOf(user); + + // Mint tokens + vm.prank(controller); + _startSnapshotGas("OsTokenTest_test_mint"); + osToken.mint(user, amount); + _stopSnapshotGas(); + + // Verify balance increased + assertEq(osToken.balanceOf(user), initialBalance + amount, "Balance should increase by minted amount"); + } + + // Test minting access control + function test_mint_onlyController() public { + uint256 amount = 100 ether; + + // Try to mint without being a controller + vm.prank(user); + _startSnapshotGas("OsTokenTest_test_mint_onlyController"); + vm.expectRevert(Errors.AccessDenied.selector); + osToken.mint(user, amount); + _stopSnapshotGas(); + } + + // Test burning + function test_burn() public { + // Setup controller and mint tokens first + address currentOwner = osToken.owner(); + vm.prank(currentOwner); + osToken.setController(controller, true); + + uint256 amount = 100 ether; + vm.prank(controller); + osToken.mint(user, amount); + + uint256 initialBalance = osToken.balanceOf(user); + + // Burn tokens + vm.prank(controller); + _startSnapshotGas("OsTokenTest_test_burn"); + osToken.burn(user, amount); + _stopSnapshotGas(); + + // Verify balance decreased + assertEq(osToken.balanceOf(user), initialBalance - amount, "Balance should decrease by burned amount"); + } + + // Test burning access control + function test_burn_onlyController() public { + // Mint tokens first using the _mintOsToken helper + uint256 amount = 100 ether; + _mintOsToken(user, amount); + + // Try to burn without being a controller + vm.prank(user); + _startSnapshotGas("OsTokenTest_test_burn_onlyController"); + vm.expectRevert(Errors.AccessDenied.selector); + osToken.burn(user, amount); + _stopSnapshotGas(); + } + + // Test integration with OsTokenVaultController + function test_controllerIntegration() public { + // Test that the OsTokenVaultController can mint tokens + uint256 amount = 10 ether; + uint256 initialBalance = osToken.balanceOf(user); + + // Use the vault controller to mint tokens + _startSnapshotGas("OsTokenTest_test_controllerIntegration_mint"); + _mintOsToken(user, amount); + _stopSnapshotGas(); + + // Verify balance increased + assertEq(osToken.balanceOf(user), initialBalance + amount, "Balance should increase by minted amount"); + + // Test burning from the controller + vm.prank(address(contracts.osTokenVaultController)); + _startSnapshotGas("OsTokenTest_test_controllerIntegration_burn"); + osToken.burn(user, amount); + _stopSnapshotGas(); + + // Verify balance decreased back to initial + assertEq(osToken.balanceOf(user), initialBalance, "Balance should decrease back to initial amount"); + } + + // Test token permit functionality + function test_permit() public { + uint256 ownerPrivateKey = 123456; // Sample private key for testing + address tokenOwner = vm.addr(ownerPrivateKey); + + // Mint tokens to the token owner + _mintOsToken(tokenOwner, 100 ether); + + // Create permit data + uint256 value = 10 ether; + uint256 deadline = block.timestamp + 1 hours; + uint256 nonceBefore = osToken.nonces(tokenOwner); + + // Generate signature + bytes32 domainSeparator = osToken.DOMAIN_SEPARATOR(); + bytes32 permitTypehash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 structHash = keccak256(abi.encode(permitTypehash, tokenOwner, user, value, nonceBefore, deadline)); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + // Execute permit + _startSnapshotGas("OsTokenTest_test_permit"); + osToken.permit(tokenOwner, user, value, deadline, v, r, s); + _stopSnapshotGas(); + + // Verify allowance was set + assertEq(osToken.allowance(tokenOwner, user), value, "Allowance should be set to permit value"); + + // Verify nonce was incremented + assertEq(osToken.nonces(tokenOwner), nonceBefore + 1, "Nonce should be incremented"); + } + + // Test permit with expired deadline + function test_permit_expiredDeadline() public { + uint256 ownerPrivateKey = 123456; + address tokenOwner = vm.addr(ownerPrivateKey); + + // Create permit with expired deadline + uint256 expiredDeadline = block.timestamp - 1 hours; + + // Generate signature (exact signature doesn't matter as we'll hit the deadline check first) + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, bytes32(0)); + + // Execute permit with expired deadline + _startSnapshotGas("OsTokenTest_test_permit_expiredDeadline"); + vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 + osToken.permit(tokenOwner, user, 1 ether, expiredDeadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with invalid signature + function test_permit_invalidSignature() public { + uint256 ownerPrivateKey = 123456; + address tokenOwner = vm.addr(ownerPrivateKey); + uint256 wrongPrivateKey = 654321; + + // Create valid permit data + uint256 value = 10 ether; + uint256 deadline = block.timestamp + 1 hours; + uint256 nonce = osToken.nonces(tokenOwner); + + // Generate invalid signature (using wrong private key) + bytes32 domainSeparator = osToken.DOMAIN_SEPARATOR(); + bytes32 permitTypehash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 structHash = keccak256(abi.encode(permitTypehash, tokenOwner, user, value, nonce, deadline)); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, digest); + + // Execute permit with invalid signature + _startSnapshotGas("OsTokenTest_test_permit_invalidSignature"); + vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 + osToken.permit(tokenOwner, user, value, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with zero address spender + function test_permit_zeroAddress() public { + uint256 ownerPrivateKey = 123456; + address tokenOwner = vm.addr(ownerPrivateKey); + + // Create permit with zero address + uint256 deadline = block.timestamp + 1 hours; + + // Generate signature (exact signature doesn't matter as we'll hit the zero address check first) + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, bytes32(0)); + + // Execute permit with zero address + _startSnapshotGas("OsTokenTest_test_permit_zeroAddress"); + vm.expectRevert(); // OpenZeppelin uses its own error format for ERC2612 + osToken.permit(tokenOwner, address(0), 1 ether, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test ERC20 transfer and transferFrom functionality + function test_erc20_transfers() public { + // Mint tokens to the user + uint256 amount = 50 ether; + _mintOsToken(user, amount); + + address recipient = makeAddr("recipient"); + uint256 transferAmount = 10 ether; + + // Test transfer function + vm.prank(user); + _startSnapshotGas("OsTokenTest_test_erc20_transfer"); + bool transferSuccess = osToken.transfer(recipient, transferAmount); + _stopSnapshotGas(); + + assertTrue(transferSuccess, "Transfer should succeed"); + assertEq(osToken.balanceOf(recipient), transferAmount, "Recipient should receive tokens"); + assertEq(osToken.balanceOf(user), amount - transferAmount, "User's balance should be reduced"); + + // Test transferFrom function + address spender = makeAddr("spender"); + uint256 approvalAmount = 20 ether; + + // Approve spender + vm.prank(user); + osToken.approve(spender, approvalAmount); + + // Use transferFrom + vm.prank(spender); + _startSnapshotGas("OsTokenTest_test_erc20_transferFrom"); + bool transferFromSuccess = osToken.transferFrom(user, recipient, 5 ether); + _stopSnapshotGas(); + + assertTrue(transferFromSuccess, "TransferFrom should succeed"); + assertEq(osToken.balanceOf(recipient), transferAmount + 5 ether, "Recipient should receive additional tokens"); + assertEq(osToken.balanceOf(user), amount - transferAmount - 5 ether, "User's balance should be further reduced"); + assertEq(osToken.allowance(user, spender), approvalAmount - 5 ether, "Allowance should be reduced"); + } + + // Test integration with full deposit flow + function test_fullDepositFlow() public { + // Create a vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, user, initParams, false); + + // Collateralize vault + _collateralizeEthVault(vaultAddr); + + // Deposit ETH to mint vault tokens + uint256 depositAmount = 10 ether; + uint256 initialOsTokenBalance = osToken.balanceOf(user); + + // Deposit and mint osToken in one transaction + vm.deal(user, user.balance + depositAmount); + vm.prank(user); + _startSnapshotGas("OsTokenTest_test_fullDepositFlow"); + uint256 mintedOsTokenShares = IEthVault(vaultAddr).depositAndMintOsToken{value: depositAmount}( + user, + type(uint256).max, // max possible amount + address(0) + ); + _stopSnapshotGas(); + + // Verify osToken was minted + assertGt(osToken.balanceOf(user), initialOsTokenBalance, "osToken balance should increase"); + + // Due to conversion rates and fees, the exact amounts may not match perfectly + // We verify the amounts are close enough (within 5%) + uint256 actualIncrease = osToken.balanceOf(user) - initialOsTokenBalance; + assertApproxEqRel( + actualIncrease, + mintedOsTokenShares, + 0.05e18, // 5% tolerance + "Minted osToken amount too far from expected" + ); + } } diff --git a/test/OsTokenConfig.t.sol b/test/OsTokenConfig.t.sol index 0750d4ec..a480f93f 100644 --- a/test/OsTokenConfig.t.sol +++ b/test/OsTokenConfig.t.sol @@ -1,427 +1,393 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {OsTokenConfig} from '../contracts/tokens/OsTokenConfig.sol'; -import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {OsTokenConfig} from "../contracts/tokens/OsTokenConfig.sol"; +import {IOsTokenConfig} from "../contracts/interfaces/IOsTokenConfig.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract OsTokenConfigTest is Test, EthHelpers { - // Test accounts - address public owner; - address public nonOwner; - address public newRedeemer; - address public vault; - address public anotherVault; - - // Contract under test - IOsTokenConfig public osTokenConfig; - - // Deployment constants - uint256 constant MAX_PERCENT = 1e18; // 100% - uint256 constant DISABLED_LIQ_THRESHOLD = type(uint64).max; - - function setUp() public { - // Activate Ethereum fork and get contracts - ForkContracts memory contracts = _activateEthereumFork(); - - // Get the OsTokenConfig contract from the fork - osTokenConfig = contracts.osTokenConfig; - - // Set up test accounts - owner = Ownable(address(osTokenConfig)).owner(); - nonOwner = makeAddr('nonOwner'); - newRedeemer = makeAddr('newRedeemer'); - vault = makeAddr('vault'); - anotherVault = makeAddr('anotherVault'); - } - - // Test for initial contract state - function test_initialState() public view { - // Check that redeemer is already set - address currentRedeemer = osTokenConfig.redeemer(); - assertFalse(currentRedeemer == address(0), 'Redeemer should be set'); - - // Get default config and check it's valid - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(0)); - assertTrue(config.ltvPercent > 0, 'Default LTV should be greater than 0'); - assertTrue( - config.ltvPercent <= MAX_PERCENT, - 'Default LTV should be less than or equal to max percent' - ); - - // Check that liqThresholdPercent is either valid or disabled - if (config.liqThresholdPercent != DISABLED_LIQ_THRESHOLD) { - assertTrue( - config.liqThresholdPercent > config.ltvPercent, - 'Default liq threshold should be greater than LTV' - ); - assertTrue( - config.liqThresholdPercent < MAX_PERCENT, - 'Default liq threshold should be less than max percent' - ); + // Test accounts + address public owner; + address public nonOwner; + address public newRedeemer; + address public vault; + address public anotherVault; + + // Contract under test + IOsTokenConfig public osTokenConfig; + + // Deployment constants + uint256 constant MAX_PERCENT = 1e18; // 100% + uint256 constant DISABLED_LIQ_THRESHOLD = type(uint64).max; + + function setUp() public { + // Activate Ethereum fork and get contracts + ForkContracts memory contracts = _activateEthereumFork(); + + // Get the OsTokenConfig contract from the fork + osTokenConfig = contracts.osTokenConfig; + + // Set up test accounts + owner = Ownable(address(osTokenConfig)).owner(); + nonOwner = makeAddr("nonOwner"); + newRedeemer = makeAddr("newRedeemer"); + vault = makeAddr("vault"); + anotherVault = makeAddr("anotherVault"); } - // Check liqBonus constraints - if (config.liqThresholdPercent == DISABLED_LIQ_THRESHOLD) { - assertEq(config.liqBonusPercent, 0, 'When liquidations disabled, bonus should be 0'); - } else { - assertTrue( - config.liqBonusPercent >= MAX_PERCENT, - 'Default liq bonus should be at least max percent' - ); - - // Check threshold * bonus <= MAX_PERCENT - uint256 product = (config.liqThresholdPercent * config.liqBonusPercent) / MAX_PERCENT; - assertTrue(product <= MAX_PERCENT, 'Threshold * bonus should be <= max percent'); + // Test for initial contract state + function test_initialState() public view { + // Check that redeemer is already set + address currentRedeemer = osTokenConfig.redeemer(); + assertFalse(currentRedeemer == address(0), "Redeemer should be set"); + + // Get default config and check it's valid + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(0)); + assertTrue(config.ltvPercent > 0, "Default LTV should be greater than 0"); + assertTrue(config.ltvPercent <= MAX_PERCENT, "Default LTV should be less than or equal to max percent"); + + // Check that liqThresholdPercent is either valid or disabled + if (config.liqThresholdPercent != DISABLED_LIQ_THRESHOLD) { + assertTrue( + config.liqThresholdPercent > config.ltvPercent, "Default liq threshold should be greater than LTV" + ); + assertTrue( + config.liqThresholdPercent < MAX_PERCENT, "Default liq threshold should be less than max percent" + ); + } + + // Check liqBonus constraints + if (config.liqThresholdPercent == DISABLED_LIQ_THRESHOLD) { + assertEq(config.liqBonusPercent, 0, "When liquidations disabled, bonus should be 0"); + } else { + assertTrue(config.liqBonusPercent >= MAX_PERCENT, "Default liq bonus should be at least max percent"); + + // Check threshold * bonus <= MAX_PERCENT + uint256 product = (config.liqThresholdPercent * config.liqBonusPercent) / MAX_PERCENT; + assertTrue(product <= MAX_PERCENT, "Threshold * bonus should be <= max percent"); + } } - } - // Test setting redeemer address - function test_setRedeemer() public { - // Get current redeemer - address currentRedeemer = osTokenConfig.redeemer(); + // Test setting redeemer address + function test_setRedeemer() public { + // Get current redeemer + address currentRedeemer = osTokenConfig.redeemer(); - // Make sure our new redeemer is different - if (newRedeemer == currentRedeemer) { - newRedeemer = makeAddr('anotherNewRedeemer'); + // Make sure our new redeemer is different + if (newRedeemer == currentRedeemer) { + newRedeemer = makeAddr("anotherNewRedeemer"); + } + + // Set up expected event + vm.expectEmit(true, false, false, false); + emit IOsTokenConfig.RedeemerUpdated(newRedeemer); + + // Set new redeemer as owner + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_setRedeemer"); + osTokenConfig.setRedeemer(newRedeemer); + _stopSnapshotGas(); + + // Verify redeemer was updated + assertEq(osTokenConfig.redeemer(), newRedeemer, "Redeemer not updated correctly"); + + // Reset to original state for other tests + vm.prank(owner); + osTokenConfig.setRedeemer(currentRedeemer); + } + + // Test non-owner trying to set redeemer (should fail) + function test_setRedeemer_notOwner() public { + // Get current redeemer + address currentRedeemer = osTokenConfig.redeemer(); + + // Attempt to set redeemer as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas("OsTokenConfigForkTest_test_setRedeemer_notOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + osTokenConfig.setRedeemer(newRedeemer); + _stopSnapshotGas(); + + // Verify redeemer was not changed + assertEq(osTokenConfig.redeemer(), currentRedeemer, "Redeemer should not be changed"); } - // Set up expected event - vm.expectEmit(true, false, false, false); - emit IOsTokenConfig.RedeemerUpdated(newRedeemer); - - // Set new redeemer as owner - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_setRedeemer'); - osTokenConfig.setRedeemer(newRedeemer); - _stopSnapshotGas(); - - // Verify redeemer was updated - assertEq(osTokenConfig.redeemer(), newRedeemer, 'Redeemer not updated correctly'); - - // Reset to original state for other tests - vm.prank(owner); - osTokenConfig.setRedeemer(currentRedeemer); - } - - // Test non-owner trying to set redeemer (should fail) - function test_setRedeemer_notOwner() public { - // Get current redeemer - address currentRedeemer = osTokenConfig.redeemer(); - - // Attempt to set redeemer as non-owner, should revert - vm.prank(nonOwner); - _startSnapshotGas('OsTokenConfigForkTest_test_setRedeemer_notOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - osTokenConfig.setRedeemer(newRedeemer); - _stopSnapshotGas(); - - // Verify redeemer was not changed - assertEq(osTokenConfig.redeemer(), currentRedeemer, 'Redeemer should not be changed'); - } - - // Test setting the same redeemer (should fail) - function test_setRedeemer_sameValue() public { - // Get current redeemer - address currentRedeemer = osTokenConfig.redeemer(); - - // Attempt to set the same redeemer, should revert - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_setRedeemer_sameValue'); - vm.expectRevert(Errors.ValueNotChanged.selector); - osTokenConfig.setRedeemer(currentRedeemer); - _stopSnapshotGas(); - - // Verify redeemer was not changed - assertEq(osTokenConfig.redeemer(), currentRedeemer, 'Redeemer should not be changed'); - } - - // Test updating config for a specific vault - function test_updateConfig_forVault() public { - // Create new config with reasonable values - IOsTokenConfig.Config memory newConfig = IOsTokenConfig.Config({ - ltvPercent: 7e17, // 70% - liqThresholdPercent: 8e17, // 80% - liqBonusPercent: 1.2e18 // 120% - }); - - // Set up expected event - vm.expectEmit(true, true, true, true); - emit IOsTokenConfig.OsTokenConfigUpdated( - vault, - newConfig.liqBonusPercent, - newConfig.liqThresholdPercent, - newConfig.ltvPercent - ); - - // Update config for vault - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_forVault'); - osTokenConfig.updateConfig(vault, newConfig); - _stopSnapshotGas(); - - // Verify config was updated for vault - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(vault); - assertEq(config.ltvPercent, newConfig.ltvPercent, 'Vault LTV not updated correctly'); - assertEq( - config.liqThresholdPercent, - newConfig.liqThresholdPercent, - 'Vault liquidation threshold not updated correctly' - ); - assertEq( - config.liqBonusPercent, - newConfig.liqBonusPercent, - 'Vault liquidation bonus not updated correctly' - ); - - // Get default config - IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); - - // Check default config was not affected - assertNotEq(config.ltvPercent, defaultConfig.ltvPercent, 'Default LTV should not be changed'); - assertNotEq( - config.liqThresholdPercent, - defaultConfig.liqThresholdPercent, - 'Default liquidation threshold should not be changed' - ); - assertNotEq( - config.liqBonusPercent, - defaultConfig.liqBonusPercent, - 'Default liquidation bonus should not be changed' - ); - } - - // Test non-owner trying to update config (should fail) - function test_updateConfig_notOwner() public { - // Create new config - IOsTokenConfig.Config memory newConfig = IOsTokenConfig.Config({ - ltvPercent: 7e17, // 70% - liqThresholdPercent: 8e17, // 80% - liqBonusPercent: 1.2e18 // 120% - }); - - // Attempt to update config as non-owner, should revert - vm.prank(nonOwner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_notOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - osTokenConfig.updateConfig(vault, newConfig); - _stopSnapshotGas(); - } - - // Test updating config with invalid LTV percent - function test_updateConfig_invalidLtvPercent() public { - // Get default config - IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); - - // Test with ltvPercent = 0 - IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 0, - liqThresholdPercent: defaultConfig.liqThresholdPercent, - liqBonusPercent: defaultConfig.liqBonusPercent - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_zero'); - vm.expectRevert(Errors.InvalidLtvPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - - // Test with ltvPercent > MAX_PERCENT (1e18) - invalidConfig = IOsTokenConfig.Config({ - ltvPercent: uint64(MAX_PERCENT + 1), - liqThresholdPercent: defaultConfig.liqThresholdPercent, - liqBonusPercent: defaultConfig.liqBonusPercent - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_tooHigh'); - vm.expectRevert(Errors.InvalidLtvPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - } - - // Test updating config with invalid liquidation threshold percent - function test_updateConfig_invalidLiqThresholdPercent() public { - // Test with liqThresholdPercent = 0 (when not disabled) - IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 5e17, // 50% - liqThresholdPercent: 0, - liqBonusPercent: 1.1e18 // 110% - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_zero'); - vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - - // Test with liqThresholdPercent >= MAX_PERCENT (1e18) - invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 5e17, // 50% - liqThresholdPercent: uint64(MAX_PERCENT), - liqBonusPercent: 1.1e18 // 110% - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_tooHigh'); - vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - - // Test with ltvPercent > liqThresholdPercent - invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 9e17, // 90% - liqThresholdPercent: 8e17, // 80% - liqBonusPercent: 1.1e18 // 110% - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_ltv'); - vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - } - - // Test updating config with invalid liquidation bonus percent - function test_updateConfig_invalidLiqBonusPercent() public { - // Test with liqBonusPercent < MAX_PERCENT (1e18) - IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 5e17, // 50% - liqThresholdPercent: 7e17, // 70% - liqBonusPercent: 0.9e18 // 90% - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_tooLow'); - vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - - // Test with threshold * bonus > MAX_PERCENT - // If threshold = 95% and bonus = 106%, then 0.95 * 1.06 = 1.007 > 1.0 - invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 8e17, // 80% - liqThresholdPercent: 95e16, // 95% - liqBonusPercent: 1.06e18 // 106% - }); - - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_product'); - vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - } - - // Test disabled liquidations configuration - function test_updateConfig_disabledLiquidations() public { - // Create config with disabled liquidations - IOsTokenConfig.Config memory disabledLiqConfig = IOsTokenConfig.Config({ - ltvPercent: 5e17, // 50% - liqThresholdPercent: uint64(DISABLED_LIQ_THRESHOLD), - liqBonusPercent: 0 // Must be 0 when liquidations disabled - }); - - // Update config for vault - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_disabledLiquidations'); - osTokenConfig.updateConfig(vault, disabledLiqConfig); - _stopSnapshotGas(); - - // Verify config was updated correctly - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(vault); - assertEq(config.ltvPercent, disabledLiqConfig.ltvPercent, 'Vault LTV not updated correctly'); - assertEq( - config.liqThresholdPercent, - uint64(DISABLED_LIQ_THRESHOLD), - 'Vault liquidation threshold should be disabled' - ); - assertEq(config.liqBonusPercent, 0, 'Vault liquidation bonus should be 0'); - } - - // Test invalid disabled liquidations configuration - function test_updateConfig_invalidDisabledLiquidations() public { - // Create config with disabled liquidations but non-zero bonus - IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ - ltvPercent: 5e17, // 50% - liqThresholdPercent: uint64(DISABLED_LIQ_THRESHOLD), - liqBonusPercent: 1.1e18 // Should be 0 when liquidations disabled - }); - - // Attempt to update config, should revert - vm.prank(owner); - _startSnapshotGas('OsTokenConfigForkTest_test_updateConfig_invalidDisabledLiquidations'); - vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); - osTokenConfig.updateConfig(vault, invalidConfig); - _stopSnapshotGas(); - } - - // Test getConfig for vault with no specific config - function test_getConfig_defaultFallback() public view { - // Get default config - IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); - - // Verify vault with no specific config gets default config - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(anotherVault); - assertEq(config.ltvPercent, defaultConfig.ltvPercent, 'Should return default LTV'); - assertEq( - config.liqThresholdPercent, - defaultConfig.liqThresholdPercent, - 'Should return default liquidation threshold' - ); - assertEq( - config.liqBonusPercent, - defaultConfig.liqBonusPercent, - 'Should return default liquidation bonus' - ); - } - - function test_updateDefaultConfig_success() public { - // Define new default configuration values - uint64 newLtvPercent = 0.7e18; // 70% - uint64 newLiqThresholdPercent = 0.8e18; // 80% - uint128 newLiqBonusPercent = 1.1e18; // 110% - - IOsTokenConfig.Config memory newDefaultConfig = IOsTokenConfig.Config({ - ltvPercent: newLtvPercent, - liqThresholdPercent: newLiqThresholdPercent, - liqBonusPercent: newLiqBonusPercent - }); - - // Test address that doesn't have a specific config - address randomVault = makeAddr('randomVault'); - - // Expect OsTokenConfigUpdated event - vm.expectEmit(true, false, true, true); - emit IOsTokenConfig.OsTokenConfigUpdated( - address(0), - newLiqBonusPercent, - newLiqThresholdPercent, - newLtvPercent - ); - - // Update the default configuration - vm.prank(owner); - _startSnapshotGas('OsTokenConfigTest_test_updateDefaultConfig_success'); - osTokenConfig.updateConfig(address(0), newDefaultConfig); - _stopSnapshotGas(); - - // Get the config for a random vault without specific config - IOsTokenConfig.Config memory retrievedConfig = osTokenConfig.getConfig(randomVault); - - // Verify the default config was updated and is returned for vaults without specific config - assertEq(retrievedConfig.ltvPercent, newLtvPercent, 'LTV percent not updated correctly'); - assertEq( - retrievedConfig.liqThresholdPercent, - newLiqThresholdPercent, - 'Liquidation threshold percent not updated correctly' - ); - assertEq( - retrievedConfig.liqBonusPercent, - newLiqBonusPercent, - 'Liquidation bonus percent not updated correctly' - ); - } + // Test setting the same redeemer (should fail) + function test_setRedeemer_sameValue() public { + // Get current redeemer + address currentRedeemer = osTokenConfig.redeemer(); + + // Attempt to set the same redeemer, should revert + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_setRedeemer_sameValue"); + vm.expectRevert(Errors.ValueNotChanged.selector); + osTokenConfig.setRedeemer(currentRedeemer); + _stopSnapshotGas(); + + // Verify redeemer was not changed + assertEq(osTokenConfig.redeemer(), currentRedeemer, "Redeemer should not be changed"); + } + + // Test updating config for a specific vault + function test_updateConfig_forVault() public { + // Create new config with reasonable values + IOsTokenConfig.Config memory newConfig = IOsTokenConfig.Config({ + ltvPercent: 7e17, // 70% + liqThresholdPercent: 8e17, // 80% + liqBonusPercent: 1.2e18 // 120% + }); + + // Set up expected event + vm.expectEmit(true, true, true, true); + emit IOsTokenConfig.OsTokenConfigUpdated( + vault, newConfig.liqBonusPercent, newConfig.liqThresholdPercent, newConfig.ltvPercent + ); + + // Update config for vault + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_forVault"); + osTokenConfig.updateConfig(vault, newConfig); + _stopSnapshotGas(); + + // Verify config was updated for vault + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(vault); + assertEq(config.ltvPercent, newConfig.ltvPercent, "Vault LTV not updated correctly"); + assertEq( + config.liqThresholdPercent, + newConfig.liqThresholdPercent, + "Vault liquidation threshold not updated correctly" + ); + assertEq(config.liqBonusPercent, newConfig.liqBonusPercent, "Vault liquidation bonus not updated correctly"); + + // Get default config + IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); + + // Check default config was not affected + assertNotEq(config.ltvPercent, defaultConfig.ltvPercent, "Default LTV should not be changed"); + assertNotEq( + config.liqThresholdPercent, + defaultConfig.liqThresholdPercent, + "Default liquidation threshold should not be changed" + ); + assertNotEq( + config.liqBonusPercent, defaultConfig.liqBonusPercent, "Default liquidation bonus should not be changed" + ); + } + + // Test non-owner trying to update config (should fail) + function test_updateConfig_notOwner() public { + // Create new config + IOsTokenConfig.Config memory newConfig = IOsTokenConfig.Config({ + ltvPercent: 7e17, // 70% + liqThresholdPercent: 8e17, // 80% + liqBonusPercent: 1.2e18 // 120% + }); + + // Attempt to update config as non-owner, should revert + vm.prank(nonOwner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_notOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + osTokenConfig.updateConfig(vault, newConfig); + _stopSnapshotGas(); + } + + // Test updating config with invalid LTV percent + function test_updateConfig_invalidLtvPercent() public { + // Get default config + IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); + + // Test with ltvPercent = 0 + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 0, + liqThresholdPercent: defaultConfig.liqThresholdPercent, + liqBonusPercent: defaultConfig.liqBonusPercent + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_zero"); + vm.expectRevert(Errors.InvalidLtvPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with ltvPercent > MAX_PERCENT (1e18) + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: uint64(MAX_PERCENT + 1), + liqThresholdPercent: defaultConfig.liqThresholdPercent, + liqBonusPercent: defaultConfig.liqBonusPercent + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_tooHigh"); + vm.expectRevert(Errors.InvalidLtvPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test updating config with invalid liquidation threshold percent + function test_updateConfig_invalidLiqThresholdPercent() public { + // Test with liqThresholdPercent = 0 (when not disabled) + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: 0, + liqBonusPercent: 1.1e18 // 110% + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_zero"); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with liqThresholdPercent >= MAX_PERCENT (1e18) + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: uint64(MAX_PERCENT), + liqBonusPercent: 1.1e18 // 110% + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_tooHigh"); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with ltvPercent > liqThresholdPercent + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 9e17, // 90% + liqThresholdPercent: 8e17, // 80% + liqBonusPercent: 1.1e18 // 110% + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_ltv"); + vm.expectRevert(Errors.InvalidLiqThresholdPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test updating config with invalid liquidation bonus percent + function test_updateConfig_invalidLiqBonusPercent() public { + // Test with liqBonusPercent < MAX_PERCENT (1e18) + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: 7e17, // 70% + liqBonusPercent: 0.9e18 // 90% + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_tooLow"); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + + // Test with threshold * bonus > MAX_PERCENT + // If threshold = 95% and bonus = 106%, then 0.95 * 1.06 = 1.007 > 1.0 + invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 8e17, // 80% + liqThresholdPercent: 95e16, // 95% + liqBonusPercent: 1.06e18 // 106% + }); + + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidLiqBonusPercent_product"); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test disabled liquidations configuration + function test_updateConfig_disabledLiquidations() public { + // Create config with disabled liquidations + IOsTokenConfig.Config memory disabledLiqConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: uint64(DISABLED_LIQ_THRESHOLD), + liqBonusPercent: 0 // Must be 0 when liquidations disabled + }); + + // Update config for vault + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_disabledLiquidations"); + osTokenConfig.updateConfig(vault, disabledLiqConfig); + _stopSnapshotGas(); + + // Verify config was updated correctly + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(vault); + assertEq(config.ltvPercent, disabledLiqConfig.ltvPercent, "Vault LTV not updated correctly"); + assertEq( + config.liqThresholdPercent, uint64(DISABLED_LIQ_THRESHOLD), "Vault liquidation threshold should be disabled" + ); + assertEq(config.liqBonusPercent, 0, "Vault liquidation bonus should be 0"); + } + + // Test invalid disabled liquidations configuration + function test_updateConfig_invalidDisabledLiquidations() public { + // Create config with disabled liquidations but non-zero bonus + IOsTokenConfig.Config memory invalidConfig = IOsTokenConfig.Config({ + ltvPercent: 5e17, // 50% + liqThresholdPercent: uint64(DISABLED_LIQ_THRESHOLD), + liqBonusPercent: 1.1e18 // Should be 0 when liquidations disabled + }); + + // Attempt to update config, should revert + vm.prank(owner); + _startSnapshotGas("OsTokenConfigForkTest_test_updateConfig_invalidDisabledLiquidations"); + vm.expectRevert(Errors.InvalidLiqBonusPercent.selector); + osTokenConfig.updateConfig(vault, invalidConfig); + _stopSnapshotGas(); + } + + // Test getConfig for vault with no specific config + function test_getConfig_defaultFallback() public view { + // Get default config + IOsTokenConfig.Config memory defaultConfig = osTokenConfig.getConfig(address(0)); + + // Verify vault with no specific config gets default config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(anotherVault); + assertEq(config.ltvPercent, defaultConfig.ltvPercent, "Should return default LTV"); + assertEq( + config.liqThresholdPercent, defaultConfig.liqThresholdPercent, "Should return default liquidation threshold" + ); + assertEq(config.liqBonusPercent, defaultConfig.liqBonusPercent, "Should return default liquidation bonus"); + } + + function test_updateDefaultConfig_success() public { + // Define new default configuration values + uint64 newLtvPercent = 0.7e18; // 70% + uint64 newLiqThresholdPercent = 0.8e18; // 80% + uint128 newLiqBonusPercent = 1.1e18; // 110% + + IOsTokenConfig.Config memory newDefaultConfig = IOsTokenConfig.Config({ + ltvPercent: newLtvPercent, + liqThresholdPercent: newLiqThresholdPercent, + liqBonusPercent: newLiqBonusPercent + }); + + // Test address that doesn't have a specific config + address randomVault = makeAddr("randomVault"); + + // Expect OsTokenConfigUpdated event + vm.expectEmit(true, false, true, true); + emit IOsTokenConfig.OsTokenConfigUpdated(address(0), newLiqBonusPercent, newLiqThresholdPercent, newLtvPercent); + + // Update the default configuration + vm.prank(owner); + _startSnapshotGas("OsTokenConfigTest_test_updateDefaultConfig_success"); + osTokenConfig.updateConfig(address(0), newDefaultConfig); + _stopSnapshotGas(); + + // Get the config for a random vault without specific config + IOsTokenConfig.Config memory retrievedConfig = osTokenConfig.getConfig(randomVault); + + // Verify the default config was updated and is returned for vaults without specific config + assertEq(retrievedConfig.ltvPercent, newLtvPercent, "LTV percent not updated correctly"); + assertEq( + retrievedConfig.liqThresholdPercent, + newLiqThresholdPercent, + "Liquidation threshold percent not updated correctly" + ); + assertEq(retrievedConfig.liqBonusPercent, newLiqBonusPercent, "Liquidation bonus percent not updated correctly"); + } } diff --git a/test/OsTokenFlashLoans.t.sol b/test/OsTokenFlashLoans.t.sol index ae3cb44c..f0c8f903 100644 --- a/test/OsTokenFlashLoans.t.sol +++ b/test/OsTokenFlashLoans.t.sol @@ -1,203 +1,197 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {OsTokenFlashLoans, IOsTokenFlashLoans} from '../contracts/tokens/OsTokenFlashLoans.sol'; -import {OsTokenFlashLoanRecipientMock} from '../contracts/mocks/OsTokenFlashLoanRecipientMock.sol'; -import {OsToken} from '../contracts/tokens/OsToken.sol'; -import {IOsTokenFlashLoanRecipient} from '../contracts/interfaces/IOsTokenFlashLoanRecipient.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {OsTokenFlashLoans, IOsTokenFlashLoans} from "../contracts/tokens/OsTokenFlashLoans.sol"; +import {OsTokenFlashLoanRecipientMock} from "../contracts/mocks/OsTokenFlashLoanRecipientMock.sol"; +import {OsToken} from "../contracts/tokens/OsToken.sol"; +import {IOsTokenFlashLoanRecipient} from "../contracts/interfaces/IOsTokenFlashLoanRecipient.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract OsTokenFlashLoansTest is Test, EthHelpers { - // Constants for deployed contracts - uint256 public constant MAX_FLASH_LOAN_AMOUNT = 100_000 ether; - - ForkContracts public contracts; - - // Contract instances - OsTokenFlashLoans public flashLoans; - OsToken public osToken; - OsTokenFlashLoanRecipientMock public recipient; - - // Test accounts - address public admin; - address public user; - - function setUp() public { - // Fork mainnet - contracts = _activateEthereumFork(); - - // Connect to deployed contracts - flashLoans = OsTokenFlashLoans(_osTokenFlashLoans); - osToken = OsToken(_osToken); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - vm.deal(user, 100 ether); - - // Deploy mock recipient - recipient = new OsTokenFlashLoanRecipientMock(_osToken, _osTokenFlashLoans); - - // Mint tokens to the recipient for repayment - _mintOsToken(address(recipient), 1000 ether); - } - - function test_flashLoan_success() public { - // Configure recipient to repay the loan - recipient.setShouldRepayLoan(true); - - uint256 flashLoanAmount = 100 ether; - - // Record pre-loan state - uint256 recipientPreBalance = osToken.balanceOf(address(recipient)); - uint256 flashLoansPreBalance = osToken.balanceOf(_osTokenFlashLoans); - - // Execute the flash loan - vm.expectEmit(true, true, false, false); - emit IOsTokenFlashLoans.OsTokenFlashLoan(address(recipient), flashLoanAmount); - - vm.prank(address(recipient)); - recipient.executeFlashLoan(flashLoanAmount, '0x'); - - // Verify post-loan state - uint256 recipientPostBalance = osToken.balanceOf(address(recipient)); - uint256 flashLoansPostBalance = osToken.balanceOf(_osTokenFlashLoans); - - // Flash loan contract's balance should be unchanged - // (It mints tokens, receives repayment, then burns the tokens) - assertEq( - flashLoansPostBalance, - flashLoansPreBalance, - 'Flash loans contract balance should remain the same' - ); - - // Recipient's balance should be reduced by the loan amount - // (It repays the loan from its own balance) - assertEq( - recipientPostBalance, - recipientPreBalance, - 'Recipient should have the same balance after repaying the loan' - ); - } - - function test_flashLoan_failure() public { - // Configure recipient to NOT repay the loan - recipient.setShouldRepayLoan(false); - - uint256 flashLoanAmount = 100 ether; - - // Execute flash loan - should revert because loan isn't repaid - vm.prank(address(recipient)); - vm.expectRevert(Errors.FlashLoanFailed.selector); - recipient.executeFlashLoan(flashLoanAmount, '0x'); - } - - function test_flashLoan_zeroAmount() public { - // Try to execute flash loan with 0 amount - should revert - vm.prank(address(recipient)); - vm.expectRevert(Errors.InvalidShares.selector); - recipient.executeFlashLoan(0, '0x'); - } - - function test_flashLoan_excessiveAmount() public { - // Try to execute flash loan with more than the max amount - should revert - uint256 excessiveAmount = MAX_FLASH_LOAN_AMOUNT + 1; - - vm.prank(address(recipient)); - vm.expectRevert(Errors.InvalidShares.selector); - recipient.executeFlashLoan(excessiveAmount, '0x'); - } - - function test_flashLoan_withUserData() public { - // Configure recipient to repay the loan - recipient.setShouldRepayLoan(true); - - uint256 flashLoanAmount = 100 ether; - bytes memory userData = abi.encode('test data'); - - // Execute flash loan with user data - vm.prank(address(recipient)); - recipient.executeFlashLoan(flashLoanAmount, userData); - - // Test passes if the loan executes without reverting - // (We can't easily verify the userData was received correctly without modifying the recipient) - } - - function test_flashLoan_maxAmount() public { - // Configure recipient to repay the loan - recipient.setShouldRepayLoan(true); - - // Ensure recipient has enough tokens to repay max loan - _mintOsToken(address(recipient), MAX_FLASH_LOAN_AMOUNT); - - // Execute flash loan with maximum allowed amount - vm.prank(address(recipient)); - recipient.executeFlashLoan(MAX_FLASH_LOAN_AMOUNT, '0x'); - - // Test passes if the loan executes without reverting - } - - function test_flashLoan_reentrancy() public { - // Create a malicious recipient that attempts re-entrancy - MaliciousRecipient malicious = new MaliciousRecipient(_osToken, _osTokenFlashLoans); - - // Mint tokens to the malicious recipient for repayment - _mintOsToken(address(recipient), 1000 ether); - - // Attempt the attack - should fail due to nonReentrant modifier - vm.prank(address(malicious)); - vm.expectRevert(); // Either a custom error or a low-level revert - malicious.executeAttack(100 ether); - } - - function test_flashLoan_gasUsage() public { - // Configure recipient to repay the loan - recipient.setShouldRepayLoan(true); - - uint256 flashLoanAmount = 100 ether; - - // Measure gas usage - vm.prank(address(recipient)); - uint256 gasStart = gasleft(); - recipient.executeFlashLoan(flashLoanAmount, '0x'); - uint256 gasUsed = gasStart - gasleft(); - - // Optional: assert gas usage is below a reasonable threshold - assertLt(gasUsed, 300000, 'Flash loan gas usage should be reasonable'); - } + // Constants for deployed contracts + uint256 public constant MAX_FLASH_LOAN_AMOUNT = 100_000 ether; + + ForkContracts public contracts; + + // Contract instances + OsTokenFlashLoans public flashLoans; + OsToken public osToken; + OsTokenFlashLoanRecipientMock public recipient; + + // Test accounts + address public admin; + address public user; + + function setUp() public { + // Fork mainnet + contracts = _activateEthereumFork(); + + // Connect to deployed contracts + flashLoans = OsTokenFlashLoans(_osTokenFlashLoans); + osToken = OsToken(_osToken); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + vm.deal(user, 100 ether); + + // Deploy mock recipient + recipient = new OsTokenFlashLoanRecipientMock(_osToken, _osTokenFlashLoans); + + // Mint tokens to the recipient for repayment + _mintOsToken(address(recipient), 1000 ether); + } + + function test_flashLoan_success() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + uint256 flashLoanAmount = 100 ether; + + // Record pre-loan state + uint256 recipientPreBalance = osToken.balanceOf(address(recipient)); + uint256 flashLoansPreBalance = osToken.balanceOf(_osTokenFlashLoans); + + // Execute the flash loan + vm.expectEmit(true, true, false, false); + emit IOsTokenFlashLoans.OsTokenFlashLoan(address(recipient), flashLoanAmount); + + vm.prank(address(recipient)); + recipient.executeFlashLoan(flashLoanAmount, "0x"); + + // Verify post-loan state + uint256 recipientPostBalance = osToken.balanceOf(address(recipient)); + uint256 flashLoansPostBalance = osToken.balanceOf(_osTokenFlashLoans); + + // Flash loan contract's balance should be unchanged + // (It mints tokens, receives repayment, then burns the tokens) + assertEq(flashLoansPostBalance, flashLoansPreBalance, "Flash loans contract balance should remain the same"); + + // Recipient's balance should be reduced by the loan amount + // (It repays the loan from its own balance) + assertEq( + recipientPostBalance, recipientPreBalance, "Recipient should have the same balance after repaying the loan" + ); + } + + function test_flashLoan_failure() public { + // Configure recipient to NOT repay the loan + recipient.setShouldRepayLoan(false); + + uint256 flashLoanAmount = 100 ether; + + // Execute flash loan - should revert because loan isn't repaid + vm.prank(address(recipient)); + vm.expectRevert(Errors.FlashLoanFailed.selector); + recipient.executeFlashLoan(flashLoanAmount, "0x"); + } + + function test_flashLoan_zeroAmount() public { + // Try to execute flash loan with 0 amount - should revert + vm.prank(address(recipient)); + vm.expectRevert(Errors.InvalidShares.selector); + recipient.executeFlashLoan(0, "0x"); + } + + function test_flashLoan_excessiveAmount() public { + // Try to execute flash loan with more than the max amount - should revert + uint256 excessiveAmount = MAX_FLASH_LOAN_AMOUNT + 1; + + vm.prank(address(recipient)); + vm.expectRevert(Errors.InvalidShares.selector); + recipient.executeFlashLoan(excessiveAmount, "0x"); + } + + function test_flashLoan_withUserData() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + uint256 flashLoanAmount = 100 ether; + bytes memory userData = abi.encode("test data"); + + // Execute flash loan with user data + vm.prank(address(recipient)); + recipient.executeFlashLoan(flashLoanAmount, userData); + + // Test passes if the loan executes without reverting + // (We can't easily verify the userData was received correctly without modifying the recipient) + } + + function test_flashLoan_maxAmount() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + // Ensure recipient has enough tokens to repay max loan + _mintOsToken(address(recipient), MAX_FLASH_LOAN_AMOUNT); + + // Execute flash loan with maximum allowed amount + vm.prank(address(recipient)); + recipient.executeFlashLoan(MAX_FLASH_LOAN_AMOUNT, "0x"); + + // Test passes if the loan executes without reverting + } + + function test_flashLoan_reentrancy() public { + // Create a malicious recipient that attempts re-entrancy + MaliciousRecipient malicious = new MaliciousRecipient(_osToken, _osTokenFlashLoans); + + // Mint tokens to the malicious recipient for repayment + _mintOsToken(address(recipient), 1000 ether); + + // Attempt the attack - should fail due to nonReentrant modifier + vm.prank(address(malicious)); + vm.expectRevert(); // Either a custom error or a low-level revert + malicious.executeAttack(100 ether); + } + + function test_flashLoan_gasUsage() public { + // Configure recipient to repay the loan + recipient.setShouldRepayLoan(true); + + uint256 flashLoanAmount = 100 ether; + + // Measure gas usage + vm.prank(address(recipient)); + uint256 gasStart = gasleft(); + recipient.executeFlashLoan(flashLoanAmount, "0x"); + uint256 gasUsed = gasStart - gasleft(); + + // Optional: assert gas usage is below a reasonable threshold + assertLt(gasUsed, 300000, "Flash loan gas usage should be reasonable"); + } } // A malicious recipient that attempts to perform a re-entrancy attack contract MaliciousRecipient is IOsTokenFlashLoanRecipient { - address public osToken; - address public flashLoanContract; - bool public attacking; + address public osToken; + address public flashLoanContract; + bool public attacking; + + constructor(address _osToken, address _flashLoanContract) { + osToken = _osToken; + flashLoanContract = _flashLoanContract; + } - constructor(address _osToken, address _flashLoanContract) { - osToken = _osToken; - flashLoanContract = _flashLoanContract; - } + function executeAttack(uint256 amount) external { + OsTokenFlashLoans(flashLoanContract).flashLoan(amount, "0x"); + } - function executeAttack(uint256 amount) external { - OsTokenFlashLoans(flashLoanContract).flashLoan(amount, '0x'); - } + function receiveFlashLoan(uint256 osTokenShares, bytes calldata) external override { + require(msg.sender == flashLoanContract, "Caller is not flash loan contract"); - function receiveFlashLoan(uint256 osTokenShares, bytes calldata) external override { - require(msg.sender == flashLoanContract, 'Caller is not flash loan contract'); + if (!attacking) { + attacking = true; - if (!attacking) { - attacking = true; + // Try to call flashLoan again (re-entrancy attempt) + OsTokenFlashLoans(flashLoanContract).flashLoan(osTokenShares, "0x"); - // Try to call flashLoan again (re-entrancy attempt) - OsTokenFlashLoans(flashLoanContract).flashLoan(osTokenShares, '0x'); + attacking = false; + } - attacking = false; + // Repay the original loan + IERC20(osToken).transfer(msg.sender, osTokenShares); } - - // Repay the original loan - IERC20(osToken).transfer(msg.sender, osTokenShares); - } } diff --git a/test/OwnMevEscrow.t.sol b/test/OwnMevEscrow.t.sol index 32ee7e68..21739435 100644 --- a/test/OwnMevEscrow.t.sol +++ b/test/OwnMevEscrow.t.sol @@ -1,205 +1,201 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {OwnMevEscrow} from '../contracts/vaults/ethereum/mev/OwnMevEscrow.sol'; -import {IVaultEthStaking} from '../contracts/interfaces/IVaultEthStaking.sol'; -import {IOwnMevEscrow} from '../contracts/interfaces/IOwnMevEscrow.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; +import {Test} from "forge-std/Test.sol"; +import {OwnMevEscrow} from "../contracts/vaults/ethereum/mev/OwnMevEscrow.sol"; +import {IVaultEthStaking} from "../contracts/interfaces/IVaultEthStaking.sol"; +import {IOwnMevEscrow} from "../contracts/interfaces/IOwnMevEscrow.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; contract OwnMevEscrowTest is Test, EthHelpers { - ForkContracts public contracts; - OwnMevEscrow public escrow; - EthVault public vault; - address public user; - address public admin; - - function setUp() public { - // Activate Ethereum fork - contracts = _activateEthereumFork(); - - // Setup test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - - // Create vault with own MEV escrow - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, true); - vault = EthVault(payable(vaultAddr)); - - // Get the vault's own MEV escrow - escrow = OwnMevEscrow(payable(vault.mevEscrow())); - } - - // Test 1: Verify initialization - function test_initialization() public view { - assertEq(escrow.vault(), address(vault), 'Vault address should match'); - } - - // Test 2: Receive ETH and emit event - function test_receiveMev() public { - uint256 sendAmount = 1 ether; - - // Expect MevReceived event - vm.expectEmit(true, true, true, true); - emit IOwnMevEscrow.MevReceived(sendAmount); - - // Send ETH to the escrow - vm.prank(user); - _startSnapshotGas('OwnMevEscrowTest_test_receiveMev'); - (bool success, ) = address(escrow).call{value: sendAmount}(''); - _stopSnapshotGas(); - assertTrue(success, 'Transfer to escrow failed'); - - // Verify balance - assertEq(address(escrow).balance, sendAmount, 'Escrow balance should be updated'); - } - - // Test 3: Successful harvest - function test_harvest_fromVault() public { - // Send ETH to the escrow - uint256 sendAmount = 1 ether; - vm.prank(user); - (bool success, ) = address(escrow).call{value: sendAmount}(''); - assertTrue(success, 'Transfer to escrow failed'); - - // Get initial vault balance - uint256 initialVaultBalance = address(vault).balance; - - // Expect Harvested event - vm.expectEmit(true, true, true, true); - emit IOwnMevEscrow.Harvested(sendAmount); - - // Harvest from vault - vm.prank(address(vault)); - _startSnapshotGas('OwnMevEscrowTest_test_harvest_fromVault'); - uint256 harvested = escrow.harvest(); - _stopSnapshotGas(); - - // Verify harvested amount - assertEq(harvested, sendAmount, 'Harvest should return correct amount'); - - // Verify escrow balance is zero - assertEq(address(escrow).balance, 0, 'Escrow balance should be zero after harvest'); - - // Verify vault balance increased - assertEq( - address(vault).balance, - initialVaultBalance + sendAmount, - 'Vault balance should increase' - ); - } - - // Test 4: Failed harvest from non-vault - function test_harvest_fromNonVault() public { - // Send ETH to the escrow - uint256 sendAmount = 1 ether; - vm.prank(user); - (bool success, ) = address(escrow).call{value: sendAmount}(''); - assertTrue(success, 'Transfer to escrow failed'); - - // Try to harvest from non-vault account - vm.prank(user); - _startSnapshotGas('OwnMevEscrowTest_test_harvest_fromNonVault'); - vm.expectRevert(Errors.HarvestFailed.selector); - escrow.harvest(); - _stopSnapshotGas(); - - // Verify escrow balance unchanged - assertEq(address(escrow).balance, sendAmount, 'Escrow balance should remain unchanged'); - } - - // Test 5: Harvest with zero balance - function test_harvest_zeroBalance() public { - // Verify escrow has zero balance initially - assertEq(address(escrow).balance, 0, 'Escrow should start with zero balance'); - - // Harvest from vault with zero balance - vm.prank(address(vault)); - _startSnapshotGas('OwnMevEscrowTest_test_harvest_zeroBalance'); - uint256 harvested = escrow.harvest(); - _stopSnapshotGas(); - - // Verify returned zero - assertEq(harvested, 0, 'Harvest should return zero for empty escrow'); - } - - // Test 6: Multiple harvests - function test_multipleHarvests() public { - // Send ETH to the escrow multiple times - uint256 firstAmount = 1 ether; - vm.prank(user); - (bool success1, ) = address(escrow).call{value: firstAmount}(''); - assertTrue(success1, 'First transfer to escrow failed'); - - // Harvest first time - vm.prank(address(vault)); - uint256 firstHarvest = escrow.harvest(); - assertEq(firstHarvest, firstAmount, 'First harvest amount incorrect'); - - // Send more ETH - uint256 secondAmount = 2 ether; - vm.prank(user); - (bool success2, ) = address(escrow).call{value: secondAmount}(''); - assertTrue(success2, 'Second transfer to escrow failed'); - - // Harvest second time - vm.prank(address(vault)); - _startSnapshotGas('OwnMevEscrowTest_test_multipleHarvests'); - uint256 secondHarvest = escrow.harvest(); - _stopSnapshotGas(); - assertEq(secondHarvest, secondAmount, 'Second harvest amount incorrect'); - } - - // Test 7: Multiple senders - function test_multipleSenders() public { - // Create another user - address anotherUser = makeAddr('anotherUser'); - vm.deal(anotherUser, 5 ether); - - // Send ETH from multiple accounts - uint256 firstAmount = 1 ether; - vm.prank(user); - (bool success1, ) = address(escrow).call{value: firstAmount}(''); - assertTrue(success1, 'First transfer to escrow failed'); - - uint256 secondAmount = 2 ether; - vm.prank(anotherUser); - (bool success2, ) = address(escrow).call{value: secondAmount}(''); - assertTrue(success2, 'Second transfer to escrow failed'); - - // Verify escrow balance is the sum of both transfers - assertEq(address(escrow).balance, firstAmount + secondAmount, 'Escrow balance incorrect'); - - // Harvest all funds at once - vm.prank(address(vault)); - _startSnapshotGas('OwnMevEscrowTest_test_multipleSenders'); - uint256 harvested = escrow.harvest(); - _stopSnapshotGas(); - - // Verify harvested the total amount - assertEq(harvested, firstAmount + secondAmount, 'Harvested amount incorrect'); - } - - // Test 8: Create escrow directly - function test_createEscrowDirectly() public { - address newVault = makeAddr('newVault'); - - // Create a new escrow with newVault as the vault address - OwnMevEscrow newEscrow = new OwnMevEscrow(newVault); - - // Verify initialization - assertEq(newEscrow.vault(), newVault, 'New escrow vault address incorrect'); - } + ForkContracts public contracts; + OwnMevEscrow public escrow; + EthVault public vault; + address public user; + address public admin; + + function setUp() public { + // Activate Ethereum fork + contracts = _activateEthereumFork(); + + // Setup test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault with own MEV escrow + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, true); + vault = EthVault(payable(vaultAddr)); + + // Get the vault's own MEV escrow + escrow = OwnMevEscrow(payable(vault.mevEscrow())); + } + + // Test 1: Verify initialization + function test_initialization() public view { + assertEq(escrow.vault(), address(vault), "Vault address should match"); + } + + // Test 2: Receive ETH and emit event + function test_receiveMev() public { + uint256 sendAmount = 1 ether; + + // Expect MevReceived event + vm.expectEmit(true, true, true, true); + emit IOwnMevEscrow.MevReceived(sendAmount); + + // Send ETH to the escrow + vm.prank(user); + _startSnapshotGas("OwnMevEscrowTest_test_receiveMev"); + (bool success,) = address(escrow).call{value: sendAmount}(""); + _stopSnapshotGas(); + assertTrue(success, "Transfer to escrow failed"); + + // Verify balance + assertEq(address(escrow).balance, sendAmount, "Escrow balance should be updated"); + } + + // Test 3: Successful harvest + function test_harvest_fromVault() public { + // Send ETH to the escrow + uint256 sendAmount = 1 ether; + vm.prank(user); + (bool success,) = address(escrow).call{value: sendAmount}(""); + assertTrue(success, "Transfer to escrow failed"); + + // Get initial vault balance + uint256 initialVaultBalance = address(vault).balance; + + // Expect Harvested event + vm.expectEmit(true, true, true, true); + emit IOwnMevEscrow.Harvested(sendAmount); + + // Harvest from vault + vm.prank(address(vault)); + _startSnapshotGas("OwnMevEscrowTest_test_harvest_fromVault"); + uint256 harvested = escrow.harvest(); + _stopSnapshotGas(); + + // Verify harvested amount + assertEq(harvested, sendAmount, "Harvest should return correct amount"); + + // Verify escrow balance is zero + assertEq(address(escrow).balance, 0, "Escrow balance should be zero after harvest"); + + // Verify vault balance increased + assertEq(address(vault).balance, initialVaultBalance + sendAmount, "Vault balance should increase"); + } + + // Test 4: Failed harvest from non-vault + function test_harvest_fromNonVault() public { + // Send ETH to the escrow + uint256 sendAmount = 1 ether; + vm.prank(user); + (bool success,) = address(escrow).call{value: sendAmount}(""); + assertTrue(success, "Transfer to escrow failed"); + + // Try to harvest from non-vault account + vm.prank(user); + _startSnapshotGas("OwnMevEscrowTest_test_harvest_fromNonVault"); + vm.expectRevert(Errors.HarvestFailed.selector); + escrow.harvest(); + _stopSnapshotGas(); + + // Verify escrow balance unchanged + assertEq(address(escrow).balance, sendAmount, "Escrow balance should remain unchanged"); + } + + // Test 5: Harvest with zero balance + function test_harvest_zeroBalance() public { + // Verify escrow has zero balance initially + assertEq(address(escrow).balance, 0, "Escrow should start with zero balance"); + + // Harvest from vault with zero balance + vm.prank(address(vault)); + _startSnapshotGas("OwnMevEscrowTest_test_harvest_zeroBalance"); + uint256 harvested = escrow.harvest(); + _stopSnapshotGas(); + + // Verify returned zero + assertEq(harvested, 0, "Harvest should return zero for empty escrow"); + } + + // Test 6: Multiple harvests + function test_multipleHarvests() public { + // Send ETH to the escrow multiple times + uint256 firstAmount = 1 ether; + vm.prank(user); + (bool success1,) = address(escrow).call{value: firstAmount}(""); + assertTrue(success1, "First transfer to escrow failed"); + + // Harvest first time + vm.prank(address(vault)); + uint256 firstHarvest = escrow.harvest(); + assertEq(firstHarvest, firstAmount, "First harvest amount incorrect"); + + // Send more ETH + uint256 secondAmount = 2 ether; + vm.prank(user); + (bool success2,) = address(escrow).call{value: secondAmount}(""); + assertTrue(success2, "Second transfer to escrow failed"); + + // Harvest second time + vm.prank(address(vault)); + _startSnapshotGas("OwnMevEscrowTest_test_multipleHarvests"); + uint256 secondHarvest = escrow.harvest(); + _stopSnapshotGas(); + assertEq(secondHarvest, secondAmount, "Second harvest amount incorrect"); + } + + // Test 7: Multiple senders + function test_multipleSenders() public { + // Create another user + address anotherUser = makeAddr("anotherUser"); + vm.deal(anotherUser, 5 ether); + + // Send ETH from multiple accounts + uint256 firstAmount = 1 ether; + vm.prank(user); + (bool success1,) = address(escrow).call{value: firstAmount}(""); + assertTrue(success1, "First transfer to escrow failed"); + + uint256 secondAmount = 2 ether; + vm.prank(anotherUser); + (bool success2,) = address(escrow).call{value: secondAmount}(""); + assertTrue(success2, "Second transfer to escrow failed"); + + // Verify escrow balance is the sum of both transfers + assertEq(address(escrow).balance, firstAmount + secondAmount, "Escrow balance incorrect"); + + // Harvest all funds at once + vm.prank(address(vault)); + _startSnapshotGas("OwnMevEscrowTest_test_multipleSenders"); + uint256 harvested = escrow.harvest(); + _stopSnapshotGas(); + + // Verify harvested the total amount + assertEq(harvested, firstAmount + secondAmount, "Harvested amount incorrect"); + } + + // Test 8: Create escrow directly + function test_createEscrowDirectly() public { + address newVault = makeAddr("newVault"); + + // Create a new escrow with newVault as the vault address + OwnMevEscrow newEscrow = new OwnMevEscrow(newVault); + + // Verify initialization + assertEq(newEscrow.vault(), newVault, "New escrow vault address incorrect"); + } } diff --git a/test/PriceFeed.t.sol b/test/PriceFeed.t.sol index 938cd10b..27ba27b0 100644 --- a/test/PriceFeed.t.sol +++ b/test/PriceFeed.t.sol @@ -1,158 +1,137 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {PriceFeed} from '../contracts/tokens/PriceFeed.sol'; -import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; -import {IChainlinkAggregator} from '../contracts/interfaces/IChainlinkAggregator.sol'; -import {IChainlinkV3Aggregator} from '../contracts/interfaces/IChainlinkV3Aggregator.sol'; -import {IBalancerRateProvider} from '../contracts/interfaces/IBalancerRateProvider.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {PriceFeed} from "../contracts/tokens/PriceFeed.sol"; +import {IOsTokenVaultController} from "../contracts/interfaces/IOsTokenVaultController.sol"; +import {IChainlinkAggregator} from "../contracts/interfaces/IChainlinkAggregator.sol"; +import {IChainlinkV3Aggregator} from "../contracts/interfaces/IChainlinkV3Aggregator.sol"; +import {IBalancerRateProvider} from "../contracts/interfaces/IBalancerRateProvider.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract PriceFeedTest is Test, EthHelpers { - // Test contracts - PriceFeed public priceFeed; - IOsTokenVaultController public osTokenVaultController; - - // Test addresses - address public user; - - // Fork contracts - ForkContracts public contracts; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - osTokenVaultController = contracts.osTokenVaultController; - - // Set up test accounts - user = makeAddr('user'); - - // Deploy the PriceFeed contract - priceFeed = new PriceFeed(address(osTokenVaultController), 'StakeWise osETH/ETH Price Feed'); - } - - // Test constructor and initialization - function test_constructor() public view { - assertEq( - priceFeed.osTokenVaultController(), - address(osTokenVaultController), - 'OsTokenVaultController address not set correctly' - ); - assertEq( - priceFeed.description(), - 'StakeWise osETH/ETH Price Feed', - 'Description not set correctly' - ); - assertEq(priceFeed.version(), 0, 'Version should be 0'); - } - - // Test getRate function (Balancer interface) - function test_getRate() public view { - uint256 rate = priceFeed.getRate(); - - // Get the expected rate directly from the vault controller - uint256 expectedRate = osTokenVaultController.convertToAssets(10 ** priceFeed.decimals()); - - assertEq(rate, expectedRate, 'Rate should match osTokenVaultController.convertToAssets'); - } - - // Test getRate with gas snapshot - function test_getRate_gas() public { - _startSnapshotGas('PriceFeedTest_test_getRate_gas'); - priceFeed.getRate(); - _stopSnapshotGas(); - } - - // Test latestAnswer function (Chainlink interface) - function test_latestAnswer() public view { - int256 answer = priceFeed.latestAnswer(); - - // Get the expected rate directly from the vault controller - uint256 expectedRate = osTokenVaultController.convertToAssets(10 ** priceFeed.decimals()); - - assertEq(answer, int256(expectedRate), 'Answer should match the rate from getRate()'); - } - - // Test latestAnswer with gas snapshot - function test_latestAnswer_gas() public { - _startSnapshotGas('PriceFeedTest_test_latestAnswer_gas'); - priceFeed.latestAnswer(); - _stopSnapshotGas(); - } - - // Test latestTimestamp function - function test_latestTimestamp() public view { - uint256 timestamp = priceFeed.latestTimestamp(); - assertEq(timestamp, block.timestamp, 'Timestamp should be the current block timestamp'); - } - - // Test decimals function - function test_decimals() public view { - uint8 dec = priceFeed.decimals(); - assertEq(dec, 18, 'Decimals should be 18'); - } - - // Test latestRoundData function (Chainlink V3 interface) - function test_latestRoundData() public view { - ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) = priceFeed.latestRoundData(); - - // Check return values - assertEq(roundId, 0, 'RoundId should be 0'); - - int256 expectedAnswer = priceFeed.latestAnswer(); - assertEq(answer, expectedAnswer, 'Answer should match latestAnswer()'); - - assertEq(startedAt, block.timestamp, 'StartedAt should be current block timestamp'); - assertEq(updatedAt, block.timestamp, 'UpdatedAt should be current block timestamp'); - assertEq(answeredInRound, 0, 'AnsweredInRound should be 0'); - } - - // Test latestRoundData with gas snapshot - function test_latestRoundData_gas() public { - _startSnapshotGas('PriceFeedTest_test_latestRoundData_gas'); - priceFeed.latestRoundData(); - _stopSnapshotGas(); - } - - // Test consistency between different interface methods - function test_interfaceConsistency() public view { - uint256 balancerRate = priceFeed.getRate(); - int256 chainlinkAnswer = priceFeed.latestAnswer(); - - assertEq( - int256(balancerRate), - chainlinkAnswer, - 'Balancer rate and Chainlink answer should be consistent' - ); - - (, int256 roundDataAnswer, , , ) = priceFeed.latestRoundData(); - - assertEq( - chainlinkAnswer, - roundDataAnswer, - 'Chainlink answer and round data answer should be consistent' - ); - } - - // Test timestamp consistency across methods - function test_timestampConsistency() public view { - uint256 timestamp = priceFeed.latestTimestamp(); - - (, , uint256 startedAt, uint256 updatedAt, ) = priceFeed.latestRoundData(); - - assertEq( - timestamp, - block.timestamp, - 'Timestamp from latestTimestamp should be block.timestamp' - ); - assertEq(startedAt, block.timestamp, 'StartedAt should be block.timestamp'); - assertEq(updatedAt, block.timestamp, 'UpdatedAt should be block.timestamp'); - } + // Test contracts + PriceFeed public priceFeed; + IOsTokenVaultController public osTokenVaultController; + + // Test addresses + address public user; + + // Fork contracts + ForkContracts public contracts; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + osTokenVaultController = contracts.osTokenVaultController; + + // Set up test accounts + user = makeAddr("user"); + + // Deploy the PriceFeed contract + priceFeed = new PriceFeed(address(osTokenVaultController), "StakeWise osETH/ETH Price Feed"); + } + + // Test constructor and initialization + function test_constructor() public view { + assertEq( + priceFeed.osTokenVaultController(), + address(osTokenVaultController), + "OsTokenVaultController address not set correctly" + ); + assertEq(priceFeed.description(), "StakeWise osETH/ETH Price Feed", "Description not set correctly"); + assertEq(priceFeed.version(), 0, "Version should be 0"); + } + + // Test getRate function (Balancer interface) + function test_getRate() public view { + uint256 rate = priceFeed.getRate(); + + // Get the expected rate directly from the vault controller + uint256 expectedRate = osTokenVaultController.convertToAssets(10 ** priceFeed.decimals()); + + assertEq(rate, expectedRate, "Rate should match osTokenVaultController.convertToAssets"); + } + + // Test getRate with gas snapshot + function test_getRate_gas() public { + _startSnapshotGas("PriceFeedTest_test_getRate_gas"); + priceFeed.getRate(); + _stopSnapshotGas(); + } + + // Test latestAnswer function (Chainlink interface) + function test_latestAnswer() public view { + int256 answer = priceFeed.latestAnswer(); + + // Get the expected rate directly from the vault controller + uint256 expectedRate = osTokenVaultController.convertToAssets(10 ** priceFeed.decimals()); + + assertEq(answer, int256(expectedRate), "Answer should match the rate from getRate()"); + } + + // Test latestAnswer with gas snapshot + function test_latestAnswer_gas() public { + _startSnapshotGas("PriceFeedTest_test_latestAnswer_gas"); + priceFeed.latestAnswer(); + _stopSnapshotGas(); + } + + // Test latestTimestamp function + function test_latestTimestamp() public view { + uint256 timestamp = priceFeed.latestTimestamp(); + assertEq(timestamp, block.timestamp, "Timestamp should be the current block timestamp"); + } + + // Test decimals function + function test_decimals() public view { + uint8 dec = priceFeed.decimals(); + assertEq(dec, 18, "Decimals should be 18"); + } + + // Test latestRoundData function (Chainlink V3 interface) + function test_latestRoundData() public view { + (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = + priceFeed.latestRoundData(); + + // Check return values + assertEq(roundId, 0, "RoundId should be 0"); + + int256 expectedAnswer = priceFeed.latestAnswer(); + assertEq(answer, expectedAnswer, "Answer should match latestAnswer()"); + + assertEq(startedAt, block.timestamp, "StartedAt should be current block timestamp"); + assertEq(updatedAt, block.timestamp, "UpdatedAt should be current block timestamp"); + assertEq(answeredInRound, 0, "AnsweredInRound should be 0"); + } + + // Test latestRoundData with gas snapshot + function test_latestRoundData_gas() public { + _startSnapshotGas("PriceFeedTest_test_latestRoundData_gas"); + priceFeed.latestRoundData(); + _stopSnapshotGas(); + } + + // Test consistency between different interface methods + function test_interfaceConsistency() public view { + uint256 balancerRate = priceFeed.getRate(); + int256 chainlinkAnswer = priceFeed.latestAnswer(); + + assertEq(int256(balancerRate), chainlinkAnswer, "Balancer rate and Chainlink answer should be consistent"); + + (, int256 roundDataAnswer,,,) = priceFeed.latestRoundData(); + + assertEq(chainlinkAnswer, roundDataAnswer, "Chainlink answer and round data answer should be consistent"); + } + + // Test timestamp consistency across methods + function test_timestampConsistency() public view { + uint256 timestamp = priceFeed.latestTimestamp(); + + (,, uint256 startedAt, uint256 updatedAt,) = priceFeed.latestRoundData(); + + assertEq(timestamp, block.timestamp, "Timestamp from latestTimestamp should be block.timestamp"); + assertEq(startedAt, block.timestamp, "StartedAt should be block.timestamp"); + assertEq(updatedAt, block.timestamp, "UpdatedAt should be block.timestamp"); + } } diff --git a/test/SharedMevEscrow.t.sol b/test/SharedMevEscrow.t.sol index 05c49bac..2600f06a 100644 --- a/test/SharedMevEscrow.t.sol +++ b/test/SharedMevEscrow.t.sol @@ -1,201 +1,193 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; -import {SharedMevEscrow} from '../contracts/vaults/ethereum/mev/SharedMevEscrow.sol'; -import {ISharedMevEscrow} from '../contracts/interfaces/ISharedMevEscrow.sol'; -import {IVaultEthStaking} from '../contracts/interfaces/IVaultEthStaking.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; +import {Test} from "forge-std/Test.sol"; +import {VaultsRegistry} from "../contracts/vaults/VaultsRegistry.sol"; +import {SharedMevEscrow} from "../contracts/vaults/ethereum/mev/SharedMevEscrow.sol"; +import {ISharedMevEscrow} from "../contracts/interfaces/ISharedMevEscrow.sol"; +import {IVaultEthStaking} from "../contracts/interfaces/IVaultEthStaking.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; // Mock VaultEthStaking for testing contract MockVaultEthStaking { - uint256 public receivedAmount; + uint256 public receivedAmount; - function receiveFromMevEscrow() external payable { - receivedAmount += msg.value; - } + function receiveFromMevEscrow() external payable { + receivedAmount += msg.value; + } } // Mock non-compliant vault that doesn't implement receiveFromMevEscrow contract MockNonCompliantVault { - // No receiveFromMevEscrow function +// No receiveFromMevEscrow function } contract SharedMevEscrowTest is Test { - VaultsRegistry public vaultsRegistry; - SharedMevEscrow public mevEscrow; - - address public owner; - MockVaultEthStaking public registeredVault; - address public nonRegisteredAccount; - MockNonCompliantVault public nonCompliantVault; - address public mevSender; - - uint256 public mevAmount = 1 ether; - - function setUp() public { - // Setup test accounts - owner = makeAddr('owner'); - nonRegisteredAccount = makeAddr('nonRegisteredAccount'); - mevSender = makeAddr('mevSender'); - - // Fund accounts - vm.deal(mevSender, 10 ether); - - // Deploy VaultsRegistry - vm.prank(owner); - vaultsRegistry = new VaultsRegistry(); - - // Deploy mock vaults - registeredVault = new MockVaultEthStaking(); - nonCompliantVault = new MockNonCompliantVault(); - - // Register compliant vault - vm.prank(owner); - vaultsRegistry.addVault(address(registeredVault)); - - // Register non-compliant vault - vm.prank(owner); - vaultsRegistry.addVault(address(nonCompliantVault)); - - // Deploy SharedMevEscrow - mevEscrow = new SharedMevEscrow(address(vaultsRegistry)); - } - - function test_initialization() public view { - // Verify the VaultsRegistry is set correctly - assertTrue(address(vaultsRegistry) != address(0), 'VaultsRegistry should be set'); - } - - function test_receiveMev() public { - // Initial balance - uint256 initialBalance = address(mevEscrow).balance; - - // Expect MevReceived event - vm.expectEmit(true, true, true, true); - emit ISharedMevEscrow.MevReceived(mevAmount); - - // Send MEV to escrow - vm.prank(mevSender); - (bool success, ) = address(mevEscrow).call{value: mevAmount}(''); - - // Verify transfer successful - assertTrue(success, 'MEV transfer should succeed'); - assertEq( - address(mevEscrow).balance, - initialBalance + mevAmount, - 'MEV escrow balance should increase' - ); - } - - function test_harvest_registered() public { - // Send MEV to escrow - vm.deal(address(mevEscrow), mevAmount); - - // Expect Harvested event - vm.expectEmit(true, true, true, true); - emit ISharedMevEscrow.Harvested(address(registeredVault), mevAmount); - - // Harvest MEV - vm.prank(address(registeredVault)); - mevEscrow.harvest(mevAmount); - - // Verify successful harvest - assertEq(registeredVault.receivedAmount(), mevAmount, 'Vault should receive MEV'); - assertEq(address(mevEscrow).balance, 0, 'MEV escrow should be empty after harvest'); - } - - function test_harvest_nonRegistered() public { - // Send MEV to escrow - vm.deal(address(mevEscrow), mevAmount); - - // Attempt to harvest from non-registered account - vm.prank(nonRegisteredAccount); - vm.expectRevert(Errors.HarvestFailed.selector); - mevEscrow.harvest(mevAmount); - - // Verify no MEV was harvested - assertEq(address(mevEscrow).balance, mevAmount, 'MEV escrow balance should remain unchanged'); - } - - function test_harvest_nonCompliantVault() public { - // Send MEV to escrow - vm.deal(address(mevEscrow), mevAmount); - - // Attempt to harvest from non-compliant vault - // This should revert because the vault doesn't implement receiveFromMevEscrow - vm.prank(address(nonCompliantVault)); - vm.expectRevert(); - mevEscrow.harvest(mevAmount); - - // Verify no MEV was harvested - assertEq(address(mevEscrow).balance, mevAmount, 'MEV escrow balance should remain unchanged'); - } - - function test_harvest_partialAmount() public { - // Send MEV to escrow - vm.deal(address(mevEscrow), mevAmount); - - // Partial harvest - uint256 harvestAmount = mevAmount / 2; - - // Expect Harvested event - vm.expectEmit(true, true, true, true); - emit ISharedMevEscrow.Harvested(address(registeredVault), harvestAmount); - - // Harvest partial MEV - vm.prank(address(registeredVault)); - mevEscrow.harvest(harvestAmount); - - // Verify partial harvest - assertEq(registeredVault.receivedAmount(), harvestAmount, 'Vault should receive partial MEV'); - assertEq( - address(mevEscrow).balance, - mevAmount - harvestAmount, - 'MEV escrow should contain remaining MEV' - ); - } - - function test_harvest_multipleVaults() public { - // Deploy another mock vault - MockVaultEthStaking anotherVault = new MockVaultEthStaking(); - - // Register the another vault - vm.prank(owner); - vaultsRegistry.addVault(address(anotherVault)); - - // Send MEV to escrow - vm.deal(address(mevEscrow), mevAmount * 2); - - // First vault harvests - vm.prank(address(registeredVault)); - mevEscrow.harvest(mevAmount); - - // Second vault harvests - vm.prank(address(anotherVault)); - mevEscrow.harvest(mevAmount); - - // Verify both harvests - assertEq(registeredVault.receivedAmount(), mevAmount, 'First vault should receive MEV'); - assertEq(anotherVault.receivedAmount(), mevAmount, 'Second vault should receive MEV'); - assertEq(address(mevEscrow).balance, 0, 'MEV escrow should be empty after both harvests'); - } - - function test_harvest_exceedBalance() public { - // Send MEV to escrow - vm.deal(address(mevEscrow), mevAmount); - - // Attempt to harvest more than available - uint256 excessAmount = mevAmount * 2; - - // This should revert due to insufficient balance - vm.prank(address(registeredVault)); - vm.expectRevert(); - mevEscrow.harvest(excessAmount); - - // Verify no MEV was harvested - assertEq(registeredVault.receivedAmount(), 0, 'Vault should not receive any MEV'); - assertEq(address(mevEscrow).balance, mevAmount, 'MEV escrow balance should remain unchanged'); - } + VaultsRegistry public vaultsRegistry; + SharedMevEscrow public mevEscrow; + + address public owner; + MockVaultEthStaking public registeredVault; + address public nonRegisteredAccount; + MockNonCompliantVault public nonCompliantVault; + address public mevSender; + + uint256 public mevAmount = 1 ether; + + function setUp() public { + // Setup test accounts + owner = makeAddr("owner"); + nonRegisteredAccount = makeAddr("nonRegisteredAccount"); + mevSender = makeAddr("mevSender"); + + // Fund accounts + vm.deal(mevSender, 10 ether); + + // Deploy VaultsRegistry + vm.prank(owner); + vaultsRegistry = new VaultsRegistry(); + + // Deploy mock vaults + registeredVault = new MockVaultEthStaking(); + nonCompliantVault = new MockNonCompliantVault(); + + // Register compliant vault + vm.prank(owner); + vaultsRegistry.addVault(address(registeredVault)); + + // Register non-compliant vault + vm.prank(owner); + vaultsRegistry.addVault(address(nonCompliantVault)); + + // Deploy SharedMevEscrow + mevEscrow = new SharedMevEscrow(address(vaultsRegistry)); + } + + function test_initialization() public view { + // Verify the VaultsRegistry is set correctly + assertTrue(address(vaultsRegistry) != address(0), "VaultsRegistry should be set"); + } + + function test_receiveMev() public { + // Initial balance + uint256 initialBalance = address(mevEscrow).balance; + + // Expect MevReceived event + vm.expectEmit(true, true, true, true); + emit ISharedMevEscrow.MevReceived(mevAmount); + + // Send MEV to escrow + vm.prank(mevSender); + (bool success,) = address(mevEscrow).call{value: mevAmount}(""); + + // Verify transfer successful + assertTrue(success, "MEV transfer should succeed"); + assertEq(address(mevEscrow).balance, initialBalance + mevAmount, "MEV escrow balance should increase"); + } + + function test_harvest_registered() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Expect Harvested event + vm.expectEmit(true, true, true, true); + emit ISharedMevEscrow.Harvested(address(registeredVault), mevAmount); + + // Harvest MEV + vm.prank(address(registeredVault)); + mevEscrow.harvest(mevAmount); + + // Verify successful harvest + assertEq(registeredVault.receivedAmount(), mevAmount, "Vault should receive MEV"); + assertEq(address(mevEscrow).balance, 0, "MEV escrow should be empty after harvest"); + } + + function test_harvest_nonRegistered() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Attempt to harvest from non-registered account + vm.prank(nonRegisteredAccount); + vm.expectRevert(Errors.HarvestFailed.selector); + mevEscrow.harvest(mevAmount); + + // Verify no MEV was harvested + assertEq(address(mevEscrow).balance, mevAmount, "MEV escrow balance should remain unchanged"); + } + + function test_harvest_nonCompliantVault() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Attempt to harvest from non-compliant vault + // This should revert because the vault doesn't implement receiveFromMevEscrow + vm.prank(address(nonCompliantVault)); + vm.expectRevert(); + mevEscrow.harvest(mevAmount); + + // Verify no MEV was harvested + assertEq(address(mevEscrow).balance, mevAmount, "MEV escrow balance should remain unchanged"); + } + + function test_harvest_partialAmount() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Partial harvest + uint256 harvestAmount = mevAmount / 2; + + // Expect Harvested event + vm.expectEmit(true, true, true, true); + emit ISharedMevEscrow.Harvested(address(registeredVault), harvestAmount); + + // Harvest partial MEV + vm.prank(address(registeredVault)); + mevEscrow.harvest(harvestAmount); + + // Verify partial harvest + assertEq(registeredVault.receivedAmount(), harvestAmount, "Vault should receive partial MEV"); + assertEq(address(mevEscrow).balance, mevAmount - harvestAmount, "MEV escrow should contain remaining MEV"); + } + + function test_harvest_multipleVaults() public { + // Deploy another mock vault + MockVaultEthStaking anotherVault = new MockVaultEthStaking(); + + // Register the another vault + vm.prank(owner); + vaultsRegistry.addVault(address(anotherVault)); + + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount * 2); + + // First vault harvests + vm.prank(address(registeredVault)); + mevEscrow.harvest(mevAmount); + + // Second vault harvests + vm.prank(address(anotherVault)); + mevEscrow.harvest(mevAmount); + + // Verify both harvests + assertEq(registeredVault.receivedAmount(), mevAmount, "First vault should receive MEV"); + assertEq(anotherVault.receivedAmount(), mevAmount, "Second vault should receive MEV"); + assertEq(address(mevEscrow).balance, 0, "MEV escrow should be empty after both harvests"); + } + + function test_harvest_exceedBalance() public { + // Send MEV to escrow + vm.deal(address(mevEscrow), mevAmount); + + // Attempt to harvest more than available + uint256 excessAmount = mevAmount * 2; + + // This should revert due to insufficient balance + vm.prank(address(registeredVault)); + vm.expectRevert(); + mevEscrow.harvest(excessAmount); + + // Verify no MEV was harvested + assertEq(registeredVault.receivedAmount(), 0, "Vault should not receive any MEV"); + assertEq(address(mevEscrow).balance, mevAmount, "MEV escrow balance should remain unchanged"); + } } diff --git a/test/VaultAdmin.t.sol b/test/VaultAdmin.t.sol index 0ad25ce9..bea0bd94 100644 --- a/test/VaultAdmin.t.sol +++ b/test/VaultAdmin.t.sol @@ -1,150 +1,146 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IVaultAdmin} from '../contracts/interfaces/IVaultAdmin.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {CommonBase} from '../lib/forge-std/src/Base.sol'; -import {StdAssertions} from '../lib/forge-std/src/StdAssertions.sol'; -import {StdChains} from '../lib/forge-std/src/StdChains.sol'; -import {StdCheats, StdCheatsSafe} from '../lib/forge-std/src/StdCheats.sol'; -import {StdUtils} from '../lib/forge-std/src/StdUtils.sol'; -import {Test} from '../lib/forge-std/src/Test.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultAdmin} from "../contracts/interfaces/IVaultAdmin.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {CommonBase} from "../lib/forge-std/src/Base.sol"; +import {StdAssertions} from "../lib/forge-std/src/StdAssertions.sol"; +import {StdChains} from "../lib/forge-std/src/StdChains.sol"; +import {StdCheats, StdCheatsSafe} from "../lib/forge-std/src/StdCheats.sol"; +import {StdUtils} from "../lib/forge-std/src/StdUtils.sol"; +import {Test} from "../lib/forge-std/src/Test.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract VaultAdminTest is Test, EthHelpers { - ForkContracts public contracts; - address public vault; - - address public admin; - address public nonAdmin; - address public newAdmin; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - nonAdmin = makeAddr('nonAdmin'); - newAdmin = makeAddr('newAdmin'); - - // Create a vault with admin as the admin - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'initialIpfsHash' - }) - ); - vault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - } - - function test_initialization() public { - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'initialIpfsHash' - }) - ); - - _startSnapshotGas('VaultAdminTest_test_initialization'); - address newVault = _createVault(VaultType.EthVault, admin, initParams, false); - _stopSnapshotGas(); - - assertEq( - IVaultAdmin(newVault).admin(), - admin, - 'Admin should be set correctly during initialization' - ); - } - - function test_initialAdmin() public view { - assertEq(IVaultAdmin(vault).admin(), admin, 'Initial admin should be set correctly'); - } - - function test_setAdmin_byAdmin() public { - // Expect the AdminUpdated event - vm.expectEmit(true, true, false, false); - emit IVaultAdmin.AdminUpdated(admin, newAdmin); - - // Call setAdmin as the current admin - vm.prank(admin); - _startSnapshotGas('VaultAdminTest_test_setAdmin_byAdmin'); - IVaultAdmin(vault).setAdmin(newAdmin); - _stopSnapshotGas(); - - // Verify admin was updated - assertEq(IVaultAdmin(vault).admin(), newAdmin, 'Admin should be updated'); - } - - function test_setAdmin_byNonAdmin() public { - // Call setAdmin as a non-admin user - vm.prank(nonAdmin); - _startSnapshotGas('VaultAdminTest_test_setAdmin_byNonAdmin'); - vm.expectRevert(Errors.AccessDenied.selector); - IVaultAdmin(vault).setAdmin(newAdmin); - _stopSnapshotGas(); - - // Verify admin was not changed - assertEq(IVaultAdmin(vault).admin(), admin, 'Admin should not be changed by non-admin'); - } - - function test_setAdmin_toZeroAddress() public { - // Call setAdmin with zero address - vm.prank(admin); - _startSnapshotGas('VaultAdminTest_test_setAdmin_toZeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - IVaultAdmin(vault).setAdmin(address(0)); - _stopSnapshotGas(); - - // Verify admin was not changed - assertEq(IVaultAdmin(vault).admin(), admin, 'Admin should not be changed to zero address'); - } - - function test_setMetadata_byAdmin() public { - string memory newMetadata = 'newIpfsHash'; - - // Expect the MetadataUpdated event - vm.expectEmit(true, false, false, false); - emit IVaultAdmin.MetadataUpdated(admin, newMetadata); - - // Call setMetadata as the admin - vm.prank(admin); - _startSnapshotGas('VaultAdminTest_test_setMetadata_byAdmin'); - IVaultAdmin(vault).setMetadata(newMetadata); - _stopSnapshotGas(); - } - - function test_setMetadata_byNonAdmin() public { - string memory newMetadata = 'newIpfsHash'; - - // Call setMetadata as a non-admin user - vm.prank(nonAdmin); - _startSnapshotGas('VaultAdminTest_test_setMetadata_byNonAdmin'); - vm.expectRevert(Errors.AccessDenied.selector); - IVaultAdmin(vault).setMetadata(newMetadata); - _stopSnapshotGas(); - } - - function test_checkAdmin_withOtherFunctions() public { - // Test some other functions that use _checkAdmin internally - - // Set fee recipient (from VaultFee which uses _checkAdmin) - vm.prank(nonAdmin); - _startSnapshotGas('VaultAdminTest_test_checkAdmin_withOtherFunctions_nonAdmin'); - vm.expectRevert(Errors.AccessDenied.selector); - IEthVault(vault).setFeeRecipient(nonAdmin); - _stopSnapshotGas(); - - // Now try as admin - vm.prank(admin); - _startSnapshotGas('VaultAdminTest_test_checkAdmin_withOtherFunctions_admin'); - IEthVault(vault).setFeeRecipient(admin); - _stopSnapshotGas(); - - // Verify fee recipient was updated - assertEq(IEthVault(vault).feeRecipient(), admin, 'Fee recipient should be updated by admin'); - } + ForkContracts public contracts; + address public vault; + + address public admin; + address public nonAdmin; + address public newAdmin; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + nonAdmin = makeAddr("nonAdmin"); + newAdmin = makeAddr("newAdmin"); + + // Create a vault with admin as the admin + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "initialIpfsHash" + }) + ); + vault = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + } + + function test_initialization() public { + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "initialIpfsHash" + }) + ); + + _startSnapshotGas("VaultAdminTest_test_initialization"); + address newVault = _createVault(VaultType.EthVault, admin, initParams, false); + _stopSnapshotGas(); + + assertEq(IVaultAdmin(newVault).admin(), admin, "Admin should be set correctly during initialization"); + } + + function test_initialAdmin() public view { + assertEq(IVaultAdmin(vault).admin(), admin, "Initial admin should be set correctly"); + } + + function test_setAdmin_byAdmin() public { + // Expect the AdminUpdated event + vm.expectEmit(true, true, false, false); + emit IVaultAdmin.AdminUpdated(admin, newAdmin); + + // Call setAdmin as the current admin + vm.prank(admin); + _startSnapshotGas("VaultAdminTest_test_setAdmin_byAdmin"); + IVaultAdmin(vault).setAdmin(newAdmin); + _stopSnapshotGas(); + + // Verify admin was updated + assertEq(IVaultAdmin(vault).admin(), newAdmin, "Admin should be updated"); + } + + function test_setAdmin_byNonAdmin() public { + // Call setAdmin as a non-admin user + vm.prank(nonAdmin); + _startSnapshotGas("VaultAdminTest_test_setAdmin_byNonAdmin"); + vm.expectRevert(Errors.AccessDenied.selector); + IVaultAdmin(vault).setAdmin(newAdmin); + _stopSnapshotGas(); + + // Verify admin was not changed + assertEq(IVaultAdmin(vault).admin(), admin, "Admin should not be changed by non-admin"); + } + + function test_setAdmin_toZeroAddress() public { + // Call setAdmin with zero address + vm.prank(admin); + _startSnapshotGas("VaultAdminTest_test_setAdmin_toZeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + IVaultAdmin(vault).setAdmin(address(0)); + _stopSnapshotGas(); + + // Verify admin was not changed + assertEq(IVaultAdmin(vault).admin(), admin, "Admin should not be changed to zero address"); + } + + function test_setMetadata_byAdmin() public { + string memory newMetadata = "newIpfsHash"; + + // Expect the MetadataUpdated event + vm.expectEmit(true, false, false, false); + emit IVaultAdmin.MetadataUpdated(admin, newMetadata); + + // Call setMetadata as the admin + vm.prank(admin); + _startSnapshotGas("VaultAdminTest_test_setMetadata_byAdmin"); + IVaultAdmin(vault).setMetadata(newMetadata); + _stopSnapshotGas(); + } + + function test_setMetadata_byNonAdmin() public { + string memory newMetadata = "newIpfsHash"; + + // Call setMetadata as a non-admin user + vm.prank(nonAdmin); + _startSnapshotGas("VaultAdminTest_test_setMetadata_byNonAdmin"); + vm.expectRevert(Errors.AccessDenied.selector); + IVaultAdmin(vault).setMetadata(newMetadata); + _stopSnapshotGas(); + } + + function test_checkAdmin_withOtherFunctions() public { + // Test some other functions that use _checkAdmin internally + + // Set fee recipient (from VaultFee which uses _checkAdmin) + vm.prank(nonAdmin); + _startSnapshotGas("VaultAdminTest_test_checkAdmin_withOtherFunctions_nonAdmin"); + vm.expectRevert(Errors.AccessDenied.selector); + IEthVault(vault).setFeeRecipient(nonAdmin); + _stopSnapshotGas(); + + // Now try as admin + vm.prank(admin); + _startSnapshotGas("VaultAdminTest_test_checkAdmin_withOtherFunctions_admin"); + IEthVault(vault).setFeeRecipient(admin); + _stopSnapshotGas(); + + // Verify fee recipient was updated + assertEq(IEthVault(vault).feeRecipient(), admin, "Fee recipient should be updated by admin"); + } } diff --git a/test/VaultEnterExit.t.sol b/test/VaultEnterExit.t.sol index c3bc3b07..17cbd1e1 100644 --- a/test/VaultEnterExit.t.sol +++ b/test/VaultEnterExit.t.sol @@ -1,793 +1,684 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract VaultEnterExitTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - - address public sender; - address public sender2; - address public receiver; - address public admin; - address public referrer = address(0); - - uint256 public depositAmount = 1 ether; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - sender2 = makeAddr('sender2'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - - // Fund accounts with ETH for testing - vm.deal(sender, 100 ether); - vm.deal(sender2, 100 ether); - vm.deal(admin, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - (uint128 queuedShares, , uint128 totalExitingAssets, ,) = vault.getExitQueueData(); - vm.deal( - address(vault), - address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets - ); - } - - function test_deposit_zeroAddress() public { - // Try to deposit to address(0) - vm.prank(sender); - vm.expectRevert(Errors.ZeroAddress.selector); - _startSnapshotGas('VaultEnterExitTest_test_deposit_zeroAddress'); - vault.deposit{value: depositAmount}(address(0), referrer); - _stopSnapshotGas(); - } - - function test_deposit_zeroAmount() public { - // Try to deposit 0 ETH - vm.prank(sender); - vm.expectRevert(Errors.InvalidAssets.selector); - _startSnapshotGas('VaultEnterExitTest_test_deposit_zeroAmount'); - vault.deposit{value: 0}(receiver, referrer); - _stopSnapshotGas(); - } - - function test_deposit_exceedingCapacity() public { - // Create a new vault with a small capacity - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 33 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - EthVault smallVault = EthVault(payable(vaultAddr)); - - // First deposit an amount under capacity - _depositToVault(address(smallVault), 32 ether, sender, sender); - - // Then try to deposit an amount that would exceed capacity - vm.prank(sender); - vm.expectRevert(Errors.CapacityExceeded.selector); - _startSnapshotGas('VaultEnterExitTest_test_deposit_exceedingCapacity'); - smallVault.deposit{value: 1.1 ether}(sender, referrer); - _stopSnapshotGas(); - } - - function test_deposit_success_basic() public { - // Record initial balances and state - uint256 senderBalanceBefore = sender.balance; - uint256 vaultBalanceBefore = address(vault).balance; - uint256 totalSharesBefore = vault.totalShares(); - uint256 totalAssetsBefore = vault.totalAssets(); - - // Perform the deposit - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_deposit_success_basic'); - uint256 shares = vault.deposit{value: depositAmount}(sender, referrer); - _stopSnapshotGas(); - - // Verify ETH was transferred correctly - assertEq( - sender.balance, - senderBalanceBefore - depositAmount, - "Sender's ETH balance should decrease" - ); - assertEq( - address(vault).balance, - vaultBalanceBefore + depositAmount, - "Vault's ETH balance should increase" - ); - - // Verify shares were minted correctly - assertEq(vault.getShares(sender), shares, 'Sender should receive the correct number of shares'); - assertEq( - vault.totalShares(), - totalSharesBefore + shares, - 'Total shares should increase by the minted amount' - ); - assertEq( - vault.totalAssets(), - totalAssetsBefore + depositAmount, - 'Total assets should increase by deposit amount' - ); - - // Verify the conversion between assets and shares - assertEq( - vault.convertToAssets(shares), - depositAmount, - 'Shares should convert back to the deposited amount' - ); - } - - function test_deposit_success_differentReceiver() public { - // Record initial balances and state - uint256 senderSharesBefore = vault.getShares(sender); - uint256 receiverSharesBefore = vault.getShares(receiver); - - // Perform the deposit with a different receiver - uint256 depositAssets = 1.5 ether; - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_deposit_success_differentReceiver'); - uint256 shares = vault.deposit{value: depositAssets}(receiver, referrer); - _stopSnapshotGas(); - - // Verify shares were minted to the receiver, not the sender - assertEq(vault.getShares(sender), senderSharesBefore, "Sender's shares should not change"); - assertEq( - vault.getShares(receiver), - receiverSharesBefore + shares, - 'Receiver should get the minted shares' - ); - } - - function test_deposit_success_multipleDeposits() public { - // First deposit - uint256 firstDeposit = 1 ether; - vm.prank(sender); - uint256 firstShares = vault.deposit{value: firstDeposit}(sender, referrer); - - // Second deposit - uint256 secondDeposit = 2 ether; - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_deposit_success_multipleDeposits'); - uint256 secondShares = vault.deposit{value: secondDeposit}(sender, referrer); - _stopSnapshotGas(); - - // Check the relationship between deposits - // Second deposit is 2x the first, so should get approximately 2x the shares - // (allowing for minor differences due to rounding or fees) - assertApproxEqRel( - secondShares, - firstShares * 2, - 0.01e18, // 1% tolerance - 'Second deposit should get proportional shares relative to the first deposit' - ); - - // Verify total shares - assertEq( - vault.getShares(sender), - firstShares + secondShares, - 'Total shares should be the sum of both deposits' - ); - } - - function test_deposit_success_withReferrer() public { - // Set up a referrer - address validReferrer = makeAddr('referrer'); - - // Record initial balances and state - uint256 senderBalanceBefore = sender.balance; - uint256 vaultBalanceBefore = address(vault).balance; - - // Perform the deposit with a referrer - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_deposit_success_withReferrer'); - uint256 shares = vault.deposit{value: depositAmount}(sender, validReferrer); - _stopSnapshotGas(); - - // Verify deposit succeeded with referrer - assertEq( - sender.balance, - senderBalanceBefore - depositAmount, - "Sender's ETH balance should decrease" - ); - assertEq( - address(vault).balance, - vaultBalanceBefore + depositAmount, - "Vault's ETH balance should increase" - ); - assertEq(vault.getShares(sender), shares, 'Sender should receive the correct number of shares'); - - // Note: In a real implementation, we might want to check for referral tracking or rewards, - // but the current contract doesn't seem to have specific referrer handling beyond the event - } - - function test_deposit_success_receiveFunction() public { - // Record initial balances and state - uint256 senderBalanceBefore = sender.balance; - uint256 vaultBalanceBefore = address(vault).balance; - uint256 senderSharesBefore = vault.getShares(sender); - - // Deposit using the receive function (direct transfer) - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_deposit_success_receiveFunction'); - (bool success, ) = address(vault).call{value: depositAmount}(''); - _stopSnapshotGas(); - - // Verify transfer succeeded - assertTrue(success, 'Direct transfer should succeed'); - - // Verify ETH was transferred correctly - assertEq( - sender.balance, - senderBalanceBefore - depositAmount, - "Sender's ETH balance should decrease" - ); - assertEq( - address(vault).balance, - vaultBalanceBefore + depositAmount, - "Vault's ETH balance should increase" - ); - - // Verify shares were minted to the sender - assertGt(vault.getShares(sender), senderSharesBefore, 'Sender should receive shares'); - } - - function test_enterExitQueue_basicFlow() public { - // 1. Deposit ETH - _depositToVault(address(vault), depositAmount, sender, sender); - - // 2. Collateralize the vault (required for exit queue to work with actual validators) - _collateralizeEthVault(address(vault)); - - // 3. Enter exit queue - uint256 shares = vault.getShares(sender); - (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_basicFlow'); - uint256 positionTicket = vault.enterExitQueue(shares, receiver); - _stopSnapshotGas(); - - // 4. Verify the position ticket was created and shares moved to the queue - (uint128 queuedShares, , , ,) = vault.getExitQueueData(); - assertEq( - queuedShares, - queuedSharesBefore + shares, - 'Queued shares should equal the shares sent to exit queue' - ); - assertEq(vault.getShares(sender), 0, 'Sender should have 0 shares after entering exit queue'); - - // 5. Process the exit queue (update state) - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 6. Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // 7. Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); - - // 8. Calculate exited assets - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault - .calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); - - assertApproxEqAbs(leftTickets, 0, 1, 'All tickets should be processed'); - assertApproxEqAbs(exitedTickets, shares, 1, 'Exited tickets should equal the shares entered'); - assertApproxEqAbs( - exitedAssets, - depositAmount, - 1e9, - 'Exited assets should approximately equal deposit amount' - ); - - // 9. Claim exited assets - uint256 receiverBalanceBefore = address(receiver).balance; - - vm.prank(receiver); - _startSnapshotGas('VaultEnterExitTest_test_claimExitedAssets'); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // 10. Verify assets were transferred to the receiver - uint256 receiverBalanceAfter = address(receiver).balance; - assertEq( - receiverBalanceAfter - receiverBalanceBefore, - exitedAssets, - 'Receiver should have received the exited assets' - ); - } - - function test_enterExitQueue_directRedemption() public { - address _newVault = _createVault( - VaultType.EthVault, - admin, - abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ), - false - ); - IEthVault newVault = IEthVault(_newVault); - - // 1. Deposit ETH - _depositToVault(_newVault, depositAmount, sender, sender); - - // 2. Enter exit queue (without collateralizing the vault) - uint256 shares = newVault.getShares(sender); - uint256 assets = newVault.convertToAssets(shares); - - uint256 receiverBalanceBefore = address(receiver).balance; - - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_directRedemption'); - uint256 positionTicket = newVault.enterExitQueue(shares, receiver); - _stopSnapshotGas(); - - // 3. Verify direct redemption occurred (max uint256 ticket indicates direct redemption) - assertEq( - positionTicket, - type(uint256).max, - 'Position ticket should be max uint256 for direct redemption' - ); - assertEq(newVault.getShares(sender), 0, 'Sender should have 0 shares after direct redemption'); - assertApproxEqAbs( - address(receiver).balance - receiverBalanceBefore, - assets, - 1e9, - 'Assets should be transferred directly to receiver' - ); - } - - function test_claimExitedAssets_insufficientDelay() public { - // 1. Deposit ETH - _depositToVault(address(vault), depositAmount, sender, sender); - - // 2. Collateralize the vault - _collateralizeEthVault(address(vault)); - - // 3. Enter exit queue - uint256 shares = vault.getShares(sender); - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - uint256 positionTicket = vault.enterExitQueue(shares, receiver); - - // 4. Process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 5. Try to claim before the delay has passed - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); - - vm.prank(receiver); - _startSnapshotGas('VaultEnterExitTest_test_claimExitedAssets_insufficientDelay'); - vm.expectRevert(Errors.ExitRequestNotProcessed.selector); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - } - - function test_enterExitQueue_invalidParams() public { - // 1. Deposit ETH - _depositToVault(address(vault), depositAmount, sender, sender); - - // 2. Try to enter exit queue with 0 shares - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroShares'); - vm.expectRevert(Errors.InvalidShares.selector); - vault.enterExitQueue(0, receiver); - _stopSnapshotGas(); - - // 3. Try to enter exit queue with zero address as receiver - uint256 sharesToExit = vault.getShares(sender); - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.enterExitQueue(sharesToExit, address(0)); - _stopSnapshotGas(); - - // 4. Try to enter exit queue with more shares than owned - uint256 shares = vault.getShares(sender); - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_invalidParams_tooManyShares'); - vm.expectRevert(); // Should revert with arithmetic underflow - vault.enterExitQueue(shares + 1, receiver); - _stopSnapshotGas(); - } - - function test_calculateExitedAssets_invalidPosition() public { - // Try to calculate exited assets for a non-existent position - _startSnapshotGas('VaultEnterExitTest_test_calculateExitedAssets_invalidPosition'); - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault - .calculateExitedAssets( - receiver, - 999, // Non-existent position ticket - vm.getBlockTimestamp(), - 0 - ); - _stopSnapshotGas(); - - assertEq(leftTickets, 0, 'Left tickets should be 0 for non-existent position'); - assertEq(exitedTickets, 0, 'Exited tickets should be 0 for non-existent position'); - assertEq(exitedAssets, 0, 'Exited assets should be 0 for non-existent position'); - } - - function test_claimExitedAssets_invalidCheckpoint() public { - // 1. Deposit ETH - _depositToVault(address(vault), depositAmount, sender, sender); - - // 2. Collateralize the vault - _collateralizeEthVault(address(vault)); - - // 3. Enter exit queue - uint256 shares = vault.getShares(sender); - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - uint256 positionTicket = vault.enterExitQueue(shares, receiver); - - // 4. Process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 5. Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // 6. Try to claim with an invalid checkpoint index - vm.prank(receiver); - _startSnapshotGas('VaultEnterExitTest_test_claimExitedAssets_invalidCheckpoint'); - vm.expectRevert(Errors.ExitRequestNotProcessed.selector); - vault.claimExitedAssets( - positionTicket, - timestamp, - 999 // Invalid checkpoint index - ); - _stopSnapshotGas(); - } - - function test_enterExitQueue_multiUser() public { - // 1. Both users deposit ETH - _depositToVault(address(vault), depositAmount, sender, sender); - _depositToVault(address(vault), depositAmount * 2, sender2, sender2); - - // 2. Collateralize the vault - _collateralizeEthVault(address(vault)); - - // 3. Both users enter exit queue - uint256 shares1 = vault.getShares(sender); - uint256 shares2 = vault.getShares(sender2); - - (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); - - vm.prank(sender); - uint256 timestamp1 = vm.getBlockTimestamp(); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_multiUser_user1'); - uint256 positionTicket1 = vault.enterExitQueue(shares1, receiver); - _stopSnapshotGas(); - - vm.prank(sender2); - uint256 timestamp2 = vm.getBlockTimestamp(); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_multiUser_sender2'); - uint256 positionTicket2 = vault.enterExitQueue(shares2, sender2); - _stopSnapshotGas(); - - // 4. Verify the queued shares - (uint128 queuedShares, , , ,) = vault.getExitQueueData(); - assertEq( - queuedShares, - queuedSharesBefore + shares1 + shares2, - 'Queued shares should equal the sum of all shares in exit queue' - ); - - // 5. Process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 6. Wait for claim delay to pass - vm.warp(timestamp2 + _exitingAssetsClaimDelay + 1); - - // 7. Both users claim their assets - int256 exitQueueIndex1 = vault.getExitQueueIndex(positionTicket1); - int256 exitQueueIndex2 = vault.getExitQueueIndex(positionTicket2); - - assertGt(exitQueueIndex1, -1, 'Exit queue index 1 should be valid'); - assertGt(exitQueueIndex2, -1, 'Exit queue index 2 should be valid'); - - (, , uint256 exitedAssets1) = vault.calculateExitedAssets( - receiver, - positionTicket1, - timestamp1, - uint256(exitQueueIndex1) - ); - - (, , uint256 exitedAssets2) = vault.calculateExitedAssets( - sender2, - positionTicket2, - timestamp2, - uint256(exitQueueIndex2) - ); - - // push down the stack - uint256 timestamp1_ = timestamp1; - uint256 timestamp2_ = timestamp2; - uint256 positionTicket1_ = positionTicket1; - uint256 positionTicket2_ = positionTicket2; - uint256 exitQueueIndex1_ = uint256(exitQueueIndex1); - uint256 exitQueueIndex2_ = uint256(exitQueueIndex2); - - uint256 receiverBalanceBefore = address(receiver).balance; - uint256 sender2BalanceBefore = address(sender2).balance; - - vm.prank(receiver); - vault.claimExitedAssets(positionTicket1_, timestamp1_, exitQueueIndex1_); - - vm.prank(sender2); - vault.claimExitedAssets(positionTicket2_, timestamp2_, exitQueueIndex2_); - - // 8. Verify assets were transferred to the respective receivers - uint256 receiverBalanceAfter = address(receiver).balance; - uint256 sender2BalanceAfter = address(sender2).balance; - - assertEq( - receiverBalanceAfter - receiverBalanceBefore, - exitedAssets1, - 'Receiver should have received the correct exited assets' - ); - assertEq( - sender2BalanceAfter - sender2BalanceBefore, - exitedAssets2, - 'Sender2 should have received the correct exited assets' - ); - } - - function test_enterExitQueue_partialExit() public { - // 1. Deposit ETH - _depositToVault(address(vault), depositAmount * 2, sender, sender); - - // 2. Collateralize the vault - _collateralizeEthVault(address(vault)); - (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); - - // 3. Enter exit queue with half of the shares - uint256 totalShares = vault.getShares(sender); - uint256 halfShares = totalShares / 2; - - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_partialExit'); - uint256 positionTicket = vault.enterExitQueue(halfShares, receiver); - _stopSnapshotGas(); - - // 4. Verify the position ticket and remaining shares - (uint128 queuedShares, , , ,) = vault.getExitQueueData(); - assertEq( - queuedShares, - queuedSharesBefore + halfShares, - 'Queued shares should equal the half shares sent to exit queue' - ); - assertEq( - vault.getShares(sender), - halfShares, - 'Sender should have half of the original shares left' - ); - - // 5. Process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 6. Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // 7. Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); - - // 8. Calculate exited assets - (, , uint256 exitedAssets) = vault.calculateExitedAssets( - receiver, - positionTicket, - timestamp, - uint256(exitQueueIndex) - ); - - // 9. Claim exited assets - uint256 receiverBalanceBefore = address(receiver).balance; - vm.prank(receiver); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - uint256 receiverBalanceAfter = address(receiver).balance; - - // 10. Verify assets were transferred to the receiver - assertEq( - receiverBalanceAfter - receiverBalanceBefore, - exitedAssets, - 'Receiver should have received the exited assets' - ); - - // 11. Verify sender still has the remaining shares - assertEq( - vault.getShares(sender), - halfShares, - 'Sender should still have half of the original shares' - ); - } - - function test_enterExitQueue_afterValidatorExit() public { - // 1. Deposit ETH - _depositToVault(address(vault), 40 ether, sender, sender); - - // 2. Register a validator with 32 ETH - _registerEthValidator(address(vault), 32 ether, true); - - // 3. Simulate validator exit - vm.deal(address(vault), address(vault).balance + 32 ether); - - // 4. Enter exit queue - uint256 shares = vault.getShares(sender); - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_afterValidatorExit'); - uint256 positionTicket = vault.enterExitQueue(shares, receiver); - _stopSnapshotGas(); - - // 5. Process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 6. Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // 7. Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); - - // 8. Calculate exited assets - (, , uint256 exitedAssets) = vault.calculateExitedAssets( - receiver, - positionTicket, - timestamp, - uint256(exitQueueIndex) - ); - - // 9. Claim exited assets - uint256 receiverBalanceBefore = address(receiver).balance; - vm.prank(receiver); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - uint256 receiverBalanceAfter = address(receiver).balance; - - // 10. Verify assets were transferred to the receiver - assertApproxEqAbs( - exitedAssets, - 40 ether, - 1, - 'Receiver should have received at least the initial deposit' - ); - assertEq( - receiverBalanceAfter - receiverBalanceBefore, - exitedAssets, - 'Receiver should have received the exited assets' - ); - } - - function test_enterExitQueue_multipleUpdates() public { - address _newVault = _createVault( - VaultType.EthVault, - admin, - abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ), - false - ); - IEthVault newVault = IEthVault(_newVault); - - // 1. Deposit a large amount of ETH - _depositToVault(_newVault, 100 ether, sender, sender); - - // 2. Collateralize the vault - _collateralizeEthVault(_newVault); - - // 3. Enter exit queue with all shares - uint256 shares = newVault.getShares(sender); - uint256 timestamp = vm.getBlockTimestamp(); - - vm.prank(sender); - _startSnapshotGas('VaultEnterExitTest_test_enterExitQueue_multipleUpdates'); - uint256 positionTicket = newVault.enterExitQueue(shares, receiver); - _stopSnapshotGas(); - - uint256 vaultBalanceBefore = _newVault.balance; - vm.deal(_newVault, 0); - - // 4. Process the exit queue in multiple updates - // First update with a penalty (to reduce the available assets) - IKeeperRewards.HarvestParams memory harvestParams1 = _setEthVaultReward( - _newVault, - int160(-30 ether), - 0 - ); - newVault.updateState(harvestParams1); - - // Second update with a reward - IKeeperRewards.HarvestParams memory harvestParams2 = _setEthVaultReward( - _newVault, - int160(15 ether), - 0 - ); - newVault.updateState(harvestParams2); - - // Final update with remaining balance - vm.deal(_newVault, vaultBalanceBefore); - IKeeperRewards.HarvestParams memory harvestParams3 = _setEthVaultReward( - _newVault, - int160(15 ether), - 0 - ); - newVault.updateState(harvestParams3); - - // 5. Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // 6. Get exit queue index - int256 exitQueueIndex = newVault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index should be valid'); - - // 7. Calculate exited assets - (, , uint256 exitedAssets) = newVault.calculateExitedAssets( - receiver, - positionTicket, - timestamp, - uint256(exitQueueIndex) - ); - - // 8. Claim exited assets - uint256 receiverBalanceBefore = address(receiver).balance; - vm.prank(receiver); - newVault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - uint256 receiverBalanceAfter = address(receiver).balance; - - // 9. Verify assets were transferred to the receiver - uint256 receivedAssets = receiverBalanceAfter - receiverBalanceBefore; - assertEq(receivedAssets, exitedAssets, 'Receiver should have received the exited assets'); - - // The final amount should reflect the penalties and rewards, so approximately: - // 100 ETH (initial) - 30 ETH (penalty) + 15 ETH (reward) + 15 ETH (reward) = 100 ETH - // But there might be some precision loss or fees, so we use an approximate comparison. - assertApproxEqAbs( - receivedAssets, - 100 ether, - 1 ether, - 'Receiver should have received about 100 ETH' - ); - } + ForkContracts public contracts; + EthVault public vault; + + address public sender; + address public sender2; + address public receiver; + address public admin; + address public referrer = address(0); + + uint256 public depositAmount = 1 ether; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + sender2 = makeAddr("sender2"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + + // Fund accounts with ETH for testing + vm.deal(sender, 100 ether); + vm.deal(sender2, 100 ether); + vm.deal(admin, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + (uint128 queuedShares,, uint128 totalExitingAssets,,) = vault.getExitQueueData(); + vm.deal(address(vault), address(vault).balance + vault.convertToAssets(queuedShares) + totalExitingAssets); + } + + function test_deposit_zeroAddress() public { + // Try to deposit to address(0) + vm.prank(sender); + vm.expectRevert(Errors.ZeroAddress.selector); + _startSnapshotGas("VaultEnterExitTest_test_deposit_zeroAddress"); + vault.deposit{value: depositAmount}(address(0), referrer); + _stopSnapshotGas(); + } + + function test_deposit_zeroAmount() public { + // Try to deposit 0 ETH + vm.prank(sender); + vm.expectRevert(Errors.InvalidAssets.selector); + _startSnapshotGas("VaultEnterExitTest_test_deposit_zeroAmount"); + vault.deposit{value: 0}(receiver, referrer); + _stopSnapshotGas(); + } + + function test_deposit_exceedingCapacity() public { + // Create a new vault with a small capacity + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 33 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault smallVault = EthVault(payable(vaultAddr)); + + // First deposit an amount under capacity + _depositToVault(address(smallVault), 32 ether, sender, sender); + + // Then try to deposit an amount that would exceed capacity + vm.prank(sender); + vm.expectRevert(Errors.CapacityExceeded.selector); + _startSnapshotGas("VaultEnterExitTest_test_deposit_exceedingCapacity"); + smallVault.deposit{value: 1.1 ether}(sender, referrer); + _stopSnapshotGas(); + } + + function test_deposit_success_basic() public { + // Record initial balances and state + uint256 senderBalanceBefore = sender.balance; + uint256 vaultBalanceBefore = address(vault).balance; + uint256 totalSharesBefore = vault.totalShares(); + uint256 totalAssetsBefore = vault.totalAssets(); + + // Perform the deposit + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_deposit_success_basic"); + uint256 shares = vault.deposit{value: depositAmount}(sender, referrer); + _stopSnapshotGas(); + + // Verify ETH was transferred correctly + assertEq(sender.balance, senderBalanceBefore - depositAmount, "Sender's ETH balance should decrease"); + assertEq(address(vault).balance, vaultBalanceBefore + depositAmount, "Vault's ETH balance should increase"); + + // Verify shares were minted correctly + assertEq(vault.getShares(sender), shares, "Sender should receive the correct number of shares"); + assertEq(vault.totalShares(), totalSharesBefore + shares, "Total shares should increase by the minted amount"); + assertEq( + vault.totalAssets(), totalAssetsBefore + depositAmount, "Total assets should increase by deposit amount" + ); + + // Verify the conversion between assets and shares + assertEq(vault.convertToAssets(shares), depositAmount, "Shares should convert back to the deposited amount"); + } + + function test_deposit_success_differentReceiver() public { + // Record initial balances and state + uint256 senderSharesBefore = vault.getShares(sender); + uint256 receiverSharesBefore = vault.getShares(receiver); + + // Perform the deposit with a different receiver + uint256 depositAssets = 1.5 ether; + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_deposit_success_differentReceiver"); + uint256 shares = vault.deposit{value: depositAssets}(receiver, referrer); + _stopSnapshotGas(); + + // Verify shares were minted to the receiver, not the sender + assertEq(vault.getShares(sender), senderSharesBefore, "Sender's shares should not change"); + assertEq(vault.getShares(receiver), receiverSharesBefore + shares, "Receiver should get the minted shares"); + } + + function test_deposit_success_multipleDeposits() public { + // First deposit + uint256 firstDeposit = 1 ether; + vm.prank(sender); + uint256 firstShares = vault.deposit{value: firstDeposit}(sender, referrer); + + // Second deposit + uint256 secondDeposit = 2 ether; + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_deposit_success_multipleDeposits"); + uint256 secondShares = vault.deposit{value: secondDeposit}(sender, referrer); + _stopSnapshotGas(); + + // Check the relationship between deposits + // Second deposit is 2x the first, so should get approximately 2x the shares + // (allowing for minor differences due to rounding or fees) + assertApproxEqRel( + secondShares, + firstShares * 2, + 0.01e18, // 1% tolerance + "Second deposit should get proportional shares relative to the first deposit" + ); + + // Verify total shares + assertEq(vault.getShares(sender), firstShares + secondShares, "Total shares should be the sum of both deposits"); + } + + function test_deposit_success_withReferrer() public { + // Set up a referrer + address validReferrer = makeAddr("referrer"); + + // Record initial balances and state + uint256 senderBalanceBefore = sender.balance; + uint256 vaultBalanceBefore = address(vault).balance; + + // Perform the deposit with a referrer + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_deposit_success_withReferrer"); + uint256 shares = vault.deposit{value: depositAmount}(sender, validReferrer); + _stopSnapshotGas(); + + // Verify deposit succeeded with referrer + assertEq(sender.balance, senderBalanceBefore - depositAmount, "Sender's ETH balance should decrease"); + assertEq(address(vault).balance, vaultBalanceBefore + depositAmount, "Vault's ETH balance should increase"); + assertEq(vault.getShares(sender), shares, "Sender should receive the correct number of shares"); + + // Note: In a real implementation, we might want to check for referral tracking or rewards, + // but the current contract doesn't seem to have specific referrer handling beyond the event + } + + function test_deposit_success_receiveFunction() public { + // Record initial balances and state + uint256 senderBalanceBefore = sender.balance; + uint256 vaultBalanceBefore = address(vault).balance; + uint256 senderSharesBefore = vault.getShares(sender); + + // Deposit using the receive function (direct transfer) + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_deposit_success_receiveFunction"); + (bool success,) = address(vault).call{value: depositAmount}(""); + _stopSnapshotGas(); + + // Verify transfer succeeded + assertTrue(success, "Direct transfer should succeed"); + + // Verify ETH was transferred correctly + assertEq(sender.balance, senderBalanceBefore - depositAmount, "Sender's ETH balance should decrease"); + assertEq(address(vault).balance, vaultBalanceBefore + depositAmount, "Vault's ETH balance should increase"); + + // Verify shares were minted to the sender + assertGt(vault.getShares(sender), senderSharesBefore, "Sender should receive shares"); + } + + function test_enterExitQueue_basicFlow() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Collateralize the vault (required for exit queue to work with actual validators) + _collateralizeEthVault(address(vault)); + + // 3. Enter exit queue + uint256 shares = vault.getShares(sender); + (uint128 queuedSharesBefore,,,,) = vault.getExitQueueData(); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_basicFlow"); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + // 4. Verify the position ticket was created and shares moved to the queue + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + assertEq(queuedShares, queuedSharesBefore + shares, "Queued shares should equal the shares sent to exit queue"); + assertEq(vault.getShares(sender), 0, "Sender should have 0 shares after entering exit queue"); + + // 5. Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 7. Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index should be valid"); + + // 8. Calculate exited assets + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = + vault.calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + assertApproxEqAbs(leftTickets, 0, 1, "All tickets should be processed"); + assertApproxEqAbs(exitedTickets, shares, 1, "Exited tickets should equal the shares entered"); + assertApproxEqAbs(exitedAssets, depositAmount, 1e9, "Exited assets should approximately equal deposit amount"); + + // 9. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + + vm.prank(receiver); + _startSnapshotGas("VaultEnterExitTest_test_claimExitedAssets"); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // 10. Verify assets were transferred to the receiver + uint256 receiverBalanceAfter = address(receiver).balance; + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets, + "Receiver should have received the exited assets" + ); + } + + function test_enterExitQueue_directRedemption() public { + address _newVault = _createVault( + VaultType.EthVault, + admin, + abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ), + false + ); + IEthVault newVault = IEthVault(_newVault); + + // 1. Deposit ETH + _depositToVault(_newVault, depositAmount, sender, sender); + + // 2. Enter exit queue (without collateralizing the vault) + uint256 shares = newVault.getShares(sender); + uint256 assets = newVault.convertToAssets(shares); + + uint256 receiverBalanceBefore = address(receiver).balance; + + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_directRedemption"); + uint256 positionTicket = newVault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + // 3. Verify direct redemption occurred (max uint256 ticket indicates direct redemption) + assertEq(positionTicket, type(uint256).max, "Position ticket should be max uint256 for direct redemption"); + assertEq(newVault.getShares(sender), 0, "Sender should have 0 shares after direct redemption"); + assertApproxEqAbs( + address(receiver).balance - receiverBalanceBefore, + assets, + 1e9, + "Assets should be transferred directly to receiver" + ); + } + + function test_claimExitedAssets_insufficientDelay() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + + // 3. Enter exit queue + uint256 shares = vault.getShares(sender); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + + // 4. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 5. Try to claim before the delay has passed + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index should be valid"); + + vm.prank(receiver); + _startSnapshotGas("VaultEnterExitTest_test_claimExitedAssets_insufficientDelay"); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + } + + function test_enterExitQueue_invalidParams() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Try to enter exit queue with 0 shares + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroShares"); + vm.expectRevert(Errors.InvalidShares.selector); + vault.enterExitQueue(0, receiver); + _stopSnapshotGas(); + + // 3. Try to enter exit queue with zero address as receiver + uint256 sharesToExit = vault.getShares(sender); + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.enterExitQueue(sharesToExit, address(0)); + _stopSnapshotGas(); + + // 4. Try to enter exit queue with more shares than owned + uint256 shares = vault.getShares(sender); + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_invalidParams_tooManyShares"); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.enterExitQueue(shares + 1, receiver); + _stopSnapshotGas(); + } + + function test_calculateExitedAssets_invalidPosition() public { + // Try to calculate exited assets for a non-existent position + _startSnapshotGas("VaultEnterExitTest_test_calculateExitedAssets_invalidPosition"); + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault.calculateExitedAssets( + receiver, + 999, // Non-existent position ticket + vm.getBlockTimestamp(), + 0 + ); + _stopSnapshotGas(); + + assertEq(leftTickets, 0, "Left tickets should be 0 for non-existent position"); + assertEq(exitedTickets, 0, "Exited tickets should be 0 for non-existent position"); + assertEq(exitedAssets, 0, "Exited assets should be 0 for non-existent position"); + } + + function test_claimExitedAssets_invalidCheckpoint() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + + // 3. Enter exit queue + uint256 shares = vault.getShares(sender); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + + // 4. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 5. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 6. Try to claim with an invalid checkpoint index + vm.prank(receiver); + _startSnapshotGas("VaultEnterExitTest_test_claimExitedAssets_invalidCheckpoint"); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + vault.claimExitedAssets( + positionTicket, + timestamp, + 999 // Invalid checkpoint index + ); + _stopSnapshotGas(); + } + + function test_enterExitQueue_multiUser() public { + // 1. Both users deposit ETH + _depositToVault(address(vault), depositAmount, sender, sender); + _depositToVault(address(vault), depositAmount * 2, sender2, sender2); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + + // 3. Both users enter exit queue + uint256 shares1 = vault.getShares(sender); + uint256 shares2 = vault.getShares(sender2); + + (uint128 queuedSharesBefore,,,,) = vault.getExitQueueData(); + + vm.prank(sender); + uint256 timestamp1 = vm.getBlockTimestamp(); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_multiUser_user1"); + uint256 positionTicket1 = vault.enterExitQueue(shares1, receiver); + _stopSnapshotGas(); + + vm.prank(sender2); + uint256 timestamp2 = vm.getBlockTimestamp(); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_multiUser_sender2"); + uint256 positionTicket2 = vault.enterExitQueue(shares2, sender2); + _stopSnapshotGas(); + + // 4. Verify the queued shares + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + assertEq( + queuedShares, + queuedSharesBefore + shares1 + shares2, + "Queued shares should equal the sum of all shares in exit queue" + ); + + // 5. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp2 + _exitingAssetsClaimDelay + 1); + + // 7. Both users claim their assets + int256 exitQueueIndex1 = vault.getExitQueueIndex(positionTicket1); + int256 exitQueueIndex2 = vault.getExitQueueIndex(positionTicket2); + + assertGt(exitQueueIndex1, -1, "Exit queue index 1 should be valid"); + assertGt(exitQueueIndex2, -1, "Exit queue index 2 should be valid"); + + (,, uint256 exitedAssets1) = + vault.calculateExitedAssets(receiver, positionTicket1, timestamp1, uint256(exitQueueIndex1)); + + (,, uint256 exitedAssets2) = + vault.calculateExitedAssets(sender2, positionTicket2, timestamp2, uint256(exitQueueIndex2)); + + // push down the stack + uint256 timestamp1_ = timestamp1; + uint256 timestamp2_ = timestamp2; + uint256 positionTicket1_ = positionTicket1; + uint256 positionTicket2_ = positionTicket2; + uint256 exitQueueIndex1_ = uint256(exitQueueIndex1); + uint256 exitQueueIndex2_ = uint256(exitQueueIndex2); + + uint256 receiverBalanceBefore = address(receiver).balance; + uint256 sender2BalanceBefore = address(sender2).balance; + + vm.prank(receiver); + vault.claimExitedAssets(positionTicket1_, timestamp1_, exitQueueIndex1_); + + vm.prank(sender2); + vault.claimExitedAssets(positionTicket2_, timestamp2_, exitQueueIndex2_); + + // 8. Verify assets were transferred to the respective receivers + uint256 receiverBalanceAfter = address(receiver).balance; + uint256 sender2BalanceAfter = address(sender2).balance; + + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets1, + "Receiver should have received the correct exited assets" + ); + assertEq( + sender2BalanceAfter - sender2BalanceBefore, + exitedAssets2, + "Sender2 should have received the correct exited assets" + ); + } + + function test_enterExitQueue_partialExit() public { + // 1. Deposit ETH + _depositToVault(address(vault), depositAmount * 2, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(address(vault)); + (uint128 queuedSharesBefore,,,,) = vault.getExitQueueData(); + + // 3. Enter exit queue with half of the shares + uint256 totalShares = vault.getShares(sender); + uint256 halfShares = totalShares / 2; + + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_partialExit"); + uint256 positionTicket = vault.enterExitQueue(halfShares, receiver); + _stopSnapshotGas(); + + // 4. Verify the position ticket and remaining shares + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + assertEq( + queuedShares, + queuedSharesBefore + halfShares, + "Queued shares should equal the half shares sent to exit queue" + ); + assertEq(vault.getShares(sender), halfShares, "Sender should have half of the original shares left"); + + // 5. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 7. Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index should be valid"); + + // 8. Calculate exited assets + (,, uint256 exitedAssets) = + vault.calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // 9. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + uint256 receiverBalanceAfter = address(receiver).balance; + + // 10. Verify assets were transferred to the receiver + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets, + "Receiver should have received the exited assets" + ); + + // 11. Verify sender still has the remaining shares + assertEq(vault.getShares(sender), halfShares, "Sender should still have half of the original shares"); + } + + function test_enterExitQueue_afterValidatorExit() public { + // 1. Deposit ETH + _depositToVault(address(vault), 40 ether, sender, sender); + + // 2. Register a validator with 32 ETH + _registerEthValidator(address(vault), 32 ether, true); + + // 3. Simulate validator exit + vm.deal(address(vault), address(vault).balance + 32 ether); + + // 4. Enter exit queue + uint256 shares = vault.getShares(sender); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_afterValidatorExit"); + uint256 positionTicket = vault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + // 5. Process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 7. Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index should be valid"); + + // 8. Calculate exited assets + (,, uint256 exitedAssets) = + vault.calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // 9. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + uint256 receiverBalanceAfter = address(receiver).balance; + + // 10. Verify assets were transferred to the receiver + assertApproxEqAbs(exitedAssets, 40 ether, 1, "Receiver should have received at least the initial deposit"); + assertEq( + receiverBalanceAfter - receiverBalanceBefore, + exitedAssets, + "Receiver should have received the exited assets" + ); + } + + function test_enterExitQueue_multipleUpdates() public { + address _newVault = _createVault( + VaultType.EthVault, + admin, + abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ), + false + ); + IEthVault newVault = IEthVault(_newVault); + + // 1. Deposit a large amount of ETH + _depositToVault(_newVault, 100 ether, sender, sender); + + // 2. Collateralize the vault + _collateralizeEthVault(_newVault); + + // 3. Enter exit queue with all shares + uint256 shares = newVault.getShares(sender); + uint256 timestamp = vm.getBlockTimestamp(); + + vm.prank(sender); + _startSnapshotGas("VaultEnterExitTest_test_enterExitQueue_multipleUpdates"); + uint256 positionTicket = newVault.enterExitQueue(shares, receiver); + _stopSnapshotGas(); + + uint256 vaultBalanceBefore = _newVault.balance; + vm.deal(_newVault, 0); + + // 4. Process the exit queue in multiple updates + // First update with a penalty (to reduce the available assets) + IKeeperRewards.HarvestParams memory harvestParams1 = _setEthVaultReward(_newVault, int160(-30 ether), 0); + newVault.updateState(harvestParams1); + + // Second update with a reward + IKeeperRewards.HarvestParams memory harvestParams2 = _setEthVaultReward(_newVault, int160(15 ether), 0); + newVault.updateState(harvestParams2); + + // Final update with remaining balance + vm.deal(_newVault, vaultBalanceBefore); + IKeeperRewards.HarvestParams memory harvestParams3 = _setEthVaultReward(_newVault, int160(15 ether), 0); + newVault.updateState(harvestParams3); + + // 5. Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // 6. Get exit queue index + int256 exitQueueIndex = newVault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index should be valid"); + + // 7. Calculate exited assets + (,, uint256 exitedAssets) = + newVault.calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // 8. Claim exited assets + uint256 receiverBalanceBefore = address(receiver).balance; + vm.prank(receiver); + newVault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + uint256 receiverBalanceAfter = address(receiver).balance; + + // 9. Verify assets were transferred to the receiver + uint256 receivedAssets = receiverBalanceAfter - receiverBalanceBefore; + assertEq(receivedAssets, exitedAssets, "Receiver should have received the exited assets"); + + // The final amount should reflect the penalties and rewards, so approximately: + // 100 ETH (initial) - 30 ETH (penalty) + 15 ETH (reward) + 15 ETH (reward) = 100 ETH + // But there might be some precision loss or fees, so we use an approximate comparison. + assertApproxEqAbs(receivedAssets, 100 ether, 1 ether, "Receiver should have received about 100 ETH"); + } } diff --git a/test/VaultEthStaking.t.sol b/test/VaultEthStaking.t.sol index 8d64b4eb..27c4bd98 100644 --- a/test/VaultEthStaking.t.sol +++ b/test/VaultEthStaking.t.sol @@ -1,572 +1,483 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVaultFactory} from '../contracts/vaults/ethereum/EthVaultFactory.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperValidators} from "../contracts/interfaces/IKeeperValidators.sol"; +import {IVaultValidators} from "../contracts/interfaces/IVaultValidators.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVaultFactory} from "../contracts/vaults/ethereum/EthVaultFactory.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; contract VaultEthStakingTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - - address public sender; - address public receiver; - address public admin; - address public referrer; - address public validatorsManager; - - uint256 public depositAmount = 1 ether; - - function setUp() public { - // Get fork contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - referrer = makeAddr('referrer'); - validatorsManager = makeAddr('validatorsManager'); - - // Fund accounts for testing - vm.deal(sender, 100 ether); - vm.deal(admin, 100 ether); - vm.deal(receiver, 1 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Set validators manager - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - vm.deal(validatorsManager, 1 ether); - } - - // Test initializing vault with insufficient security deposit - function test_invalidSecurityDeposit() public { - // Security deposit amount is defined as 1e9 (1 Gwei) in the EthHelpers contract - // Create a new admin address for this test - address newAdmin = makeAddr('newAdmin'); - vm.deal(newAdmin, 1 ether); - - // Get the factory for creating vaults - EthVaultFactory factory = _getOrCreateFactory(VaultType.EthVault); - - // Prepare initialization parameters - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - // Set value to less than required security deposit (1e9 wei) - uint256 insufficientDeposit = 0.1 gwei; - - // Try to create vault with insufficient security deposit - vm.prank(newAdmin); - _startSnapshotGas('VaultEthStakingTest_test_invalidSecurityDeposit'); - vm.expectRevert(Errors.InvalidSecurityDeposit.selector); - factory.createVault{value: insufficientDeposit}(initParams, false); - _stopSnapshotGas(); - - // Also test with zero deposit - vm.prank(newAdmin); - vm.expectRevert(Errors.InvalidSecurityDeposit.selector); - factory.createVault{value: 0}(initParams, false); - - // Verify that it works with correct security deposit - vm.prank(newAdmin); - address newVault = factory.createVault{value: 1 gwei}(initParams, false); - - // Verify vault was created - assertTrue( - address(newVault) != address(0), - 'Vault should be created with valid security deposit' - ); - } - - // Test basic deposit functionality - function test_deposit() public { - // Initial balances - uint256 senderInitialBalance = sender.balance; - uint256 vaultInitialBalance = address(vault).balance; - uint256 vaultTotalSharesBefore = vault.totalShares(); - uint256 vaultTotalAssetsBefore = vault.totalAssets(); - - // Deposit - vm.prank(sender); - _startSnapshotGas('VaultEthStakingTest_test_deposit'); - uint256 shares = vault.deposit{value: depositAmount}(receiver, referrer); - _stopSnapshotGas(); - - // Verify balances changed correctly - assertEq( - sender.balance, - senderInitialBalance - depositAmount, - 'Sender balance should decrease' - ); - assertEq( - address(vault).balance, - vaultInitialBalance + depositAmount, - 'Vault balance should increase' - ); - - // Verify shares minted correctly - assertEq(vault.getShares(receiver), shares, 'Receiver should get correct shares'); - - uint256 expectedShares = vault.convertToShares(depositAmount); - assertApproxEqAbs( - shares, - expectedShares, - 1, - 'Shares should match the expected conversion rate' - ); - - // Verify totalAssets and totalShares updated - assertEq( - vault.totalAssets(), - vaultTotalAssetsBefore + depositAmount, - 'Total assets should increase' - ); - assertEq(vault.totalShares(), vaultTotalSharesBefore + shares, 'Total shares should increase'); - } - - // Test withdrawable assets - function test_withdrawableAssets() public { - uint256 withdrawableBefore = vault.withdrawableAssets(); - - // Deposit some ETH - _depositToVault(address(vault), depositAmount, sender, receiver); - - // Check withdrawable assets - uint256 withdrawable = vault.withdrawableAssets(); - assertGe( - withdrawable, - withdrawableBefore + depositAmount, - 'Withdrawable assets should include deposited amount' - ); - } - - // Test vault assets reporting - function test_vaultAssets() public { - // Initial check - uint256 initialAssets = vault.totalAssets(); - uint256 initialBalance = address(vault).balance; - - // Deposit ETH - _depositToVault(address(vault), depositAmount, sender, receiver); - - // Check assets increased - assertEq( - vault.totalAssets(), - initialAssets + depositAmount, - 'Total assets should increase by deposit amount' - ); - - // Check that vault balance (internal _vaultAssets) reflects the deposit - assertEq( - address(vault).balance, - initialBalance + depositAmount, - 'Vault ETH balance should increase by deposit amount' - ); - } - - // Test validator registration - function test_registerValidators_succeeds() public { - // Setup oracle - _startOracleImpersonate(address(contracts.keeper)); - - // Test successful registration with 0x01 prefix (32 ETH) - _depositToVault(address(vault), 32 ether, sender, sender); - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - 32 ether, - 'ipfsHash', - true - ); - - vm.prank(validatorsManager); - _startSnapshotGas('VaultEthStakingTest_test_registerValidators_01prefix'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Test successful registration with 0x02 prefix and valid amount (32 ETH) - _depositToVault(address(vault), 32 ether, sender, sender); - approvalParams = _getEthValidatorApproval(address(vault), 32 ether, 'ipfsHash', false); - - vm.prank(validatorsManager); - _startSnapshotGas('VaultEthStakingTest_test_registerValidators_02prefix'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // revert previous state - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test validator minimum and maximum effective balance limits - function test_validatorMinMaxEffectiveBalance() public { - // We need to simulate a registration attempt with invalid ETH amount - // For Ethereum, validators require exactly 32 ETH - - // Setup oracle for validator registration - _startOracleImpersonate(address(contracts.keeper)); - - // Prepare approval params - _depositToVault(address(vault), 32 ether, sender, sender); - - uint256[] memory deposits = new uint256[](1); - deposits[0] = 16 ether / 1 gwei; - IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - address(vault), - 'ipfsHash', - deposits, - false - ); - - // This should fail because the deposit amount is not 32 ETH - vm.prank(validatorsManager); - _startSnapshotGas('VaultEthStakingTest_test_validatorMinMaxEffectiveBalance'); - vm.expectRevert(Errors.InvalidAssets.selector); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test receive function for ETH - function test_receive() public { - // Send ETH directly to the vault - uint256 sendAmount = 0.5 ether; - vm.deal(sender, sendAmount); - - uint256 depositShares = vault.convertToShares(sendAmount); - uint256 userSharesBefore = vault.getShares(sender); - uint256 balanceBefore = address(vault).balance; - uint256 totalAssetsBefore = vault.totalAssets(); - - vm.prank(sender); - _startSnapshotGas('VaultEthStakingTest_test_receive'); - (bool success, ) = address(vault).call{value: sendAmount}(''); - _stopSnapshotGas(); - - assertTrue(success, 'Failed to send ETH to vault'); - assertEq( - address(vault).balance, - balanceBefore + sendAmount, - "Vault balance didn't increase correctly" - ); - assertEq( - vault.totalAssets(), - totalAssetsBefore + sendAmount, - "Vault total assets didn't increase correctly" - ); - assertApproxEqAbs( - vault.getShares(sender), - depositShares + userSharesBefore, - 1, - 'User should have deposit amount' - ); - } - - // Test update state and deposit - function test_updateStateAndDeposit() public { - // Collateralize vault to enable rewards - _collateralizeEthVault(address(vault)); - - // Set up reward parameters - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - uint256 initialBalance = address(vault).balance; - uint256 initialShares = vault.totalShares(); - - // Call updateStateAndDeposit - vm.prank(sender); - _startSnapshotGas('VaultEthStakingTest_test_updateStateAndDeposit'); - uint256 shares = vault.updateStateAndDeposit{value: depositAmount}( - receiver, - referrer, - harvestParams - ); - _stopSnapshotGas(); - - // Verify the deposit was successful and state was updated - assertGt(shares, 0, 'Should have minted shares'); - assertEq( - address(vault).balance, - initialBalance + depositAmount, - 'Vault balance should increase by deposit amount' - ); - assertGt(vault.totalShares(), initialShares, 'Total shares should increase'); - } - - // Test receiving from MEV escrow - function test_receiveFromMevEscrow() public { - // Get MEV escrow address - address mevEscrow = vault.mevEscrow(); - uint256 initialBalance = address(vault).balance; - uint256 mevAmount = 0.5 ether; - - vm.deal(mevEscrow, mevAmount); - - // Can only be called by the MEV escrow - vm.prank(sender); - _startSnapshotGas('VaultEthStakingTest_test_receiveFromMevEscrow_fail'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.receiveFromMevEscrow{value: 0.1 ether}(); - _stopSnapshotGas(); - - // Call from MEV escrow succeeds - vm.prank(mevEscrow); - _startSnapshotGas('VaultEthStakingTest_test_receiveFromMevEscrow_success'); - vault.receiveFromMevEscrow{value: mevAmount}(); - _stopSnapshotGas(); - - assertEq( - address(vault).balance, - initialBalance + mevAmount, - 'Vault balance should increase by MEV amount' - ); - } - - // Test deposit and mint OsToken - function test_depositAndMintOsToken() public { - // Collateralize vault for OsToken minting - _collateralizeEthVault(address(vault)); - - uint256 initialBalance = address(vault).balance; - - // Deposit and mint maximum possible OsToken shares - vm.prank(sender); - _startSnapshotGas('VaultEthStakingTest_test_depositAndMintOsToken'); - uint256 assets = vault.depositAndMintOsToken{value: depositAmount}( - sender, - type(uint256).max, - referrer - ); - _stopSnapshotGas(); - - // Verify deposit - assertEq( - address(vault).balance, - initialBalance + depositAmount, - 'Vault balance should increase by deposit amount' - ); - - // Verify OsToken minting - assertGt(assets, 0, 'Should have minted OsToken assets'); - assertGt(vault.osTokenPositions(sender), 0, 'Should have OsToken position'); - } - - // Test update state, deposit and mint OsToken - function test_updateStateAndDepositAndMintOsToken() public { - // Collateralize vault to enable rewards - _collateralizeEthVault(address(vault)); - - // Set up reward parameters - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - uint256 initialBalance = address(vault).balance; - - // Call updateStateAndDepositAndMintOsToken - vm.prank(sender); - _startSnapshotGas('VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken'); - uint256 assets = vault.updateStateAndDepositAndMintOsToken{value: depositAmount}( - sender, - type(uint256).max, - referrer, - harvestParams - ); - _stopSnapshotGas(); - - // Verify the deposit was successful and state was updated - assertGt(assets, 0, 'Should have minted OsToken assets'); - assertEq( - address(vault).balance, - initialBalance + depositAmount, - 'Vault balance should increase by deposit amount' - ); - assertGt(vault.osTokenPositions(sender), 0, 'Should have OsToken position'); - } - - // Test transferVaultAssets functionality through the exit queue - function test_transferVaultAssets() public { - // Collateralize vault - _collateralizeEthVault(address(vault)); - - // Deposit ETH to the vault - (uint128 queuedShares, , uint128 totalExitingAssets, ,) = vault.getExitQueueData(); - uint256 senderDeposit = vault.convertToAssets(queuedShares) + - totalExitingAssets + - depositAmount; - _depositToVault(address(vault), senderDeposit, sender, sender); - - // Record initial balances - uint256 receiverInitialBalance = receiver.balance; - - // Enter exit queue - uint256 withdrawalAmount = vault.convertToShares(depositAmount); - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - uint256 positionTicket = vault.enterExitQueue(withdrawalAmount, receiver); - - // Process the exit queue (update state) - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Claim exited assets which will trigger _transferVaultAssets - vm.prank(receiver); - _startSnapshotGas('VaultEthStakingTest_test_transferVaultAssets'); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // Verify the transfer occurred - uint256 receiverFinalBalance = receiver.balance; - assertGt(receiverFinalBalance, receiverInitialBalance, 'Receiver balance should increase'); - } - - // Test mev rewards processing through _harvestAssets - function test_harvestAssets() public { - // Collateralize vault - _collateralizeEthVault(address(vault)); - - // Set up a reward with MEV component - uint160 mevReward = 0.2 ether; - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.3 ether)), - mevReward - ); - - // Setup MEV escrow with some ETH - address mevEscrow = vault.mevEscrow(); - vm.deal(mevEscrow, mevReward); - - // Record initial balances - uint256 vaultInitialBalance = address(vault).balance; - - // Update state which will trigger _harvestAssets - _startSnapshotGas('VaultEthStakingTest_test_harvestAssets'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify the vault received MEV rewards - assertGt( - address(vault).balance, - vaultInitialBalance, - 'Vault balance should increase from MEV rewards' - ); - } - - // Test adding validator then withdrawing (full flow) - function test_withdrawValidator_fullFlow() public { - // 1. Deposit and register a validator - _depositToVault(address(vault), 32 ether, sender, sender); - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 2. Fund validators manager for the withdrawal fee - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(validatorsManager); - _startSnapshotGas('VaultEthStakingTest_test_withdrawValidator_fullFlow'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - // Test funding existing validators - function test_fundValidators() public { - // 1. Deposit enough ETH for multiple validator operations - _depositToVault(address(vault), 64 ether, sender, sender); - - // Setup oracle for validator registration - _startOracleImpersonate(address(contracts.keeper)); - - // 2. Register a validator first to make it tracked - bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); - - // 3. Try to top up a non-existing validator (should fail) - bytes memory nonExistingPublicKey = vm.randomBytes(48); - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - nonExistingPublicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create top-up data for non-existing validator - bytes memory invalidTopUpData = bytes.concat( - nonExistingPublicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - vm.prank(validatorsManager); - _startSnapshotGas('VaultEthStakingTest_test_fundValidators_invalid'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.fundValidators(invalidTopUpData, ''); - _stopSnapshotGas(); - - // 4. Successfully top up the registered validator - // Create valid top-up data using the same public key as the registered validator - topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Check for ValidatorFunded event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); - - vm.prank(validatorsManager); - _startSnapshotGas('VaultEthStakingTest_test_fundValidators_valid'); - vault.fundValidators(validTopUpData, ''); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } + ForkContracts public contracts; + EthVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + + uint256 public depositAmount = 1 ether; + + function setUp() public { + // Get fork contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + referrer = makeAddr("referrer"); + validatorsManager = makeAddr("validatorsManager"); + + // Fund accounts for testing + vm.deal(sender, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(receiver, 1 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Set validators manager + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + vm.deal(validatorsManager, 1 ether); + } + + // Test initializing vault with insufficient security deposit + function test_invalidSecurityDeposit() public { + // Security deposit amount is defined as 1e9 (1 Gwei) in the EthHelpers contract + // Create a new admin address for this test + address newAdmin = makeAddr("newAdmin"); + vm.deal(newAdmin, 1 ether); + + // Get the factory for creating vaults + EthVaultFactory factory = _getOrCreateFactory(VaultType.EthVault); + + // Prepare initialization parameters + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + // Set value to less than required security deposit (1e9 wei) + uint256 insufficientDeposit = 0.1 gwei; + + // Try to create vault with insufficient security deposit + vm.prank(newAdmin); + _startSnapshotGas("VaultEthStakingTest_test_invalidSecurityDeposit"); + vm.expectRevert(Errors.InvalidSecurityDeposit.selector); + factory.createVault{value: insufficientDeposit}(initParams, false); + _stopSnapshotGas(); + + // Also test with zero deposit + vm.prank(newAdmin); + vm.expectRevert(Errors.InvalidSecurityDeposit.selector); + factory.createVault{value: 0}(initParams, false); + + // Verify that it works with correct security deposit + vm.prank(newAdmin); + address newVault = factory.createVault{value: 1 gwei}(initParams, false); + + // Verify vault was created + assertTrue(address(newVault) != address(0), "Vault should be created with valid security deposit"); + } + + // Test basic deposit functionality + function test_deposit() public { + // Initial balances + uint256 senderInitialBalance = sender.balance; + uint256 vaultInitialBalance = address(vault).balance; + uint256 vaultTotalSharesBefore = vault.totalShares(); + uint256 vaultTotalAssetsBefore = vault.totalAssets(); + + // Deposit + vm.prank(sender); + _startSnapshotGas("VaultEthStakingTest_test_deposit"); + uint256 shares = vault.deposit{value: depositAmount}(receiver, referrer); + _stopSnapshotGas(); + + // Verify balances changed correctly + assertEq(sender.balance, senderInitialBalance - depositAmount, "Sender balance should decrease"); + assertEq(address(vault).balance, vaultInitialBalance + depositAmount, "Vault balance should increase"); + + // Verify shares minted correctly + assertEq(vault.getShares(receiver), shares, "Receiver should get correct shares"); + + uint256 expectedShares = vault.convertToShares(depositAmount); + assertApproxEqAbs(shares, expectedShares, 1, "Shares should match the expected conversion rate"); + + // Verify totalAssets and totalShares updated + assertEq(vault.totalAssets(), vaultTotalAssetsBefore + depositAmount, "Total assets should increase"); + assertEq(vault.totalShares(), vaultTotalSharesBefore + shares, "Total shares should increase"); + } + + // Test withdrawable assets + function test_withdrawableAssets() public { + uint256 withdrawableBefore = vault.withdrawableAssets(); + + // Deposit some ETH + _depositToVault(address(vault), depositAmount, sender, receiver); + + // Check withdrawable assets + uint256 withdrawable = vault.withdrawableAssets(); + assertGe( + withdrawable, withdrawableBefore + depositAmount, "Withdrawable assets should include deposited amount" + ); + } + + // Test vault assets reporting + function test_vaultAssets() public { + // Initial check + uint256 initialAssets = vault.totalAssets(); + uint256 initialBalance = address(vault).balance; + + // Deposit ETH + _depositToVault(address(vault), depositAmount, sender, receiver); + + // Check assets increased + assertEq(vault.totalAssets(), initialAssets + depositAmount, "Total assets should increase by deposit amount"); + + // Check that vault balance (internal _vaultAssets) reflects the deposit + assertEq( + address(vault).balance, + initialBalance + depositAmount, + "Vault ETH balance should increase by deposit amount" + ); + } + + // Test validator registration + function test_registerValidators_succeeds() public { + // Setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Test successful registration with 0x01 prefix (32 ETH) + _depositToVault(address(vault), 32 ether, sender, sender); + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), 32 ether, "ipfsHash", true); + + vm.prank(validatorsManager); + _startSnapshotGas("VaultEthStakingTest_test_registerValidators_01prefix"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Test successful registration with 0x02 prefix and valid amount (32 ETH) + _depositToVault(address(vault), 32 ether, sender, sender); + approvalParams = _getEthValidatorApproval(address(vault), 32 ether, "ipfsHash", false); + + vm.prank(validatorsManager); + _startSnapshotGas("VaultEthStakingTest_test_registerValidators_02prefix"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // revert previous state + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test validator minimum and maximum effective balance limits + function test_validatorMinMaxEffectiveBalance() public { + // We need to simulate a registration attempt with invalid ETH amount + // For Ethereum, validators require exactly 32 ETH + + // Setup oracle for validator registration + _startOracleImpersonate(address(contracts.keeper)); + + // Prepare approval params + _depositToVault(address(vault), 32 ether, sender, sender); + + uint256[] memory deposits = new uint256[](1); + deposits[0] = 16 ether / 1 gwei; + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + "ipfsHash", + deposits, + false + ); + + // This should fail because the deposit amount is not 32 ETH + vm.prank(validatorsManager); + _startSnapshotGas("VaultEthStakingTest_test_validatorMinMaxEffectiveBalance"); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test receive function for ETH + function test_receive() public { + // Send ETH directly to the vault + uint256 sendAmount = 0.5 ether; + vm.deal(sender, sendAmount); + + uint256 depositShares = vault.convertToShares(sendAmount); + uint256 userSharesBefore = vault.getShares(sender); + uint256 balanceBefore = address(vault).balance; + uint256 totalAssetsBefore = vault.totalAssets(); + + vm.prank(sender); + _startSnapshotGas("VaultEthStakingTest_test_receive"); + (bool success,) = address(vault).call{value: sendAmount}(""); + _stopSnapshotGas(); + + assertTrue(success, "Failed to send ETH to vault"); + assertEq(address(vault).balance, balanceBefore + sendAmount, "Vault balance didn't increase correctly"); + assertEq(vault.totalAssets(), totalAssetsBefore + sendAmount, "Vault total assets didn't increase correctly"); + assertApproxEqAbs( + vault.getShares(sender), depositShares + userSharesBefore, 1, "User should have deposit amount" + ); + } + + // Test update state and deposit + function test_updateStateAndDeposit() public { + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + uint256 initialBalance = address(vault).balance; + uint256 initialShares = vault.totalShares(); + + // Call updateStateAndDeposit + vm.prank(sender); + _startSnapshotGas("VaultEthStakingTest_test_updateStateAndDeposit"); + uint256 shares = vault.updateStateAndDeposit{value: depositAmount}(receiver, referrer, harvestParams); + _stopSnapshotGas(); + + // Verify the deposit was successful and state was updated + assertGt(shares, 0, "Should have minted shares"); + assertEq( + address(vault).balance, initialBalance + depositAmount, "Vault balance should increase by deposit amount" + ); + assertGt(vault.totalShares(), initialShares, "Total shares should increase"); + } + + // Test receiving from MEV escrow + function test_receiveFromMevEscrow() public { + // Get MEV escrow address + address mevEscrow = vault.mevEscrow(); + uint256 initialBalance = address(vault).balance; + uint256 mevAmount = 0.5 ether; + + vm.deal(mevEscrow, mevAmount); + + // Can only be called by the MEV escrow + vm.prank(sender); + _startSnapshotGas("VaultEthStakingTest_test_receiveFromMevEscrow_fail"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.receiveFromMevEscrow{value: 0.1 ether}(); + _stopSnapshotGas(); + + // Call from MEV escrow succeeds + vm.prank(mevEscrow); + _startSnapshotGas("VaultEthStakingTest_test_receiveFromMevEscrow_success"); + vault.receiveFromMevEscrow{value: mevAmount}(); + _stopSnapshotGas(); + + assertEq(address(vault).balance, initialBalance + mevAmount, "Vault balance should increase by MEV amount"); + } + + // Test deposit and mint OsToken + function test_depositAndMintOsToken() public { + // Collateralize vault for OsToken minting + _collateralizeEthVault(address(vault)); + + uint256 initialBalance = address(vault).balance; + + // Deposit and mint maximum possible OsToken shares + vm.prank(sender); + _startSnapshotGas("VaultEthStakingTest_test_depositAndMintOsToken"); + uint256 assets = vault.depositAndMintOsToken{value: depositAmount}(sender, type(uint256).max, referrer); + _stopSnapshotGas(); + + // Verify deposit + assertEq( + address(vault).balance, initialBalance + depositAmount, "Vault balance should increase by deposit amount" + ); + + // Verify OsToken minting + assertGt(assets, 0, "Should have minted OsToken assets"); + assertGt(vault.osTokenPositions(sender), 0, "Should have OsToken position"); + } + + // Test update state, deposit and mint OsToken + function test_updateStateAndDepositAndMintOsToken() public { + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + uint256 initialBalance = address(vault).balance; + + // Call updateStateAndDepositAndMintOsToken + vm.prank(sender); + _startSnapshotGas("VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken"); + uint256 assets = vault.updateStateAndDepositAndMintOsToken{value: depositAmount}( + sender, type(uint256).max, referrer, harvestParams + ); + _stopSnapshotGas(); + + // Verify the deposit was successful and state was updated + assertGt(assets, 0, "Should have minted OsToken assets"); + assertEq( + address(vault).balance, initialBalance + depositAmount, "Vault balance should increase by deposit amount" + ); + assertGt(vault.osTokenPositions(sender), 0, "Should have OsToken position"); + } + + // Test transferVaultAssets functionality through the exit queue + function test_transferVaultAssets() public { + // Collateralize vault + _collateralizeEthVault(address(vault)); + + // Deposit ETH to the vault + (uint128 queuedShares,, uint128 totalExitingAssets,,) = vault.getExitQueueData(); + uint256 senderDeposit = vault.convertToAssets(queuedShares) + totalExitingAssets + depositAmount; + _depositToVault(address(vault), senderDeposit, sender, sender); + + // Record initial balances + uint256 receiverInitialBalance = receiver.balance; + + // Enter exit queue + uint256 withdrawalAmount = vault.convertToShares(depositAmount); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(withdrawalAmount, receiver); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Claim exited assets which will trigger _transferVaultAssets + vm.prank(receiver); + _startSnapshotGas("VaultEthStakingTest_test_transferVaultAssets"); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify the transfer occurred + uint256 receiverFinalBalance = receiver.balance; + assertGt(receiverFinalBalance, receiverInitialBalance, "Receiver balance should increase"); + } + + // Test mev rewards processing through _harvestAssets + function test_harvestAssets() public { + // Collateralize vault + _collateralizeEthVault(address(vault)); + + // Set up a reward with MEV component + uint160 mevReward = 0.2 ether; + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.3 ether)), mevReward); + + // Setup MEV escrow with some ETH + address mevEscrow = vault.mevEscrow(); + vm.deal(mevEscrow, mevReward); + + // Record initial balances + uint256 vaultInitialBalance = address(vault).balance; + + // Update state which will trigger _harvestAssets + _startSnapshotGas("VaultEthStakingTest_test_harvestAssets"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify the vault received MEV rewards + assertGt(address(vault).balance, vaultInitialBalance, "Vault balance should increase from MEV rewards"); + } + + // Test adding validator then withdrawing (full flow) + function test_withdrawValidator_fullFlow() public { + // 1. Deposit and register a validator + _depositToVault(address(vault), 32 ether, sender, sender); + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 2. Fund validators manager for the withdrawal fee + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas("VaultEthStakingTest_test_withdrawValidator_fullFlow"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + // Test funding existing validators + function test_fundValidators() public { + // 1. Deposit enough ETH for multiple validator operations + _depositToVault(address(vault), 64 ether, sender, sender); + + // Setup oracle for validator registration + _startOracleImpersonate(address(contracts.keeper)); + + // 2. Register a validator first to make it tracked + bytes memory publicKey = _registerEthValidator(address(vault), 32 ether, false); + + // 3. Try to top up a non-existing validator (should fail) + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory nonExistingPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = + _getDepositDataRoot(nonExistingPublicKey, signature, withdrawalCredentials, topUpAmount); + + // Create top-up data for non-existing validator + bytes memory invalidTopUpData = + bytes.concat(nonExistingPublicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + vm.prank(validatorsManager); + _startSnapshotGas("VaultEthStakingTest_test_fundValidators_invalid"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(invalidTopUpData, ""); + _stopSnapshotGas(); + + // 4. Successfully top up the registered validator + // Create valid top-up data using the same public key as the registered validator + topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + vm.prank(validatorsManager); + _startSnapshotGas("VaultEthStakingTest_test_fundValidators_valid"); + vault.fundValidators(validTopUpData, ""); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } } diff --git a/test/VaultFee.t.sol b/test/VaultFee.t.sol index 2e941c67..0a546772 100644 --- a/test/VaultFee.t.sol +++ b/test/VaultFee.t.sol @@ -1,414 +1,393 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract VaultFeeTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - - address public admin; - address public user; - address public feeRecipient; - address public newFeeRecipient; - address public referrer = address(0); - - uint16 public initialFeePercent; - uint256 public depositAmount = 10 ether; - uint256 public rewardAmount = 1 ether; - uint256 public feeChangeDelay = 7 days; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - feeRecipient = makeAddr('feeRecipient'); - newFeeRecipient = makeAddr('newFeeRecipient'); - - // Fund accounts with ETH for testing - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - initialFeePercent = vault.feePercent(); - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - - vm.prank(admin); - vault.setFeeRecipient(admin); - } - - function test_initialFeeRecipient() public view { - // The fee recipient should initially be set to the admin as per the vault initialization - assertEq(vault.feeRecipient(), admin, 'Initial fee recipient should be the admin'); - assertEq(vault.feePercent(), initialFeePercent, 'Initial fee percent should match parameter'); - } - - function test_setFeeRecipient_success() public { - // Test setting a new fee recipient as admin - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_success'); - vault.setFeeRecipient(newFeeRecipient); - _stopSnapshotGas(); - - // Verify the new fee recipient - assertEq(vault.feeRecipient(), newFeeRecipient, 'Fee recipient should be updated'); - } - - function test_setFeeRecipient_notAdmin() public { - // Test setting fee recipient as non-admin - vm.prank(user); - _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_notAdmin'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.setFeeRecipient(newFeeRecipient); - _stopSnapshotGas(); - - // Fee recipient should remain unchanged - assertEq(vault.feeRecipient(), admin, 'Fee recipient should not change'); - } - - function test_setFeeRecipient_zeroAddress() public { - // Test setting fee recipient to zero address - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_zeroAddress'); - vm.expectRevert(Errors.InvalidFeeRecipient.selector); - vault.setFeeRecipient(address(0)); - _stopSnapshotGas(); - - // Fee recipient should remain unchanged - assertEq(vault.feeRecipient(), admin, 'Fee recipient should not change'); - } - - function test_setFeeRecipient_requiresHarvest() public { - // Make sure vault needs to be harvested - _collateralizeEthVault(address(vault)); - - // update state twice to require harvesting - _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(rewardAmount)), - 0 - ); - - // Test setting fee recipient without harvesting - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeeRecipient_requiresHarvest'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.setFeeRecipient(newFeeRecipient); - _stopSnapshotGas(); - - // First update state - vault.updateState(harvestParams); - - // Then try setting fee recipient again - vm.prank(admin); - vault.setFeeRecipient(newFeeRecipient); - assertEq( - vault.feeRecipient(), - newFeeRecipient, - 'Fee recipient should be updated after harvest' - ); - } - - function test_setFeePercent_success() public { - // Test setting a new fee percentage as admin - uint16 newFeePercent = vault.feePercent() + 1; - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_success'); - vault.setFeePercent(newFeePercent); - _stopSnapshotGas(); - - // Verify the new fee percentage - assertEq(vault.feePercent(), newFeePercent, 'Fee percent should be updated'); - } - - function test_setFeePercent_notAdmin() public { - // Test setting fee percentage as non-admin - uint16 newFeePercent = 500; // 5% - vm.prank(user); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_notAdmin'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.setFeePercent(newFeePercent); - _stopSnapshotGas(); - - // Fee percentage should remain unchanged - assertEq(vault.feePercent(), initialFeePercent, 'Fee percent should not change'); - } - - function test_setFeePercent_aboveMaximum() public { - // Test setting fee percentage above maximum (10000 = 100%) - uint16 invalidFeePercent = 10001; // 100.01% - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_aboveMaximum'); - vm.expectRevert(Errors.InvalidFeePercent.selector); - vault.setFeePercent(invalidFeePercent); - _stopSnapshotGas(); - - // Fee percentage should remain unchanged - assertEq(vault.feePercent(), initialFeePercent, 'Fee percent should not change'); - } - - function test_setFeePercent_tooSoon() public { - // First set fee percentage - uint16 firstFeePercent = 500; // 5% - vm.prank(admin); - vault.setFeePercent(firstFeePercent); - - // Then try to set again too soon (before feeChangeDelay have passed) - uint16 secondFeePercent = 600; // 6% - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_tooSoon'); - vm.expectRevert(Errors.TooEarlyUpdate.selector); - vault.setFeePercent(secondFeePercent); - _stopSnapshotGas(); - - // Fee percentage should remain at the first update - assertEq(vault.feePercent(), firstFeePercent, 'Fee percent should not change'); - - // Try again after the delay period - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - vm.prank(admin); - vault.setFeePercent(secondFeePercent); - assertEq(vault.feePercent(), secondFeePercent, 'Fee percent should update after delay'); - } - - function test_setFeePercent_maxIncrease() public { - // First set fee percentage - uint16 firstFeePercent = 500; // 5% - vm.prank(admin); - vault.setFeePercent(firstFeePercent); - - // Wait for delay period - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - - // Try to increase fee by more than 20% - uint16 invalidIncrease = 700; // 7% (more than 20% increase from 5%) - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_maxIncrease'); - vm.expectRevert(Errors.InvalidFeePercent.selector); - vault.setFeePercent(invalidIncrease); - _stopSnapshotGas(); - - // Fee percentage should remain at the first update - assertEq(vault.feePercent(), firstFeePercent, 'Fee percent should not change'); - - // Try a valid increase (below 20%) - uint16 validIncrease = 600; // 6% (20% increase from 5%) - vm.prank(admin); - vault.setFeePercent(validIncrease); - assertEq(vault.feePercent(), validIncrease, 'Fee percent should update with valid increase'); - } - - function test_setFeePercent_requiresHarvest() public { - // Make sure vault needs to be harvested - _collateralizeEthVault(address(vault)); - _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(rewardAmount)), - 0 - ); - - // Test setting fee percentage without harvesting - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - uint16 newFeePercent = 500; // 5% - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_requiresHarvest'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.setFeePercent(newFeePercent); - _stopSnapshotGas(); - - // First update state - vault.updateState(harvestParams); - - // Then try setting fee percentage again - vm.prank(admin); - vault.setFeePercent(newFeePercent); - assertEq(vault.feePercent(), newFeePercent, 'Fee percent should be updated after harvest'); - } - - function test_setFeePercent_initialZeroToOne() public { - // Create a new vault with 0% fee - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 0, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address zeroFeeVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - EthVault zeroFeeVault = EthVault(payable(zeroFeeVaultAddr)); - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - - // Ensure the initial fee percent is 0 - assertEq(zeroFeeVault.feePercent(), 0, 'Initial fee percent should be 0'); - - // Test increasing from 0% to 1% - vm.prank(admin); - _startSnapshotGas('VaultFeeTest_test_setFeePercent_initialZeroToOne'); - zeroFeeVault.setFeePercent(100); // 1% - _stopSnapshotGas(); - - // Verify the fee percentage was set to 1% - assertEq(zeroFeeVault.feePercent(), 100, 'Fee percent should be updated to 1%'); - - // Try to set fee to more than 1% immediately - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - vm.prank(admin); - vm.expectRevert(Errors.InvalidFeePercent.selector); - zeroFeeVault.setFeePercent(200); // 2% (more than allowed increase from 1%) - - // Fee percentage should remain at 1% - assertEq(zeroFeeVault.feePercent(), 100, 'Fee percent should remain at 1%'); - } - - function test_feeCollection() public { - // Setup: deposit ETH and make vault active - _depositToVault(address(vault), depositAmount, user, user); - _collateralizeEthVault(address(vault)); - - // Set a different fee recipient to track fee minting - vm.prank(admin); - vault.setFeeRecipient(feeRecipient); - - // Record initial shares of fee recipient - uint256 feeRecipientInitialShares = vault.getShares(feeRecipient); - - // Add a reward to the vault - int160 rewardValue = int160(int256(rewardAmount)); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - rewardValue, - 0 - ); - - // Update state to process rewards - _startSnapshotGas('VaultFeeTest_test_feeCollection'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify fee recipient received shares - uint256 feeRecipientFinalShares = vault.getShares(feeRecipient); - uint256 feeShares = feeRecipientFinalShares - feeRecipientInitialShares; - - // Check that the fee recipient got shares - assertGt(feeShares, 0, 'Fee recipient should receive shares'); - - // Convert shares to assets to verify percentage - uint256 feeAssets = vault.convertToAssets(feeShares); - - // Calculate expected fees with a small tolerance for rounding - uint256 expectedFeeAssets = (rewardAmount * initialFeePercent) / 10000; - assertApproxEqAbs( - feeAssets, - expectedFeeAssets, - 1e9, // 1 Gwei tolerance - 'Invalid fee assets minted' - ); - } - - function test_feePercent_changeAffectsFutureRewards() public { - // Setup: deposit ETH and make vault active - _depositToVault(address(vault), depositAmount, user, user); - _collateralizeEthVault(address(vault)); - - // Set a different fee recipient to track fee minting - vm.startPrank(admin); - vault.setFeeRecipient(feeRecipient); - while (vault.feePercent() != 1000) { - // increment by 20% until fee percent is 10% - uint256 newFeePercent = (uint256(vault.feePercent()) * 120) / 100; - if (newFeePercent > 1000) { - newFeePercent = 1000; - } - vault.setFeePercent(uint16(newFeePercent)); - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + ForkContracts public contracts; + EthVault public vault; + + address public admin; + address public user; + address public feeRecipient; + address public newFeeRecipient; + address public referrer = address(0); + + uint16 public initialFeePercent; + uint256 public depositAmount = 10 ether; + uint256 public rewardAmount = 1 ether; + uint256 public feeChangeDelay = 7 days; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + feeRecipient = makeAddr("feeRecipient"); + newFeeRecipient = makeAddr("newFeeRecipient"); + + // Fund accounts with ETH for testing + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + initialFeePercent = vault.feePercent(); + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + + vm.prank(admin); + vault.setFeeRecipient(admin); + } + + function test_initialFeeRecipient() public view { + // The fee recipient should initially be set to the admin as per the vault initialization + assertEq(vault.feeRecipient(), admin, "Initial fee recipient should be the admin"); + assertEq(vault.feePercent(), initialFeePercent, "Initial fee percent should match parameter"); + } + + function test_setFeeRecipient_success() public { + // Test setting a new fee recipient as admin + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeeRecipient_success"); + vault.setFeeRecipient(newFeeRecipient); + _stopSnapshotGas(); + + // Verify the new fee recipient + assertEq(vault.feeRecipient(), newFeeRecipient, "Fee recipient should be updated"); + } + + function test_setFeeRecipient_notAdmin() public { + // Test setting fee recipient as non-admin + vm.prank(user); + _startSnapshotGas("VaultFeeTest_test_setFeeRecipient_notAdmin"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setFeeRecipient(newFeeRecipient); + _stopSnapshotGas(); + + // Fee recipient should remain unchanged + assertEq(vault.feeRecipient(), admin, "Fee recipient should not change"); + } + + function test_setFeeRecipient_zeroAddress() public { + // Test setting fee recipient to zero address + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeeRecipient_zeroAddress"); + vm.expectRevert(Errors.InvalidFeeRecipient.selector); + vault.setFeeRecipient(address(0)); + _stopSnapshotGas(); + + // Fee recipient should remain unchanged + assertEq(vault.feeRecipient(), admin, "Fee recipient should not change"); + } + + function test_setFeeRecipient_requiresHarvest() public { + // Make sure vault needs to be harvested + _collateralizeEthVault(address(vault)); + + // update state twice to require harvesting + _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); + + // Test setting fee recipient without harvesting + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeeRecipient_requiresHarvest"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.setFeeRecipient(newFeeRecipient); + _stopSnapshotGas(); + + // First update state + vault.updateState(harvestParams); + + // Then try setting fee recipient again + vm.prank(admin); + vault.setFeeRecipient(newFeeRecipient); + assertEq(vault.feeRecipient(), newFeeRecipient, "Fee recipient should be updated after harvest"); + } + + function test_setFeePercent_success() public { + // Test setting a new fee percentage as admin + uint16 newFeePercent = vault.feePercent() + 1; + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_success"); + vault.setFeePercent(newFeePercent); + _stopSnapshotGas(); + + // Verify the new fee percentage + assertEq(vault.feePercent(), newFeePercent, "Fee percent should be updated"); + } + + function test_setFeePercent_notAdmin() public { + // Test setting fee percentage as non-admin + uint16 newFeePercent = 500; // 5% + vm.prank(user); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_notAdmin"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setFeePercent(newFeePercent); + _stopSnapshotGas(); + + // Fee percentage should remain unchanged + assertEq(vault.feePercent(), initialFeePercent, "Fee percent should not change"); + } + + function test_setFeePercent_aboveMaximum() public { + // Test setting fee percentage above maximum (10000 = 100%) + uint16 invalidFeePercent = 10001; // 100.01% + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_aboveMaximum"); + vm.expectRevert(Errors.InvalidFeePercent.selector); + vault.setFeePercent(invalidFeePercent); + _stopSnapshotGas(); + + // Fee percentage should remain unchanged + assertEq(vault.feePercent(), initialFeePercent, "Fee percent should not change"); + } + + function test_setFeePercent_tooSoon() public { + // First set fee percentage + uint16 firstFeePercent = 500; // 5% + vm.prank(admin); + vault.setFeePercent(firstFeePercent); + + // Then try to set again too soon (before feeChangeDelay have passed) + uint16 secondFeePercent = 600; // 6% + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_tooSoon"); + vm.expectRevert(Errors.TooEarlyUpdate.selector); + vault.setFeePercent(secondFeePercent); + _stopSnapshotGas(); + + // Fee percentage should remain at the first update + assertEq(vault.feePercent(), firstFeePercent, "Fee percent should not change"); + + // Try again after the delay period + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + vm.prank(admin); + vault.setFeePercent(secondFeePercent); + assertEq(vault.feePercent(), secondFeePercent, "Fee percent should update after delay"); + } + + function test_setFeePercent_maxIncrease() public { + // First set fee percentage + uint16 firstFeePercent = 500; // 5% + vm.prank(admin); + vault.setFeePercent(firstFeePercent); + + // Wait for delay period + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + + // Try to increase fee by more than 20% + uint16 invalidIncrease = 700; // 7% (more than 20% increase from 5%) + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_maxIncrease"); + vm.expectRevert(Errors.InvalidFeePercent.selector); + vault.setFeePercent(invalidIncrease); + _stopSnapshotGas(); + + // Fee percentage should remain at the first update + assertEq(vault.feePercent(), firstFeePercent, "Fee percent should not change"); + + // Try a valid increase (below 20%) + uint16 validIncrease = 600; // 6% (20% increase from 5%) + vm.prank(admin); + vault.setFeePercent(validIncrease); + assertEq(vault.feePercent(), validIncrease, "Fee percent should update with valid increase"); + } + + function test_setFeePercent_requiresHarvest() public { + // Make sure vault needs to be harvested + _collateralizeEthVault(address(vault)); + _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(rewardAmount)), 0); + + // Test setting fee percentage without harvesting + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + uint16 newFeePercent = 500; // 5% + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_requiresHarvest"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.setFeePercent(newFeePercent); + _stopSnapshotGas(); + + // First update state + vault.updateState(harvestParams); + + // Then try setting fee percentage again + vm.prank(admin); + vault.setFeePercent(newFeePercent); + assertEq(vault.feePercent(), newFeePercent, "Fee percent should be updated after harvest"); + } + + function test_setFeePercent_initialZeroToOne() public { + // Create a new vault with 0% fee + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 0, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address zeroFeeVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault zeroFeeVault = EthVault(payable(zeroFeeVaultAddr)); + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + + // Ensure the initial fee percent is 0 + assertEq(zeroFeeVault.feePercent(), 0, "Initial fee percent should be 0"); + + // Test increasing from 0% to 1% + vm.prank(admin); + _startSnapshotGas("VaultFeeTest_test_setFeePercent_initialZeroToOne"); + zeroFeeVault.setFeePercent(100); // 1% + _stopSnapshotGas(); + + // Verify the fee percentage was set to 1% + assertEq(zeroFeeVault.feePercent(), 100, "Fee percent should be updated to 1%"); + + // Try to set fee to more than 1% immediately + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + vm.prank(admin); + vm.expectRevert(Errors.InvalidFeePercent.selector); + zeroFeeVault.setFeePercent(200); // 2% (more than allowed increase from 1%) + + // Fee percentage should remain at 1% + assertEq(zeroFeeVault.feePercent(), 100, "Fee percent should remain at 1%"); + } + + function test_feeCollection() public { + // Setup: deposit ETH and make vault active + _depositToVault(address(vault), depositAmount, user, user); + _collateralizeEthVault(address(vault)); + + // Set a different fee recipient to track fee minting + vm.prank(admin); + vault.setFeeRecipient(feeRecipient); + + // Record initial shares of fee recipient + uint256 feeRecipientInitialShares = vault.getShares(feeRecipient); + + // Add a reward to the vault + int160 rewardValue = int160(int256(rewardAmount)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), rewardValue, 0); + + // Update state to process rewards + _startSnapshotGas("VaultFeeTest_test_feeCollection"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify fee recipient received shares + uint256 feeRecipientFinalShares = vault.getShares(feeRecipient); + uint256 feeShares = feeRecipientFinalShares - feeRecipientInitialShares; + + // Check that the fee recipient got shares + assertGt(feeShares, 0, "Fee recipient should receive shares"); + + // Convert shares to assets to verify percentage + uint256 feeAssets = vault.convertToAssets(feeShares); + + // Calculate expected fees with a small tolerance for rounding + uint256 expectedFeeAssets = (rewardAmount * initialFeePercent) / 10000; + assertApproxEqAbs( + feeAssets, + expectedFeeAssets, + 1e9, // 1 Gwei tolerance + "Invalid fee assets minted" + ); + } + + function test_feePercent_changeAffectsFutureRewards() public { + // Setup: deposit ETH and make vault active + _depositToVault(address(vault), depositAmount, user, user); + _collateralizeEthVault(address(vault)); + + // Set a different fee recipient to track fee minting + vm.startPrank(admin); + vault.setFeeRecipient(feeRecipient); + while (vault.feePercent() != 1000) { + // increment by 20% until fee percent is 10% + uint256 newFeePercent = (uint256(vault.feePercent()) * 120) / 100; + if (newFeePercent > 1000) { + newFeePercent = 1000; + } + vault.setFeePercent(uint16(newFeePercent)); + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + } + vm.stopPrank(); + assertEq(vault.feePercent(), 1000, "Fee percent should be updated to 10%"); + + // Record initial shares of fee recipient + uint256 feeRecipientInitialShares = vault.getShares(feeRecipient); + + // First reward with 10% fee + int160 firstRewardValue = int160(int256(rewardAmount)); + IKeeperRewards.HarvestParams memory firstHarvestParams = _setEthVaultReward(address(vault), firstRewardValue, 0); + vault.updateState(firstHarvestParams); + + // Record intermediate shares + uint256 feeRecipientMidShares = vault.getShares(feeRecipient); + uint256 firstFeeShares = feeRecipientMidShares - feeRecipientInitialShares; + uint256 firstFeeAssets = vault.convertToAssets(firstFeeShares); + + // Change fee percentage to 5% + vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); + vm.prank(admin); + vault.setFeePercent(500); + assertEq(vault.feePercent(), 500, "Fee percent should be updated to 5%"); + + // Second reward with 5% fee + int160 secondRewardValue = firstRewardValue + int160(int256(rewardAmount)); + IKeeperRewards.HarvestParams memory secondHarvestParams = + _setEthVaultReward(address(vault), secondRewardValue, 0); + + _startSnapshotGas("VaultFeeTest_test_feePercent_changeAffectsFutureRewards"); + vault.updateState(secondHarvestParams); + _stopSnapshotGas(); + + // Record final shares + uint256 feeRecipientFinalShares = vault.getShares(feeRecipient); + uint256 secondFeeShares = feeRecipientFinalShares - feeRecipientMidShares; + uint256 secondFeeAssets = vault.convertToAssets(secondFeeShares); + + // Calculate expected fees with a small tolerance for rounding + uint256 expectedFirstFeeAssets = (rewardAmount * 1000) / 10000; // 10% + uint256 expectedSecondFeeAssets = (rewardAmount * 500) / 10000; // 5% + + assertApproxEqAbs( + firstFeeAssets, + expectedFirstFeeAssets, + 1e9, // 1 Gwei tolerance + "First fee assets should be approximately 10% of reward" + ); + + assertApproxEqAbs( + secondFeeAssets, + expectedSecondFeeAssets, + 1e9, // 1 Gwei tolerance + "Second fee assets should be approximately 5% of reward" + ); + + // The ratio of second fee to first fee should be about 1:2 (5% vs 10%) + assertApproxEqRel( + secondFeeAssets * 2, + firstFeeAssets, + 0.05e18, // 5% tolerance + "Second fee should be about half of first fee" + ); } - vm.stopPrank(); - assertEq(vault.feePercent(), 1000, 'Fee percent should be updated to 10%'); - - // Record initial shares of fee recipient - uint256 feeRecipientInitialShares = vault.getShares(feeRecipient); - - // First reward with 10% fee - int160 firstRewardValue = int160(int256(rewardAmount)); - IKeeperRewards.HarvestParams memory firstHarvestParams = _setEthVaultReward( - address(vault), - firstRewardValue, - 0 - ); - vault.updateState(firstHarvestParams); - - // Record intermediate shares - uint256 feeRecipientMidShares = vault.getShares(feeRecipient); - uint256 firstFeeShares = feeRecipientMidShares - feeRecipientInitialShares; - uint256 firstFeeAssets = vault.convertToAssets(firstFeeShares); - - // Change fee percentage to 5% - vm.warp(vm.getBlockTimestamp() + feeChangeDelay + 1); - vm.prank(admin); - vault.setFeePercent(500); - assertEq(vault.feePercent(), 500, 'Fee percent should be updated to 5%'); - - // Second reward with 5% fee - int160 secondRewardValue = firstRewardValue + int160(int256(rewardAmount)); - IKeeperRewards.HarvestParams memory secondHarvestParams = _setEthVaultReward( - address(vault), - secondRewardValue, - 0 - ); - - _startSnapshotGas('VaultFeeTest_test_feePercent_changeAffectsFutureRewards'); - vault.updateState(secondHarvestParams); - _stopSnapshotGas(); - - // Record final shares - uint256 feeRecipientFinalShares = vault.getShares(feeRecipient); - uint256 secondFeeShares = feeRecipientFinalShares - feeRecipientMidShares; - uint256 secondFeeAssets = vault.convertToAssets(secondFeeShares); - - // Calculate expected fees with a small tolerance for rounding - uint256 expectedFirstFeeAssets = (rewardAmount * 1000) / 10000; // 10% - uint256 expectedSecondFeeAssets = (rewardAmount * 500) / 10000; // 5% - - assertApproxEqAbs( - firstFeeAssets, - expectedFirstFeeAssets, - 1e9, // 1 Gwei tolerance - 'First fee assets should be approximately 10% of reward' - ); - - assertApproxEqAbs( - secondFeeAssets, - expectedSecondFeeAssets, - 1e9, // 1 Gwei tolerance - 'Second fee assets should be approximately 5% of reward' - ); - - // The ratio of second fee to first fee should be about 1:2 (5% vs 10%) - assertApproxEqRel( - secondFeeAssets * 2, - firstFeeAssets, - 0.05e18, // 5% tolerance - 'Second fee should be about half of first fee' - ); - } } diff --git a/test/VaultOsToken.t.sol b/test/VaultOsToken.t.sol index b5fe1239..71fb4fdb 100644 --- a/test/VaultOsToken.t.sol +++ b/test/VaultOsToken.t.sol @@ -1,1470 +1,1373 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IOsTokenVaultController} from '../contracts/interfaces/IOsTokenVaultController.sol'; -import {IOsTokenConfig} from '../contracts/interfaces/IOsTokenConfig.sol'; -import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; -import {IVaultOsToken} from '../contracts/interfaces/IVaultOsToken.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; +import {Test} from "forge-std/Test.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IOsTokenVaultController} from "../contracts/interfaces/IOsTokenVaultController.sol"; +import {IOsTokenConfig} from "../contracts/interfaces/IOsTokenConfig.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {IVaultOsToken} from "../contracts/interfaces/IVaultOsToken.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; interface IStrategiesRegistry { - function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; - function setStrategy(address strategy, bool enabled) external; + function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; + function setStrategy(address strategy, bool enabled) external; - function owner() external view returns (address); + function owner() external view returns (address); } contract VaultOsTokenTest is Test, EthHelpers { - IStrategiesRegistry private constant _strategiesRegistry = - IStrategiesRegistry(0x90b82E4b3aa385B4A02B7EBc1892a4BeD6B5c465); - - ForkContracts public contracts; - EthVault public vault; - IOsTokenVaultController public osTokenVaultController; - IOsTokenConfig public osTokenConfig; - - address public owner; - address public receiver; - address public admin; - address public referrer; - - uint256 public depositAmount = 5 ether; - - function setUp() public { - // Get fork contracts - contracts = _activateEthereumFork(); - osTokenVaultController = contracts.osTokenVaultController; - osTokenConfig = contracts.osTokenConfig; - - // Set up test accounts - owner = makeAddr('owner'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - referrer = makeAddr('referrer'); - - // Fund accounts for testing - vm.deal(owner, 100 ether); - vm.deal(admin, 100 ether); - vm.deal(receiver, 1 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Deposit to vault - _depositToVault(address(vault), depositAmount, owner, owner); - - // Collateralize vault (required for minting OsToken) - _collateralizeEthVault(address(vault)); - - vm.warp(vm.getBlockTimestamp() + 7 days + 1); - } - - // Test basic minting functionality - function test_mintOsToken_basic() public { - // Start with clean slate - uint256 initialOsTokenShares = vault.osTokenPositions(owner); - - // Calculate a portion of max mintable amount to use - uint256 osTokenSharesToMint = contracts.osTokenVaultController.convertToShares(1 ether); - - // Expect the OsTokenMinted event to be emitted - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, osTokenSharesToMint, referrer); - - // Mint OsToken - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_basic'); - uint256 assets = vault.mintOsToken(receiver, osTokenSharesToMint, referrer); - _stopSnapshotGas(); - - // Verify minting was successful - assertGt(assets, 0, 'Should have minted assets'); - assertEq( - vault.osTokenPositions(owner), - initialOsTokenShares + osTokenSharesToMint, - "Owner's OsToken position should increase" - ); - } - - // Test minting maximum amount using type(uint256).max - function test_mintOsToken_maxAmount() public { - // Start with clean slate - uint256 initialOsTokenShares = vault.osTokenPositions(owner); - - // Expect the OsTokenMinted event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, 0, referrer); // We don't know exact share amount, just verify caller - - // Mint max OsToken - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_maxAmount'); - uint256 assets = vault.mintOsToken(receiver, type(uint256).max, referrer); - _stopSnapshotGas(); - - // Verify minting was successful and minted the max available - assertGt(assets, 0, 'Should have minted assets'); - assertGt( - vault.osTokenPositions(owner), - initialOsTokenShares, - "Owner's OsToken position should increase" - ); - - // Try minting max again - should mint 0 as already at max - vm.prank(owner); - uint256 assetsRetry = vault.mintOsToken(receiver, type(uint256).max, referrer); - - assertEq(assetsRetry, 0, 'Should not mint additional shares when at max'); - } - - // Test LTV validation - function test_mintOsToken_ltvValidation() public { - // Get LTV percent from config - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - - // Calculate an amount that would exceed LTV - uint256 userAssets = vault.convertToAssets(vault.getShares(owner)); - uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; - uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); - - // Try to mint slightly more than max allowed - uint256 excessShares = maxOsTokenShares + 1; - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_ltvValidation'); - vm.expectRevert(Errors.LowLtv.selector); - vault.mintOsToken(receiver, excessShares, referrer); - _stopSnapshotGas(); - } - - // Test that entering exit queue fails when it would violate LTV - function test_enterExitQueue_ltvViolation() public { - // First mint maximum OsToken shares - uint256 userShares = vault.getShares(owner); - uint256 userAssets = vault.convertToAssets(userShares); - - // Get LTV percent from config - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; - uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); - - // Expect OsTokenMinted event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenMinted(owner, owner, 0, maxOsTokenShares, referrer); - - // Mint maximum OsToken shares - vm.prank(owner); - vault.mintOsToken(owner, maxOsTokenShares, referrer); - - // Now try to enter exit queue with some shares - // Even a small amount should fail because it would reduce collateral and violate LTV - uint256 exitAmount = userShares / 10; // Try to exit 10% of shares - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_enterExitQueue_ltvViolation'); - vm.expectRevert(Errors.LowLtv.selector); - vault.enterExitQueue(exitAmount, owner); - _stopSnapshotGas(); - - // Verify that burning some OsToken shares first would allow entering exit queue - uint128 burnAmount = uint128(maxOsTokenShares / 5); // Burn 20% of OsToken position - - // Expect OsTokenBurned event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); - - vm.prank(owner); - vault.burnOsToken(burnAmount); - - // Now should be able to enter exit queue - vm.prank(owner); - vault.enterExitQueue(exitAmount, owner); - } - - // Test fee syncing for existing positions - function test_mintOsToken_feeSync() public { - // First mint to create position - uint256 firstMintShares = contracts.osTokenVaultController.convertToShares(1 ether); - - // Expect OsTokenMinted event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenMinted(owner, owner, 0, firstMintShares, referrer); - - vm.prank(owner); - vault.mintOsToken(owner, firstMintShares, referrer); - - // Simulate time passing and reward accumulation to change cumulativeFeePerShare - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - vm.roll(block.number + 1000); - vm.warp(vm.getBlockTimestamp() + 1 days); - - // Update controller state to change cumulativeFeePerShare - vault.updateState(harvestParams); - osTokenVaultController.updateState(); - - // Record position before second mint - uint256 positionBefore = vault.osTokenPositions(owner); - - // Expect OsTokenMinted event for second mint - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenMinted(owner, owner, 0, firstMintShares / 2, referrer); - - // Mint more OsToken shares - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_feeSync'); - vault.mintOsToken(owner, firstMintShares / 2, referrer); - _stopSnapshotGas(); - - // Position should increase by more than the mint amount due to fee sync - vm.warp(vm.getBlockTimestamp() + 1 days); - uint256 positionAfter = vault.osTokenPositions(owner); - assertGt( - positionAfter, - positionBefore + firstMintShares / 2, - 'Position should increase more than mint amount due to fee sync' - ); - } - - // Test zero shares - function test_mintOsToken_zeroShares() public { - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_zeroShares'); - vm.expectRevert(Errors.InvalidShares.selector); - vault.mintOsToken(receiver, 0, referrer); - _stopSnapshotGas(); - } - - function test_mintOsToken_zeroAddressReceiver() public { - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - - // Try to mint to the zero address - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_zeroAddressReceiver'); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.mintOsToken(address(0), mintAmount, referrer); - _stopSnapshotGas(); - } - - // Test when vault is not collateralized - function test_mintOsToken_notCollateralized() public { - // Create a new vault that is not collateralized - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'test' - }) - ); - address newVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - EthVault newVault = EthVault(payable(newVaultAddr)); - - // Deposit to vault - _depositToVault(address(newVault), depositAmount, owner, owner); - - // Try to mint OsToken with uncollateralized vault - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_notCollateralized'); - vm.expectRevert(Errors.NotCollateralized.selector); - newVault.mintOsToken(receiver, mintAmount, referrer); - _stopSnapshotGas(); - } - - // Test when vault is not harvested - function test_mintOsToken_notHarvested() public { - // Set up reward parameters but don't harvest - _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.5 ether)), - 0 - ); - - // Force vault to need harvesting - vm.warp(vm.getBlockTimestamp() + 1 days); - - // Try to mint OsToken when vault needs harvesting - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_notHarvested'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.mintOsToken(receiver, mintAmount, referrer); - _stopSnapshotGas(); - - // Update state and try again - should work - vault.updateState(harvestParams); - - // Expect OsTokenMinted event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, mintAmount, referrer); - - vm.prank(owner); - uint256 assets = vault.mintOsToken(receiver, mintAmount, referrer); - assertGt(assets, 0, 'Should mint after harvesting'); - } - - // Test repeated minting until max - function test_mintOsToken_repeatedMinting() public { - // Get LTV percent from config - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - - // Calculate max OsToken shares - uint256 userAssets = vault.convertToAssets(vault.getShares(owner)); - uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; - uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); - - // Mint in small increments until approaching max - uint256 incrementAmount = maxOsTokenShares / 10; - uint256 totalMinted = 0; - - for (uint i = 0; i < 9; i++) { - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_repeatedMinting'); - uint256 assets = vault.mintOsToken(receiver, incrementAmount, referrer); - _stopSnapshotGas(); - - assertGt(assets, 0, 'Should be able to mint'); - totalMinted += incrementAmount; + IStrategiesRegistry private constant _strategiesRegistry = + IStrategiesRegistry(0x90b82E4b3aa385B4A02B7EBc1892a4BeD6B5c465); + + ForkContracts public contracts; + EthVault public vault; + IOsTokenVaultController public osTokenVaultController; + IOsTokenConfig public osTokenConfig; + + address public owner; + address public receiver; + address public admin; + address public referrer; + + uint256 public depositAmount = 5 ether; + + function setUp() public { + // Get fork contracts + contracts = _activateEthereumFork(); + osTokenVaultController = contracts.osTokenVaultController; + osTokenConfig = contracts.osTokenConfig; + + // Set up test accounts + owner = makeAddr("owner"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + referrer = makeAddr("referrer"); + + // Fund accounts for testing + vm.deal(owner, 100 ether); + vm.deal(admin, 100 ether); + vm.deal(receiver, 1 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deposit to vault + _depositToVault(address(vault), depositAmount, owner, owner); + + // Collateralize vault (required for minting OsToken) + _collateralizeEthVault(address(vault)); + + vm.warp(vm.getBlockTimestamp() + 7 days + 1); } - // Try to mint more than remaining max - uint256 remaining = maxOsTokenShares - totalMinted; - vm.prank(owner); - vm.expectRevert(Errors.LowLtv.selector); - vault.mintOsToken(receiver, remaining + 1, referrer); - - // Mint exactly the remaining amount - should succeed - vm.prank(owner); - uint256 finalAssets = vault.mintOsToken(receiver, remaining, referrer); - assertGt(finalAssets, 0, 'Should be able to mint exact remaining amount'); - } - - // Test minting to different receivers - function test_mintOsToken_multipleReceivers() public { - address receiver1 = makeAddr('receiver1'); - address receiver2 = makeAddr('receiver2'); - - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - - // Mint to first receiver - vm.prank(owner); - uint256 assets1 = vault.mintOsToken(receiver1, mintAmount, referrer); - assertGt(assets1, 0, 'Should mint to first receiver'); - - // Mint to second receiver - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_mintOsToken_multipleReceivers'); - uint256 assets2 = vault.mintOsToken(receiver2, mintAmount, referrer); - _stopSnapshotGas(); - assertGt(assets2, 0, 'Should mint to second receiver'); - - // Verify position is tracked against owner regardless of receiver - uint256 ownerPosition = vault.osTokenPositions(owner); - assertEq(ownerPosition, mintAmount * 2, 'Owner position should track all minting'); - } - - // Test basic burn functionality - function test_burnOsToken_basic() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Verify initial position - uint256 initialPosition = vault.osTokenPositions(owner); - assertEq(initialPosition, mintAmount, 'Initial position should equal minted amount'); - - // Burn a portion of shares - uint128 burnAmount = uint128(mintAmount / 2); - - // Expect OsTokenBurned event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_basic'); - uint256 burnedAssets = vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - - // Verify position is updated correctly - uint256 remainingPosition = vault.osTokenPositions(owner); - assertEq( - remainingPosition, - initialPosition - burnAmount, - 'Position should be reduced by burn amount' - ); - - // Verify assets were returned - assertGt(burnedAssets, 0, 'Should return positive asset amount'); - } - - // Test burning all shares - function test_burnOsToken_allShares() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Verify initial position - uint256 initialPosition = vault.osTokenPositions(owner); - - // Burn all shares - uint128 burnAmount = uint128(initialPosition); - - // Expect OsTokenBurned event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_allShares'); - uint256 burnedAssets = vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - - // Verify position is updated correctly - uint256 remainingPosition = vault.osTokenPositions(owner); - assertEq(remainingPosition, 0, 'Position should be zero after burning all shares'); - - // Verify assets were returned - assertGt(burnedAssets, 0, 'Should return positive asset amount'); - } - - // Test attempting to burn zero shares - function test_burnOsToken_zeroShares() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Try to burn zero shares - uint128 burnAmount = 0; - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_zeroShares'); - vm.expectRevert(Errors.InvalidShares.selector); - vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - } - - // Test attempting to burn more shares than owned - function test_burnOsToken_exceedingShares() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Try to burn more than owned - uint128 burnAmount = uint128(mintAmount * 2); - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_exceedingShares'); - vm.expectRevert(); // Should revert, possibly with an arithmetic underflow - vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - } - - // Test burning with non-existent position - function test_burnOsToken_invalidPosition() public { - // Use a different address that has no position - address nonPositionHolder = makeAddr('nonPositionHolder'); - - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(nonPositionHolder, mintAmount, referrer); - - uint128 burnAmount = 1000; - vm.prank(nonPositionHolder); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_invalidPosition'); - vm.expectRevert(Errors.InvalidPosition.selector); - vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - } - - // Test burning after fee sync - function test_burnOsToken_afterFeeSync() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Record initial position - uint256 initialPosition = vault.osTokenPositions(owner); - - // Simulate time passing and reward accumulation - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - vm.roll(block.number + 1000); - vm.warp(vm.getBlockTimestamp() + 1 days); - - // Update states to trigger fee sync - vault.updateState(harvestParams); - osTokenVaultController.updateState(); - - // Position should have grown due to fee sync - uint256 positionAfterFeeSync = vault.osTokenPositions(owner); - assertGt(positionAfterFeeSync, initialPosition, 'Position should increase after fee sync'); - - // Burn a portion of shares - uint128 burnAmount = uint128(mintAmount / 2); - - // Expect OsTokenBurned event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_afterFeeSync'); - uint256 burnedAssets = vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - - // Verify position is updated correctly - uint256 remainingPosition = vault.osTokenPositions(owner); - assertLt(remainingPosition, positionAfterFeeSync, 'Position should decrease after burning'); - assertGt(burnedAssets, 0, 'Should return positive asset amount'); - } - - // Test multiple burn operations - function test_burnOsToken_multipleBurns() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(2 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Verify initial position - uint256 initialPosition = vault.osTokenPositions(owner); - - // Burn in multiple steps - uint128 burnAmount1 = uint128(mintAmount / 4); - uint128 burnAmount2 = uint128(mintAmount / 4); - - // Expect OsTokenBurned event for first burn - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount1); - - // First burn - vm.prank(owner); - uint256 burnedAssets1 = vault.burnOsToken(burnAmount1); - - // Verify position after first burn - uint256 positionAfterFirstBurn = vault.osTokenPositions(owner); - assertEq( - positionAfterFirstBurn, - initialPosition - burnAmount1, - 'Position incorrect after first burn' - ); - - // Expect OsTokenBurned event for second burn - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount2); - - // Second burn - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_multipleBurns'); - uint256 burnedAssets2 = vault.burnOsToken(burnAmount2); - _stopSnapshotGas(); - - // Verify position after second burn - uint256 positionAfterSecondBurn = vault.osTokenPositions(owner); - assertEq( - positionAfterSecondBurn, - initialPosition - burnAmount1 - burnAmount2, - 'Position incorrect after second burn' - ); - - assertGt(burnedAssets1, 0, 'First burn should return positive assets'); - assertGt(burnedAssets2, 0, 'Second burn should return positive assets'); - } - - // Test that burn succeeds when it would have previously violated LTV - function test_burnOsToken_improvesLTV() public { - // First mint maximum OsToken shares - uint256 userShares = vault.getShares(owner); - uint256 userAssets = vault.convertToAssets(userShares); - - // Get LTV percent from config - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; - uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); - - // Mint maximum OsToken shares - vm.prank(owner); - vault.mintOsToken(owner, maxOsTokenShares, referrer); - - // Try to enter exit queue with some shares - should fail due to LTV - uint256 exitAmount = userShares / 10; - vm.prank(owner); - vm.expectRevert(Errors.LowLtv.selector); - vault.enterExitQueue(exitAmount, owner); - - // Now burn some OsToken shares - uint128 burnAmount = uint128(maxOsTokenShares / 5); - - // Expect OsTokenBurned event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_burnOsToken_improvesLTV'); - uint256 burnedAssets = vault.burnOsToken(burnAmount); - _stopSnapshotGas(); - - assertGt(burnedAssets, 0, 'Should return positive asset amount'); - - // Now should be able to enter exit queue - vm.prank(owner); - vault.enterExitQueue(exitAmount, owner); - } - - // Test that only the redeemer can call redeemOsToken - function test_redeemOsToken_onlyRedeemer() public { - // Create a position first - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Try to redeem as non-redeemer - address nonRedeemer = makeAddr('nonRedeemer'); - vm.prank(nonRedeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_onlyRedeemer'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.redeemOsToken(mintAmount, owner, receiver); - _stopSnapshotGas(); - - // Get current redeemer - address redeemer = osTokenConfig.redeemer(); - vm.prank(redeemer); - vault.redeemOsToken(mintAmount / 2, owner, receiver); - - // Verify position was reduced - assertLt( - vault.osTokenPositions(owner), - mintAmount, - 'Position should be reduced after redemption' - ); - } - - // Test basic redemption functionality - function test_redeemOsToken_basic() public { - // Create a position first - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Initial position - uint256 initialPosition = vault.osTokenPositions(owner); - uint256 initialReceiverBalance = receiver.balance; - - // Get current redeemer and perform redemption - address redeemer = osTokenConfig.redeemer(); - uint256 redeemAmount = mintAmount / 2; - - // Expect OsTokenRedeemed event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, redeemAmount, 0, 0); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_basic'); - vault.redeemOsToken(redeemAmount, owner, receiver); - _stopSnapshotGas(); - - // Verify position was updated correctly - uint256 finalPosition = vault.osTokenPositions(owner); - assertEq( - finalPosition, - initialPosition - redeemAmount, - 'Position should be reduced by redemption amount' - ); - - // Verify receiver got the assets - assertGt(receiver.balance, initialReceiverBalance, 'Receiver should receive assets'); - } - - // Test redemption with non-existent position - function test_redeemOsToken_nonExistentPosition() public { - // Try to redeem from an address with no position - address noPositionAddr = makeAddr('noPosition'); - address redeemer = osTokenConfig.redeemer(); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_nonExistentPosition'); - vm.expectRevert(Errors.InvalidPosition.selector); - vault.redeemOsToken(1 ether, noPositionAddr, receiver); - _stopSnapshotGas(); - } - - // Test redemption with insufficient shares - function test_redeemOsToken_insufficientShares() public { - // Create a small position - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Try to redeem more than available - address redeemer = osTokenConfig.redeemer(); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_insufficientShares'); - vm.expectRevert(); // Should revert due to arithmetic underflow - vault.redeemOsToken(mintAmount * 2, owner, receiver); - _stopSnapshotGas(); - } - - // Test redemption after fee sync occurs - function test_redeemOsToken_afterFeeSync() public { - // Create a position first - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Record initial position - uint256 initialPosition = vault.osTokenPositions(owner); - - // Simulate time passing and reward accumulation - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - vm.roll(block.number + 1000); - vm.warp(vm.getBlockTimestamp() + 1 days); - - // Update states to trigger fee sync - vault.updateState(harvestParams); - osTokenVaultController.updateState(); - - // Position should have grown due to fee sync - uint256 positionAfterFeeSync = vault.osTokenPositions(owner); - assertGt(positionAfterFeeSync, initialPosition, 'Position should increase after fee sync'); - - // Redeem a portion of shares - uint256 redeemAmount = mintAmount / 2; - address redeemer = osTokenConfig.redeemer(); - - // Expect OsTokenRedeemed event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, redeemAmount, 0, 0); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_afterFeeSync'); - vault.redeemOsToken(redeemAmount, owner, receiver); - _stopSnapshotGas(); - - // Verify position is updated correctly - uint256 remainingPosition = vault.osTokenPositions(owner); - assertLt(remainingPosition, positionAfterFeeSync, 'Position should decrease after redemption'); - } - - // Test redemption with health factor above liquidation threshold - function test_redeemOsToken_goodHealthFactor() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Health factor is good at this point - - // Redemption should work even with good health factor - address redeemer = osTokenConfig.redeemer(); - - // Expect OsTokenRedeemed event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount / 2, 0, 0); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_goodHealthFactor'); - vault.redeemOsToken(mintAmount / 2, owner, receiver); - _stopSnapshotGas(); - - // Verify position was updated - assertLt( - vault.osTokenPositions(owner), - mintAmount, - 'Position should be reduced after redemption' - ); - } - - // Test redemption with zero address receiver - function test_redeemOsToken_zeroAddressReceiver() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Try to redeem to zero address - address redeemer = osTokenConfig.redeemer(); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_zeroAddressReceiver'); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.redeemOsToken(mintAmount / 2, owner, address(0)); - _stopSnapshotGas(); - } - - // Test redemption with zero shares - function test_redeemOsToken_zeroShares() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Try to redeem zero shares - address redeemer = osTokenConfig.redeemer(); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_zeroShares'); - vm.expectRevert(); // Will revert but not with Errors.InvalidShares since validation happens at different point - vault.redeemOsToken(0, owner, receiver); - _stopSnapshotGas(); - } - - // Test full redemption of position - function test_redeemOsToken_fullPosition() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Redeem entire position - address redeemer = osTokenConfig.redeemer(); - - // Expect OsTokenRedeemed event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount, 0, 0); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_fullPosition'); - vault.redeemOsToken(mintAmount, owner, receiver); - _stopSnapshotGas(); - - // Verify position is zero - uint256 finalPosition = vault.osTokenPositions(owner); - assertEq(finalPosition, 0, 'Position should be zero after full redemption'); - } - - // Test redemption after state update - function test_redeemOsToken_afterStateUpdate() public { - // First mint some OsToken shares - uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, mintAmount, referrer); - - // Force state update required - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - vm.warp(vm.getBlockTimestamp() + 1 days); - - // Vault needs harvesting at this point - assertTrue(contracts.keeper.isHarvestRequired(address(vault)), 'Vault should need harvesting'); - - // Try to redeem - should fail due to not harvested - address redeemer = osTokenConfig.redeemer(); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.redeemOsToken(mintAmount / 2, owner, receiver); - _stopSnapshotGas(); - - // Update state - vault.updateState(harvestParams); - - // Now redemption should work - - // Expect OsTokenRedeemed event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount / 2, 0, 0); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success'); - vault.redeemOsToken(mintAmount / 2, owner, receiver); - _stopSnapshotGas(); - - // Verify position was updated - assertLt( - vault.osTokenPositions(owner), - mintAmount, - 'Position should be reduced after redemption' - ); - } - - // Test comparison between liquidation and redemption - function test_redeemVsLiquidate() public { - // First mint maximum OsToken shares - uint256 userShares = vault.getShares(owner); - uint256 userAssets = vault.convertToAssets(userShares); - - // Get LTV percent from config - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; - uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); - - // Mint maximum OsToken shares - vm.prank(owner); - vault.mintOsToken(owner, maxOsTokenShares, referrer); - - // Enter exit queue with almost all vault shares to create poor health factor - uint256 exitAmount = (userShares * 90) / 100; // Exit 90% of shares - vm.prank(owner); - vm.expectRevert(Errors.LowLtv.selector); // Should fail due to poor health factor - vault.enterExitQueue(exitAmount, owner); - - // Try to liquidate - will fail because health factor not below threshold yet - address liquidator = makeAddr('liquidator'); - vm.prank(liquidator); - vm.expectRevert(Errors.InvalidHealthFactor.selector); - vault.liquidateOsToken(maxOsTokenShares / 2, owner, liquidator); - - // But redeemer can redeem regardless of health factor - address redeemer = osTokenConfig.redeemer(); - - // Expect OsTokenRedeemed event - vm.expectEmit(true, false, false, false); - emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, maxOsTokenShares / 2, 0, 0); - - vm.prank(redeemer); - _startSnapshotGas('VaultOsTokenTest_test_redeemVsLiquidate'); - vault.redeemOsToken(maxOsTokenShares / 2, owner, receiver); - _stopSnapshotGas(); - - // Verify redemption worked - assertLt( - vault.osTokenPositions(owner), - maxOsTokenShares, - 'Position should be reduced after redemption' - ); - } - - // Test basic liquidation functionality - function test_liquidateOsToken_basic() public { - _depositToVault(address(vault), 10 ether, owner, owner); - - vm.prank(owner); - uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); - uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); - - // Get vault state and configuration - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - int256 requiredPenalty = int256(vault.totalAssets()) - - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); - requiredPenalty = -requiredPenalty; - - // Apply the penalty - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(requiredPenalty), - 0 - ); - vault.updateState(harvestParams); - - // Verify the position is now liquidatable - address liquidator = makeAddr('liquidator'); - uint256 liquidatorInitialBalance = liquidator.balance; - _mintOsToken(liquidator, osTokenShares); - - // Expect OsTokenLiquidated event - vm.expectEmit(true, true, false, false); - emit IVaultOsToken.OsTokenLiquidated( - liquidator, // caller - owner, // user - liquidator, // receiver - osTokenShares, - 0, // shares - we don't know exact value - 0 // receivedAssets - we don't know exact value - ); - - // Perform liquidation - vm.prank(liquidator); - _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_basic'); - vault.liquidateOsToken(osTokenShares, owner, liquidator); - _stopSnapshotGas(); - - // Verify liquidation results - assertApproxEqAbs( - vault.osTokenPositions(owner), - 0, - 0.0001 ether, - 'Position should be reduced after liquidation' - ); - assertGt(liquidator.balance, liquidatorInitialBalance, 'Liquidator should receive assets'); - } - - // Test liquidation bonus calculation - function test_liquidateOsToken_bonus() public { - _depositToVault(address(vault), 10 ether, owner, owner); - - vm.prank(owner); - uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); - uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); - - // Get configuration - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - - // Calculate and apply penalty to make position liquidatable - int256 requiredPenalty = int256(vault.totalAssets()) - - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); - requiredPenalty = -requiredPenalty; - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(requiredPenalty), - 0 - ); - vault.updateState(harvestParams); - - // Calculate expected bonus - uint256 liquidationAmount = osTokenShares / 4; - uint256 normalAssets = osTokenVaultController.convertToAssets(liquidationAmount); - uint256 expectedAssets = (normalAssets * config.liqBonusPercent) / 1e18; - - // Prepare liquidator - address liquidator = makeAddr('liquidator'); - uint256 liquidatorInitialBalance = liquidator.balance; - _mintOsToken(liquidator, liquidationAmount); - - // Expect OsTokenLiquidated event - vm.expectEmit(true, true, false, false); - emit IVaultOsToken.OsTokenLiquidated( - liquidator, // caller - owner, // user - liquidator, // receiver - liquidationAmount, - 0, // shares - we don't know exact value - 0 // receivedAssets - we don't know exact value - ); - - // Perform liquidation - vm.prank(liquidator); - _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_bonus'); - vault.liquidateOsToken(liquidationAmount, owner, liquidator); - _stopSnapshotGas(); - - // Verify liquidator received a bonus - uint256 receivedAssets = liquidator.balance - liquidatorInitialBalance; - assertGt(receivedAssets, normalAssets, 'Liquidator should receive bonus'); - - // Check the bonus is approximately as expected (with some tolerance for gas costs) - uint256 tolerance = expectedAssets / 20; // 5% tolerance - assertApproxEqAbs( - receivedAssets, - expectedAssets, - tolerance, - 'Received assets should match expected bonus calculation' - ); - } - - // Test that liquidation is disabled when configured - function test_liquidateOsToken_liquidationDisabled() public { - // Create a vault with disabled liquidations - address adminWithDisabledLiq = makeAddr('adminWithDisabledLiq'); - vm.deal(adminWithDisabledLiq, 100 ether); - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'test' - }) - ); - - address vaultAddr = _getOrCreateVault( - VaultType.EthVault, - adminWithDisabledLiq, - initParams, - false - ); - EthVault vaultWithDisabledLiq = EthVault(payable(vaultAddr)); - - // Disable liquidations - vm.startPrank(Ownable(address(osTokenConfig)).owner()); - IOsTokenConfig.Config memory disabledLiqConfig = IOsTokenConfig.Config({ - ltvPercent: 0.9999 ether, - liqThresholdPercent: type(uint64).max, // Disable liquidations - liqBonusPercent: 0 - }); - osTokenConfig.updateConfig(address(vaultWithDisabledLiq), disabledLiqConfig); - vm.stopPrank(); - - // Deposit to vault and collateralize - address vaultOwner = makeAddr('vaultOwner'); - vm.deal(vaultOwner, 100 ether); - _depositToVault(address(vaultWithDisabledLiq), 50 ether, vaultOwner, vaultOwner); - _collateralizeEthVault(address(vaultWithDisabledLiq)); - - // Create a position - vm.prank(vaultOwner); - uint256 osTokenAssets = vaultWithDisabledLiq.mintOsToken( - vaultOwner, - type(uint256).max, - referrer - ); - uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); - - // Apply severe penalty - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vaultWithDisabledLiq), - int160(int256(-10 ether)), - 0 - ); - vaultWithDisabledLiq.updateState(harvestParams); - - // Prepare liquidator - address liquidator = makeAddr('liquidator'); - uint256 liquidationAmount = osTokenShares / 4; - _mintOsToken(liquidator, liquidationAmount); - - // Try to liquidate - should fail because liquidations are disabled - vm.prank(liquidator); - _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_liquidationDisabled'); - vm.expectRevert(Errors.LiquidationDisabled.selector); - vaultWithDisabledLiq.liquidateOsToken(liquidationAmount, vaultOwner, liquidator); - _stopSnapshotGas(); - } - - // Test that liquidation fails if vault is not harvested - function test_liquidateOsToken_notHarvested() public { - _setEthVaultReward(address(vault), 0, 0); - _setEthVaultReward(address(vault), 0, 0); - - _startSnapshotGas('VaultOsTokenTest_test_test_liquidateOsToken_notHarvested'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.liquidateOsToken(1 ether, owner, owner); - _stopSnapshotGas(); - } - - // Test partial liquidation - function test_liquidateOsToken_partialLiquidation() public { - _depositToVault(address(vault), 10 ether, owner, owner); - - vm.prank(owner); - uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); - uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); - - // Get configuration - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - - // Calculate and apply penalty to make position liquidatable - int256 requiredPenalty = int256(vault.totalAssets()) - - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); - requiredPenalty = -requiredPenalty; - - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(requiredPenalty), - 0 - ); - vault.updateState(harvestParams); - - // Record initial position - uint256 initialPosition = vault.osTokenPositions(owner); - - // Prepare for partial liquidation - address liquidator = makeAddr('liquidator'); - uint256 liquidationAmount = osTokenShares / 3; - _mintOsToken(liquidator, liquidationAmount); - - // Expect OsTokenLiquidated event for first liquidation - vm.expectEmit(true, true, false, false); - emit IVaultOsToken.OsTokenLiquidated( - liquidator, // caller - owner, // user - liquidator, // receiver - liquidationAmount, - 0, // shares - we don't know exact value - 0 // receivedAssets - we don't know exact value - ); - - // Perform first liquidation - vm.prank(liquidator); - _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_partialLiquidation'); - vault.liquidateOsToken(liquidationAmount, owner, liquidator); - _stopSnapshotGas(); - - // Verify position is reduced correctly - uint256 positionAfterLiquidation = vault.osTokenPositions(owner); - assertEq( - positionAfterLiquidation, - initialPosition - liquidationAmount, - 'Position should be reduced by liquidation amount' - ); - - // Prepare for second liquidation - uint256 remainingAmount = osTokenShares - liquidationAmount; - _mintOsToken(liquidator, remainingAmount); - - // Expect OsTokenLiquidated event for second liquidation - vm.expectEmit(true, true, false, false); - emit IVaultOsToken.OsTokenLiquidated( - liquidator, // caller - owner, // user - liquidator, // receiver - remainingAmount, - 0, // shares - we don't know exact value - 0 // receivedAssets - we don't know exact value - ); - - // Liquidate remainder and verify position becomes zero - vm.prank(liquidator); - vault.liquidateOsToken(remainingAmount, owner, liquidator); - - assertApproxEqAbs( - vault.osTokenPositions(owner), - 0, - 0.0001 ether, - 'Position should be zero after complete liquidation' - ); - } - - function test_liquidateOsToken_invalidReceivedAssets() public { - _depositToVault(address(vault), 10 ether, owner, owner); - - vm.prank(owner); - uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); - uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); - - // Get vault state and configuration - IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); - int256 requiredPenalty = int256(vault.totalAssets()) - - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); - requiredPenalty = -requiredPenalty; - - // Apply the penalty - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(requiredPenalty), - 0 - ); - vault.updateState(harvestParams); - - // Verify the position is now liquidatable - address liquidator = makeAddr('liquidator'); - _mintOsToken(liquidator, osTokenShares); - - // remove withdrawable assets - vm.deal(address(vault), address(vault).balance - vault.withdrawableAssets()); - - // Perform liquidation - vm.prank(liquidator); - _startSnapshotGas('VaultOsTokenTest_test_liquidateOsToken_invalidReceivedAssets'); - vm.expectRevert(Errors.InvalidReceivedAssets.selector); - vault.liquidateOsToken(osTokenShares, owner, liquidator); - _stopSnapshotGas(); - } - - function test_transferOsTokenPositionToEscrow_basic() public { - vm.prank(_strategiesRegistry.owner()); - _strategiesRegistry.setStrategy(address(this), true); - _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); - - // First mint some osToken shares - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, osTokenShares, referrer); - - // Record initial position - uint256 initialPosition = vault.osTokenPositions(owner); - assertEq(initialPosition, osTokenShares, 'Initial position incorrect'); - - // Transfer osToken position to escrow - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_basic'); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - _stopSnapshotGas(); - - // Verify osToken position is transferred (should be zero) - uint256 afterTransferPosition = vault.osTokenPositions(owner); - assertEq(afterTransferPosition, 0, 'osToken position was not fully transferred'); - - // Verify position in escrow - (address escrowOwner, uint256 exitedAssets, uint256 escrowOsTokenShares) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - assertEq(escrowOwner, owner, 'Incorrect owner in escrow position'); - assertEq(exitedAssets, 0, 'Exited assets should be zero initially'); - assertEq(escrowOsTokenShares, osTokenShares, 'Incorrect osToken shares in escrow'); - - // Update state to process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Ensure enough time has passed for claiming - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Process the exited assets - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process'); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - uint256(vault.getExitQueueIndex(exitPositionTicket)) - ); - _stopSnapshotGas(); - - // Record user's ETH balance before claiming - uint256 ownerBalanceBefore = owner.balance; - - // Claim exited assets - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_claim'); - uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares - ); - _stopSnapshotGas(); - - // Verify assets were received - uint256 ownerBalanceAfter = owner.balance; - assertEq( - ownerBalanceAfter - ownerBalanceBefore, - claimedAssets, - 'Incorrect amount of assets transferred' - ); - assertGt(claimedAssets, 0, 'No assets were claimed'); - } - - function test_transferOsTokenPositionToEscrow_zeroShares() public { - // Mint some osToken shares first - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, osTokenShares, referrer); - - // Try to transfer zero shares - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares'); - vm.expectRevert(Errors.InvalidShares.selector); - vault.transferOsTokenPositionToEscrow(0); - _stopSnapshotGas(); - } - - function test_transferOsTokenPositionToEscrow_moreThanOwned() public { - // Mint some osToken shares first - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, osTokenShares, referrer); - - // Try to transfer more shares than owned - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_moreThanOwned'); - vm.expectRevert(Errors.InvalidShares.selector); - vault.transferOsTokenPositionToEscrow(osTokenShares * 2); - _stopSnapshotGas(); - } - - function test_transferOsTokenPositionToEscrow_notHarvested() public { - // Mint some osToken shares first - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); - vm.prank(owner); - vault.mintOsToken(owner, osTokenShares, referrer); - - // Force vault to need harvesting - _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); - _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); - - vm.warp(vm.getBlockTimestamp() + 1 days); - - // Try to transfer when vault needs harvesting - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.transferOsTokenPositionToEscrow(osTokenShares); - _stopSnapshotGas(); - } - - function test_transferOsTokenPositionToEscrow_noPosition() public { - // Try to transfer with no position - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_noPosition'); - vm.expectRevert(Errors.InvalidPosition.selector); - vault.transferOsTokenPositionToEscrow(1 ether); - _stopSnapshotGas(); - } - - function test_transferOsTokenPositionToEscrow_partialTransfer() public { - vm.prank(_strategiesRegistry.owner()); - _strategiesRegistry.setStrategy(address(this), true); - _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); - - // Mint some osToken shares first - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(2 ether); - vm.prank(owner); - vault.mintOsToken(owner, osTokenShares, referrer); - - // Transfer half of the position - uint256 transferAmount = osTokenShares / 2; - - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer'); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(transferAmount); - _stopSnapshotGas(); - - // Verify remaining position - uint256 remainingPosition = vault.osTokenPositions(owner); - assertEq(remainingPosition, osTokenShares - transferAmount, 'Remaining position incorrect'); - - // Verify position in escrow - (address escrowOwner, , uint256 escrowOsTokenShares) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - - assertEq(escrowOwner, owner, 'Incorrect owner in escrow position'); - assertEq(escrowOsTokenShares, transferAmount, 'Incorrect osToken shares in escrow'); - } - - function test_transferOsTokenPositionToEscrow_maxAmount() public { - vm.prank(_strategiesRegistry.owner()); - _strategiesRegistry.setStrategy(address(this), true); - _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); - - // Mint maximum osToken shares - vm.prank(owner); - vault.mintOsToken(owner, type(uint256).max, referrer); - uint256 mintedShares = vault.osTokenPositions(owner); - - // Transfer all minted shares - vm.prank(owner); - _startSnapshotGas('VaultOsTokenTest_test_transferOsTokenPositionToEscrow_maxAmount'); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(mintedShares); - _stopSnapshotGas(); - - // Verify position in escrow - (address escrowOwner, , uint256 escrowOsTokenShares) = contracts.osTokenVaultEscrow.getPosition( - address(vault), - exitPositionTicket - ); - - assertEq(escrowOwner, owner, 'Incorrect owner in escrow position'); - assertEq(escrowOsTokenShares, mintedShares, 'Incorrect osToken shares in escrow'); - - // Verify position is fully transferred - uint256 remainingPosition = vault.osTokenPositions(owner); - assertEq(remainingPosition, 0, 'Position should be fully transferred'); - } + // Test basic minting functionality + function test_mintOsToken_basic() public { + // Start with clean slate + uint256 initialOsTokenShares = vault.osTokenPositions(owner); + + // Calculate a portion of max mintable amount to use + uint256 osTokenSharesToMint = contracts.osTokenVaultController.convertToShares(1 ether); + + // Expect the OsTokenMinted event to be emitted + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, osTokenSharesToMint, referrer); + + // Mint OsToken + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_basic"); + uint256 assets = vault.mintOsToken(receiver, osTokenSharesToMint, referrer); + _stopSnapshotGas(); + + // Verify minting was successful + assertGt(assets, 0, "Should have minted assets"); + assertEq( + vault.osTokenPositions(owner), + initialOsTokenShares + osTokenSharesToMint, + "Owner's OsToken position should increase" + ); + } + + // Test minting maximum amount using type(uint256).max + function test_mintOsToken_maxAmount() public { + // Start with clean slate + uint256 initialOsTokenShares = vault.osTokenPositions(owner); + + // Expect the OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, 0, referrer); // We don't know exact share amount, just verify caller + + // Mint max OsToken + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_maxAmount"); + uint256 assets = vault.mintOsToken(receiver, type(uint256).max, referrer); + _stopSnapshotGas(); + + // Verify minting was successful and minted the max available + assertGt(assets, 0, "Should have minted assets"); + assertGt(vault.osTokenPositions(owner), initialOsTokenShares, "Owner's OsToken position should increase"); + + // Try minting max again - should mint 0 as already at max + vm.prank(owner); + uint256 assetsRetry = vault.mintOsToken(receiver, type(uint256).max, referrer); + + assertEq(assetsRetry, 0, "Should not mint additional shares when at max"); + } + + // Test LTV validation + function test_mintOsToken_ltvValidation() public { + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate an amount that would exceed LTV + uint256 userAssets = vault.convertToAssets(vault.getShares(owner)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Try to mint slightly more than max allowed + uint256 excessShares = maxOsTokenShares + 1; + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_ltvValidation"); + vm.expectRevert(Errors.LowLtv.selector); + vault.mintOsToken(receiver, excessShares, referrer); + _stopSnapshotGas(); + } + + // Test that entering exit queue fails when it would violate LTV + function test_enterExitQueue_ltvViolation() public { + // First mint maximum OsToken shares + uint256 userShares = vault.getShares(owner); + uint256 userAssets = vault.convertToAssets(userShares); + + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Expect OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, owner, 0, maxOsTokenShares, referrer); + + // Mint maximum OsToken shares + vm.prank(owner); + vault.mintOsToken(owner, maxOsTokenShares, referrer); + + // Now try to enter exit queue with some shares + // Even a small amount should fail because it would reduce collateral and violate LTV + uint256 exitAmount = userShares / 10; // Try to exit 10% of shares + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_enterExitQueue_ltvViolation"); + vm.expectRevert(Errors.LowLtv.selector); + vault.enterExitQueue(exitAmount, owner); + _stopSnapshotGas(); + + // Verify that burning some OsToken shares first would allow entering exit queue + uint128 burnAmount = uint128(maxOsTokenShares / 5); // Burn 20% of OsToken position + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + vault.burnOsToken(burnAmount); + + // Now should be able to enter exit queue + vm.prank(owner); + vault.enterExitQueue(exitAmount, owner); + } + + // Test fee syncing for existing positions + function test_mintOsToken_feeSync() public { + // First mint to create position + uint256 firstMintShares = contracts.osTokenVaultController.convertToShares(1 ether); + + // Expect OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, owner, 0, firstMintShares, referrer); + + vm.prank(owner); + vault.mintOsToken(owner, firstMintShares, referrer); + + // Simulate time passing and reward accumulation to change cumulativeFeePerShare + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + vm.roll(block.number + 1000); + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Update controller state to change cumulativeFeePerShare + vault.updateState(harvestParams); + osTokenVaultController.updateState(); + + // Record position before second mint + uint256 positionBefore = vault.osTokenPositions(owner); + + // Expect OsTokenMinted event for second mint + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, owner, 0, firstMintShares / 2, referrer); + + // Mint more OsToken shares + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_feeSync"); + vault.mintOsToken(owner, firstMintShares / 2, referrer); + _stopSnapshotGas(); + + // Position should increase by more than the mint amount due to fee sync + vm.warp(vm.getBlockTimestamp() + 1 days); + uint256 positionAfter = vault.osTokenPositions(owner); + assertGt( + positionAfter, + positionBefore + firstMintShares / 2, + "Position should increase more than mint amount due to fee sync" + ); + } + + // Test zero shares + function test_mintOsToken_zeroShares() public { + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_zeroShares"); + vm.expectRevert(Errors.InvalidShares.selector); + vault.mintOsToken(receiver, 0, referrer); + _stopSnapshotGas(); + } + + function test_mintOsToken_zeroAddressReceiver() public { + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + + // Try to mint to the zero address + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_zeroAddressReceiver"); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.mintOsToken(address(0), mintAmount, referrer); + _stopSnapshotGas(); + } + + // Test when vault is not collateralized + function test_mintOsToken_notCollateralized() public { + // Create a new vault that is not collateralized + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "test" + }) + ); + address newVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault newVault = EthVault(payable(newVaultAddr)); + + // Deposit to vault + _depositToVault(address(newVault), depositAmount, owner, owner); + + // Try to mint OsToken with uncollateralized vault + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_notCollateralized"); + vm.expectRevert(Errors.NotCollateralized.selector); + newVault.mintOsToken(receiver, mintAmount, referrer); + _stopSnapshotGas(); + } + + // Test when vault is not harvested + function test_mintOsToken_notHarvested() public { + // Set up reward parameters but don't harvest + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + + // Force vault to need harvesting + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Try to mint OsToken when vault needs harvesting + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_notHarvested"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.mintOsToken(receiver, mintAmount, referrer); + _stopSnapshotGas(); + + // Update state and try again - should work + vault.updateState(harvestParams); + + // Expect OsTokenMinted event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenMinted(owner, receiver, 0, mintAmount, referrer); + + vm.prank(owner); + uint256 assets = vault.mintOsToken(receiver, mintAmount, referrer); + assertGt(assets, 0, "Should mint after harvesting"); + } + + // Test repeated minting until max + function test_mintOsToken_repeatedMinting() public { + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate max OsToken shares + uint256 userAssets = vault.convertToAssets(vault.getShares(owner)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Mint in small increments until approaching max + uint256 incrementAmount = maxOsTokenShares / 10; + uint256 totalMinted = 0; + + for (uint256 i = 0; i < 9; i++) { + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_repeatedMinting"); + uint256 assets = vault.mintOsToken(receiver, incrementAmount, referrer); + _stopSnapshotGas(); + + assertGt(assets, 0, "Should be able to mint"); + totalMinted += incrementAmount; + } + + // Try to mint more than remaining max + uint256 remaining = maxOsTokenShares - totalMinted; + vm.prank(owner); + vm.expectRevert(Errors.LowLtv.selector); + vault.mintOsToken(receiver, remaining + 1, referrer); + + // Mint exactly the remaining amount - should succeed + vm.prank(owner); + uint256 finalAssets = vault.mintOsToken(receiver, remaining, referrer); + assertGt(finalAssets, 0, "Should be able to mint exact remaining amount"); + } + + // Test minting to different receivers + function test_mintOsToken_multipleReceivers() public { + address receiver1 = makeAddr("receiver1"); + address receiver2 = makeAddr("receiver2"); + + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + + // Mint to first receiver + vm.prank(owner); + uint256 assets1 = vault.mintOsToken(receiver1, mintAmount, referrer); + assertGt(assets1, 0, "Should mint to first receiver"); + + // Mint to second receiver + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_mintOsToken_multipleReceivers"); + uint256 assets2 = vault.mintOsToken(receiver2, mintAmount, referrer); + _stopSnapshotGas(); + assertGt(assets2, 0, "Should mint to second receiver"); + + // Verify position is tracked against owner regardless of receiver + uint256 ownerPosition = vault.osTokenPositions(owner); + assertEq(ownerPosition, mintAmount * 2, "Owner position should track all minting"); + } + + // Test basic burn functionality + function test_burnOsToken_basic() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Verify initial position + uint256 initialPosition = vault.osTokenPositions(owner); + assertEq(initialPosition, mintAmount, "Initial position should equal minted amount"); + + // Burn a portion of shares + uint128 burnAmount = uint128(mintAmount / 2); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_basic"); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, initialPosition - burnAmount, "Position should be reduced by burn amount"); + + // Verify assets were returned + assertGt(burnedAssets, 0, "Should return positive asset amount"); + } + + // Test burning all shares + function test_burnOsToken_allShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Verify initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Burn all shares + uint128 burnAmount = uint128(initialPosition); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_allShares"); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, 0, "Position should be zero after burning all shares"); + + // Verify assets were returned + assertGt(burnedAssets, 0, "Should return positive asset amount"); + } + + // Test attempting to burn zero shares + function test_burnOsToken_zeroShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to burn zero shares + uint128 burnAmount = 0; + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_zeroShares"); + vm.expectRevert(Errors.InvalidShares.selector); + vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + } + + // Test attempting to burn more shares than owned + function test_burnOsToken_exceedingShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to burn more than owned + uint128 burnAmount = uint128(mintAmount * 2); + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_exceedingShares"); + vm.expectRevert(); // Should revert, possibly with an arithmetic underflow + vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + } + + // Test burning with non-existent position + function test_burnOsToken_invalidPosition() public { + // Use a different address that has no position + address nonPositionHolder = makeAddr("nonPositionHolder"); + + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(nonPositionHolder, mintAmount, referrer); + + uint128 burnAmount = 1000; + vm.prank(nonPositionHolder); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_invalidPosition"); + vm.expectRevert(Errors.InvalidPosition.selector); + vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + } + + // Test burning after fee sync + function test_burnOsToken_afterFeeSync() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Simulate time passing and reward accumulation + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + vm.roll(block.number + 1000); + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Update states to trigger fee sync + vault.updateState(harvestParams); + osTokenVaultController.updateState(); + + // Position should have grown due to fee sync + uint256 positionAfterFeeSync = vault.osTokenPositions(owner); + assertGt(positionAfterFeeSync, initialPosition, "Position should increase after fee sync"); + + // Burn a portion of shares + uint128 burnAmount = uint128(mintAmount / 2); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_afterFeeSync"); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertLt(remainingPosition, positionAfterFeeSync, "Position should decrease after burning"); + assertGt(burnedAssets, 0, "Should return positive asset amount"); + } + + // Test multiple burn operations + function test_burnOsToken_multipleBurns() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(2 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Verify initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Burn in multiple steps + uint128 burnAmount1 = uint128(mintAmount / 4); + uint128 burnAmount2 = uint128(mintAmount / 4); + + // Expect OsTokenBurned event for first burn + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount1); + + // First burn + vm.prank(owner); + uint256 burnedAssets1 = vault.burnOsToken(burnAmount1); + + // Verify position after first burn + uint256 positionAfterFirstBurn = vault.osTokenPositions(owner); + assertEq(positionAfterFirstBurn, initialPosition - burnAmount1, "Position incorrect after first burn"); + + // Expect OsTokenBurned event for second burn + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount2); + + // Second burn + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_multipleBurns"); + uint256 burnedAssets2 = vault.burnOsToken(burnAmount2); + _stopSnapshotGas(); + + // Verify position after second burn + uint256 positionAfterSecondBurn = vault.osTokenPositions(owner); + assertEq( + positionAfterSecondBurn, initialPosition - burnAmount1 - burnAmount2, "Position incorrect after second burn" + ); + + assertGt(burnedAssets1, 0, "First burn should return positive assets"); + assertGt(burnedAssets2, 0, "Second burn should return positive assets"); + } + + // Test that burn succeeds when it would have previously violated LTV + function test_burnOsToken_improvesLTV() public { + // First mint maximum OsToken shares + uint256 userShares = vault.getShares(owner); + uint256 userAssets = vault.convertToAssets(userShares); + + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Mint maximum OsToken shares + vm.prank(owner); + vault.mintOsToken(owner, maxOsTokenShares, referrer); + + // Try to enter exit queue with some shares - should fail due to LTV + uint256 exitAmount = userShares / 10; + vm.prank(owner); + vm.expectRevert(Errors.LowLtv.selector); + vault.enterExitQueue(exitAmount, owner); + + // Now burn some OsToken shares + uint128 burnAmount = uint128(maxOsTokenShares / 5); + + // Expect OsTokenBurned event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenBurned(owner, 0, burnAmount); + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_burnOsToken_improvesLTV"); + uint256 burnedAssets = vault.burnOsToken(burnAmount); + _stopSnapshotGas(); + + assertGt(burnedAssets, 0, "Should return positive asset amount"); + + // Now should be able to enter exit queue + vm.prank(owner); + vault.enterExitQueue(exitAmount, owner); + } + + // Test that only the redeemer can call redeemOsToken + function test_redeemOsToken_onlyRedeemer() public { + // Create a position first + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem as non-redeemer + address nonRedeemer = makeAddr("nonRedeemer"); + vm.prank(nonRedeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_onlyRedeemer"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.redeemOsToken(mintAmount, owner, receiver); + _stopSnapshotGas(); + + // Get current redeemer + address redeemer = osTokenConfig.redeemer(); + vm.prank(redeemer); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + + // Verify position was reduced + assertLt(vault.osTokenPositions(owner), mintAmount, "Position should be reduced after redemption"); + } + + // Test basic redemption functionality + function test_redeemOsToken_basic() public { + // Create a position first + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Initial position + uint256 initialPosition = vault.osTokenPositions(owner); + uint256 initialReceiverBalance = receiver.balance; + + // Get current redeemer and perform redemption + address redeemer = osTokenConfig.redeemer(); + uint256 redeemAmount = mintAmount / 2; + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, redeemAmount, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_basic"); + vault.redeemOsToken(redeemAmount, owner, receiver); + _stopSnapshotGas(); + + // Verify position was updated correctly + uint256 finalPosition = vault.osTokenPositions(owner); + assertEq(finalPosition, initialPosition - redeemAmount, "Position should be reduced by redemption amount"); + + // Verify receiver got the assets + assertGt(receiver.balance, initialReceiverBalance, "Receiver should receive assets"); + } + + // Test redemption with non-existent position + function test_redeemOsToken_nonExistentPosition() public { + // Try to redeem from an address with no position + address noPositionAddr = makeAddr("noPosition"); + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_nonExistentPosition"); + vm.expectRevert(Errors.InvalidPosition.selector); + vault.redeemOsToken(1 ether, noPositionAddr, receiver); + _stopSnapshotGas(); + } + + // Test redemption with insufficient shares + function test_redeemOsToken_insufficientShares() public { + // Create a small position + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem more than available + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_insufficientShares"); + vm.expectRevert(); // Should revert due to arithmetic underflow + vault.redeemOsToken(mintAmount * 2, owner, receiver); + _stopSnapshotGas(); + } + + // Test redemption after fee sync occurs + function test_redeemOsToken_afterFeeSync() public { + // Create a position first + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Simulate time passing and reward accumulation + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + vm.roll(block.number + 1000); + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Update states to trigger fee sync + vault.updateState(harvestParams); + osTokenVaultController.updateState(); + + // Position should have grown due to fee sync + uint256 positionAfterFeeSync = vault.osTokenPositions(owner); + assertGt(positionAfterFeeSync, initialPosition, "Position should increase after fee sync"); + + // Redeem a portion of shares + uint256 redeemAmount = mintAmount / 2; + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, redeemAmount, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_afterFeeSync"); + vault.redeemOsToken(redeemAmount, owner, receiver); + _stopSnapshotGas(); + + // Verify position is updated correctly + uint256 remainingPosition = vault.osTokenPositions(owner); + assertLt(remainingPosition, positionAfterFeeSync, "Position should decrease after redemption"); + } + + // Test redemption with health factor above liquidation threshold + function test_redeemOsToken_goodHealthFactor() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Health factor is good at this point + + // Redemption should work even with good health factor + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount / 2, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_goodHealthFactor"); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + _stopSnapshotGas(); + + // Verify position was updated + assertLt(vault.osTokenPositions(owner), mintAmount, "Position should be reduced after redemption"); + } + + // Test redemption with zero address receiver + function test_redeemOsToken_zeroAddressReceiver() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem to zero address + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_zeroAddressReceiver"); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.redeemOsToken(mintAmount / 2, owner, address(0)); + _stopSnapshotGas(); + } + + // Test redemption with zero shares + function test_redeemOsToken_zeroShares() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Try to redeem zero shares + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_zeroShares"); + vm.expectRevert(); // Will revert but not with Errors.InvalidShares since validation happens at different point + vault.redeemOsToken(0, owner, receiver); + _stopSnapshotGas(); + } + + // Test full redemption of position + function test_redeemOsToken_fullPosition() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Redeem entire position + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_fullPosition"); + vault.redeemOsToken(mintAmount, owner, receiver); + _stopSnapshotGas(); + + // Verify position is zero + uint256 finalPosition = vault.osTokenPositions(owner); + assertEq(finalPosition, 0, "Position should be zero after full redemption"); + } + + // Test redemption after state update + function test_redeemOsToken_afterStateUpdate() public { + // First mint some OsToken shares + uint256 mintAmount = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, mintAmount, referrer); + + // Force state update required + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Vault needs harvesting at this point + assertTrue(contracts.keeper.isHarvestRequired(address(vault)), "Vault should need harvesting"); + + // Try to redeem - should fail due to not harvested + address redeemer = osTokenConfig.redeemer(); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + _stopSnapshotGas(); + + // Update state + vault.updateState(harvestParams); + + // Now redemption should work + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, mintAmount / 2, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success"); + vault.redeemOsToken(mintAmount / 2, owner, receiver); + _stopSnapshotGas(); + + // Verify position was updated + assertLt(vault.osTokenPositions(owner), mintAmount, "Position should be reduced after redemption"); + } + + // Test comparison between liquidation and redemption + function test_redeemVsLiquidate() public { + // First mint maximum OsToken shares + uint256 userShares = vault.getShares(owner); + uint256 userAssets = vault.convertToAssets(userShares); + + // Get LTV percent from config + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + uint256 maxOsTokenAssets = (userAssets * config.ltvPercent) / 1e18; + uint256 maxOsTokenShares = osTokenVaultController.convertToShares(maxOsTokenAssets); + + // Mint maximum OsToken shares + vm.prank(owner); + vault.mintOsToken(owner, maxOsTokenShares, referrer); + + // Enter exit queue with almost all vault shares to create poor health factor + uint256 exitAmount = (userShares * 90) / 100; // Exit 90% of shares + vm.prank(owner); + vm.expectRevert(Errors.LowLtv.selector); // Should fail due to poor health factor + vault.enterExitQueue(exitAmount, owner); + + // Try to liquidate - will fail because health factor not below threshold yet + address liquidator = makeAddr("liquidator"); + vm.prank(liquidator); + vm.expectRevert(Errors.InvalidHealthFactor.selector); + vault.liquidateOsToken(maxOsTokenShares / 2, owner, liquidator); + + // But redeemer can redeem regardless of health factor + address redeemer = osTokenConfig.redeemer(); + + // Expect OsTokenRedeemed event + vm.expectEmit(true, false, false, false); + emit IVaultOsToken.OsTokenRedeemed(redeemer, owner, receiver, maxOsTokenShares / 2, 0, 0); + + vm.prank(redeemer); + _startSnapshotGas("VaultOsTokenTest_test_redeemVsLiquidate"); + vault.redeemOsToken(maxOsTokenShares / 2, owner, receiver); + _stopSnapshotGas(); + + // Verify redemption worked + assertLt(vault.osTokenPositions(owner), maxOsTokenShares, "Position should be reduced after redemption"); + } + + // Test basic liquidation functionality + function test_liquidateOsToken_basic() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get vault state and configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + int256 requiredPenalty = + int256(vault.totalAssets()) - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + // Apply the penalty + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(requiredPenalty), 0); + vault.updateState(harvestParams); + + // Verify the position is now liquidatable + address liquidator = makeAddr("liquidator"); + uint256 liquidatorInitialBalance = liquidator.balance; + _mintOsToken(liquidator, osTokenShares); + + // Expect OsTokenLiquidated event + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + osTokenShares, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Perform liquidation + vm.prank(liquidator); + _startSnapshotGas("VaultOsTokenTest_test_liquidateOsToken_basic"); + vault.liquidateOsToken(osTokenShares, owner, liquidator); + _stopSnapshotGas(); + + // Verify liquidation results + assertApproxEqAbs( + vault.osTokenPositions(owner), 0, 0.0001 ether, "Position should be reduced after liquidation" + ); + assertGt(liquidator.balance, liquidatorInitialBalance, "Liquidator should receive assets"); + } + + // Test liquidation bonus calculation + function test_liquidateOsToken_bonus() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate and apply penalty to make position liquidatable + int256 requiredPenalty = + int256(vault.totalAssets()) - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(requiredPenalty), 0); + vault.updateState(harvestParams); + + // Calculate expected bonus + uint256 liquidationAmount = osTokenShares / 4; + uint256 normalAssets = osTokenVaultController.convertToAssets(liquidationAmount); + uint256 expectedAssets = (normalAssets * config.liqBonusPercent) / 1e18; + + // Prepare liquidator + address liquidator = makeAddr("liquidator"); + uint256 liquidatorInitialBalance = liquidator.balance; + _mintOsToken(liquidator, liquidationAmount); + + // Expect OsTokenLiquidated event + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + liquidationAmount, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Perform liquidation + vm.prank(liquidator); + _startSnapshotGas("VaultOsTokenTest_test_liquidateOsToken_bonus"); + vault.liquidateOsToken(liquidationAmount, owner, liquidator); + _stopSnapshotGas(); + + // Verify liquidator received a bonus + uint256 receivedAssets = liquidator.balance - liquidatorInitialBalance; + assertGt(receivedAssets, normalAssets, "Liquidator should receive bonus"); + + // Check the bonus is approximately as expected (with some tolerance for gas costs) + uint256 tolerance = expectedAssets / 20; // 5% tolerance + assertApproxEqAbs( + receivedAssets, expectedAssets, tolerance, "Received assets should match expected bonus calculation" + ); + } + + // Test that liquidation is disabled when configured + function test_liquidateOsToken_liquidationDisabled() public { + // Create a vault with disabled liquidations + address adminWithDisabledLiq = makeAddr("adminWithDisabledLiq"); + vm.deal(adminWithDisabledLiq, 100 ether); + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "test" + }) + ); + + address vaultAddr = _getOrCreateVault(VaultType.EthVault, adminWithDisabledLiq, initParams, false); + EthVault vaultWithDisabledLiq = EthVault(payable(vaultAddr)); + + // Disable liquidations + vm.startPrank(Ownable(address(osTokenConfig)).owner()); + IOsTokenConfig.Config memory disabledLiqConfig = IOsTokenConfig.Config({ + ltvPercent: 0.9999 ether, + liqThresholdPercent: type(uint64).max, // Disable liquidations + liqBonusPercent: 0 + }); + osTokenConfig.updateConfig(address(vaultWithDisabledLiq), disabledLiqConfig); + vm.stopPrank(); + + // Deposit to vault and collateralize + address vaultOwner = makeAddr("vaultOwner"); + vm.deal(vaultOwner, 100 ether); + _depositToVault(address(vaultWithDisabledLiq), 50 ether, vaultOwner, vaultOwner); + _collateralizeEthVault(address(vaultWithDisabledLiq)); + + // Create a position + vm.prank(vaultOwner); + uint256 osTokenAssets = vaultWithDisabledLiq.mintOsToken(vaultOwner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Apply severe penalty + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vaultWithDisabledLiq), int160(int256(-10 ether)), 0); + vaultWithDisabledLiq.updateState(harvestParams); + + // Prepare liquidator + address liquidator = makeAddr("liquidator"); + uint256 liquidationAmount = osTokenShares / 4; + _mintOsToken(liquidator, liquidationAmount); + + // Try to liquidate - should fail because liquidations are disabled + vm.prank(liquidator); + _startSnapshotGas("VaultOsTokenTest_test_liquidateOsToken_liquidationDisabled"); + vm.expectRevert(Errors.LiquidationDisabled.selector); + vaultWithDisabledLiq.liquidateOsToken(liquidationAmount, vaultOwner, liquidator); + _stopSnapshotGas(); + } + + // Test that liquidation fails if vault is not harvested + function test_liquidateOsToken_notHarvested() public { + _setEthVaultReward(address(vault), 0, 0); + _setEthVaultReward(address(vault), 0, 0); + + _startSnapshotGas("VaultOsTokenTest_test_test_liquidateOsToken_notHarvested"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.liquidateOsToken(1 ether, owner, owner); + _stopSnapshotGas(); + } + + // Test partial liquidation + function test_liquidateOsToken_partialLiquidation() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + + // Calculate and apply penalty to make position liquidatable + int256 requiredPenalty = + int256(vault.totalAssets()) - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(requiredPenalty), 0); + vault.updateState(harvestParams); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + + // Prepare for partial liquidation + address liquidator = makeAddr("liquidator"); + uint256 liquidationAmount = osTokenShares / 3; + _mintOsToken(liquidator, liquidationAmount); + + // Expect OsTokenLiquidated event for first liquidation + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + liquidationAmount, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Perform first liquidation + vm.prank(liquidator); + _startSnapshotGas("VaultOsTokenTest_test_liquidateOsToken_partialLiquidation"); + vault.liquidateOsToken(liquidationAmount, owner, liquidator); + _stopSnapshotGas(); + + // Verify position is reduced correctly + uint256 positionAfterLiquidation = vault.osTokenPositions(owner); + assertEq( + positionAfterLiquidation, + initialPosition - liquidationAmount, + "Position should be reduced by liquidation amount" + ); + + // Prepare for second liquidation + uint256 remainingAmount = osTokenShares - liquidationAmount; + _mintOsToken(liquidator, remainingAmount); + + // Expect OsTokenLiquidated event for second liquidation + vm.expectEmit(true, true, false, false); + emit IVaultOsToken.OsTokenLiquidated( + liquidator, // caller + owner, // user + liquidator, // receiver + remainingAmount, + 0, // shares - we don't know exact value + 0 // receivedAssets - we don't know exact value + ); + + // Liquidate remainder and verify position becomes zero + vm.prank(liquidator); + vault.liquidateOsToken(remainingAmount, owner, liquidator); + + assertApproxEqAbs( + vault.osTokenPositions(owner), 0, 0.0001 ether, "Position should be zero after complete liquidation" + ); + } + + function test_liquidateOsToken_invalidReceivedAssets() public { + _depositToVault(address(vault), 10 ether, owner, owner); + + vm.prank(owner); + uint256 osTokenAssets = vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 osTokenShares = osTokenVaultController.convertToShares(osTokenAssets); + + // Get vault state and configuration + IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(vault)); + int256 requiredPenalty = + int256(vault.totalAssets()) - int256((vault.totalAssets() * config.liqThresholdPercent) / 1e18); + requiredPenalty = -requiredPenalty; + + // Apply the penalty + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(requiredPenalty), 0); + vault.updateState(harvestParams); + + // Verify the position is now liquidatable + address liquidator = makeAddr("liquidator"); + _mintOsToken(liquidator, osTokenShares); + + // remove withdrawable assets + vm.deal(address(vault), address(vault).balance - vault.withdrawableAssets()); + + // Perform liquidation + vm.prank(liquidator); + _startSnapshotGas("VaultOsTokenTest_test_liquidateOsToken_invalidReceivedAssets"); + vm.expectRevert(Errors.InvalidReceivedAssets.selector); + vault.liquidateOsToken(osTokenShares, owner, liquidator); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_basic() public { + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); + + // First mint some osToken shares + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Record initial position + uint256 initialPosition = vault.osTokenPositions(owner); + assertEq(initialPosition, osTokenShares, "Initial position incorrect"); + + // Transfer osToken position to escrow + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_basic"); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + + // Verify osToken position is transferred (should be zero) + uint256 afterTransferPosition = vault.osTokenPositions(owner); + assertEq(afterTransferPosition, 0, "osToken position was not fully transferred"); + + // Verify position in escrow + (address escrowOwner, uint256 exitedAssets, uint256 escrowOsTokenShares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(escrowOwner, owner, "Incorrect owner in escrow position"); + assertEq(exitedAssets, 0, "Exited assets should be zero initially"); + assertEq(escrowOsTokenShares, osTokenShares, "Incorrect osToken shares in escrow"); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Ensure enough time has passed for claiming + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Process the exited assets + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process"); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), exitPositionTicket, timestamp, uint256(vault.getExitQueueIndex(exitPositionTicket)) + ); + _stopSnapshotGas(); + + // Record user's ETH balance before claiming + uint256 ownerBalanceBefore = owner.balance; + + // Claim exited assets + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_claim"); + uint256 claimedAssets = + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, osTokenShares); + _stopSnapshotGas(); + + // Verify assets were received + uint256 ownerBalanceAfter = owner.balance; + assertEq(ownerBalanceAfter - ownerBalanceBefore, claimedAssets, "Incorrect amount of assets transferred"); + assertGt(claimedAssets, 0, "No assets were claimed"); + } + + function test_transferOsTokenPositionToEscrow_zeroShares() public { + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Try to transfer zero shares + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares"); + vm.expectRevert(Errors.InvalidShares.selector); + vault.transferOsTokenPositionToEscrow(0); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_moreThanOwned() public { + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Try to transfer more shares than owned + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_moreThanOwned"); + vm.expectRevert(Errors.InvalidShares.selector); + vault.transferOsTokenPositionToEscrow(osTokenShares * 2); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_notHarvested() public { + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Force vault to need harvesting + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.5 ether)), 0); + + vm.warp(vm.getBlockTimestamp() + 1 days); + + // Try to transfer when vault needs harvesting + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_noPosition() public { + // Try to transfer with no position + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_noPosition"); + vm.expectRevert(Errors.InvalidPosition.selector); + vault.transferOsTokenPositionToEscrow(1 ether); + _stopSnapshotGas(); + } + + function test_transferOsTokenPositionToEscrow_partialTransfer() public { + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); + + // Mint some osToken shares first + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(2 ether); + vm.prank(owner); + vault.mintOsToken(owner, osTokenShares, referrer); + + // Transfer half of the position + uint256 transferAmount = osTokenShares / 2; + + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer"); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(transferAmount); + _stopSnapshotGas(); + + // Verify remaining position + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, osTokenShares - transferAmount, "Remaining position incorrect"); + + // Verify position in escrow + (address escrowOwner,, uint256 escrowOsTokenShares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(escrowOwner, owner, "Incorrect owner in escrow position"); + assertEq(escrowOsTokenShares, transferAmount, "Incorrect osToken shares in escrow"); + } + + function test_transferOsTokenPositionToEscrow_maxAmount() public { + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(owner)), owner); + + // Mint maximum osToken shares + vm.prank(owner); + vault.mintOsToken(owner, type(uint256).max, referrer); + uint256 mintedShares = vault.osTokenPositions(owner); + + // Transfer all minted shares + vm.prank(owner); + _startSnapshotGas("VaultOsTokenTest_test_transferOsTokenPositionToEscrow_maxAmount"); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(mintedShares); + _stopSnapshotGas(); + + // Verify position in escrow + (address escrowOwner,, uint256 escrowOsTokenShares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(escrowOwner, owner, "Incorrect owner in escrow position"); + assertEq(escrowOsTokenShares, mintedShares, "Incorrect osToken shares in escrow"); + + // Verify position is fully transferred + uint256 remainingPosition = vault.osTokenPositions(owner); + assertEq(remainingPosition, 0, "Position should be fully transferred"); + } } diff --git a/test/VaultState.t.sol b/test/VaultState.t.sol index 5cc3f2e2..bad67e44 100644 --- a/test/VaultState.t.sol +++ b/test/VaultState.t.sol @@ -1,552 +1,488 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {IVaultEnterExit} from '../contracts/interfaces/IVaultEnterExit.sol'; -import {IVaultState} from '../contracts/interfaces/IVaultState.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract VaultStateTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - - address public owner; - address public user1; - address public user2; - address public admin; - - uint256 public initialDeposit = 10 ether; - - function setUp() public { - // Set up the test environment - contracts = _activateEthereumFork(); - - // Setup test accounts - owner = makeAddr('owner'); - user1 = makeAddr('user1'); - user2 = makeAddr('user2'); - admin = makeAddr('admin'); - - // Fund accounts - vm.deal(owner, 100 ether); - vm.deal(user1, 100 ether); - vm.deal(user2, 100 ether); - vm.deal(admin, 100 ether); - - // Create a vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ,) = vault - .getExitQueueData(); - vm.deal( - address(vault), - unclaimedAssets + vault.convertToAssets(queuedShares) + totalExitingAssets - ); - - // Initial deposit to the vault - _depositToVault(address(vault), initialDeposit, owner, owner); - - // Collateralize the vault - _collateralizeEthVault(address(vault)); - } - - // Test conversion functions - function test_conversion() public view { - // Test convertToShares() - uint256 assetAmount = 1 ether; - uint256 shares = vault.convertToShares(assetAmount); - assertGt(shares, 0, 'Shares converted from assets should be greater than 0'); - - // Test convertToAssets() - uint256 shareAmount = 1 ether; - uint256 assets = vault.convertToAssets(shareAmount); - assertGt(assets, 0, 'Assets converted from shares should be greater than 0'); - - // Test round-trip conversion - uint256 originalAssets = 2 ether; - uint256 convertedShares = vault.convertToShares(originalAssets); - uint256 convertedBackAssets = vault.convertToAssets(convertedShares); - assertApproxEqAbs( - convertedBackAssets, - originalAssets, - 1, - 'Round-trip conversion should approximately preserve value' - ); - } - - // Test withdrawable assets - function test_withdrawableAssets() public { - // Test withdrawableAssets() before exit queue - uint256 withdrawableBefore = vault.withdrawableAssets(); - - // Enter exit queue with half of owner's shares - uint256 ownerShares = vault.getShares(owner); - uint256 exitShares = ownerShares / 2; - - vm.prank(owner); - vault.enterExitQueue(exitShares, owner); - - // Test withdrawableAssets() after exit queue - uint256 withdrawableAfter = vault.withdrawableAssets(); - uint256 exitingAssets = vault.convertToAssets(exitShares); - assertEq( - withdrawableAfter, - withdrawableBefore - exitingAssets, - 'Exiting assets should reduce withdrawable assets' - ); - } - - // Test state update - function test_stateUpdate() public { - // Force state update required - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - int160(int256(0.1 ether)), - 0 - ); - - // Test isStateUpdateRequired() - bool needsUpdate = contracts.keeper.isHarvestRequired(address(vault)); - assertTrue(needsUpdate, 'Vault should need state update'); - - // Test updateState() - uint256 totalAssetsBefore = vault.totalAssets(); - vault.updateState(harvestParams); - uint256 totalAssetsAfter = vault.totalAssets(); - assertGt( - totalAssetsAfter, - totalAssetsBefore, - 'Total assets should increase after positive reward' - ); - } - - // Test update state called multiple times without new rewards - function test_updateState_multiple_calls() public { - // Apply a reward - int160 rewardAmount = int160(int256(0.5 ether)); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - rewardAmount, - 0 - ); - - // First update - vault.updateState(harvestParams); - uint256 totalAssetsAfterFirstUpdate = vault.totalAssets(); - - // Second update with same params (should be no-op) - vault.updateState(harvestParams); - uint256 totalAssetsAfterSecondUpdate = vault.totalAssets(); - - // Verify assets didn't change after second update - assertEq( - totalAssetsAfterSecondUpdate, - totalAssetsAfterFirstUpdate, - "Assets shouldn't change on second update with same params" - ); - } - - // Test process total assets delta with positive reward - function test_processTotalAssetsDelta_positiveReward() public { - // Apply positive reward - int160 rewardAmount = int160(int256(0.5 ether)); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - rewardAmount, - 0 - ); - - // Get initial values - uint256 initialTotalAssets = vault.totalAssets(); - uint256 initialTotalShares = vault.totalShares(); - address feeRecipient = vault.feeRecipient(); - - // Update state to process reward - vm.expectEmit(true, true, true, false); - emit IVaultState.FeeSharesMinted(feeRecipient, 0, 0); - vault.updateState(harvestParams); - - // Verify total assets increased - uint256 finalTotalAssets = vault.totalAssets(); - assertGt(finalTotalAssets, initialTotalAssets, 'Total assets should increase after reward'); - - // Verify fee recipient received shares - uint256 feeRecipientShares = vault.getShares(feeRecipient); - assertGt(feeRecipientShares, 0, 'Fee recipient should receive shares'); - - // Verify total shares increased - uint256 finalTotalShares = vault.totalShares(); - assertGt(finalTotalShares, initialTotalShares, 'Total shares should increase after reward'); - } - - // Test process total assets delta with negative reward (penalty) - function test_processTotalAssetsDelta_negativeReward() public { - // Apply negative reward (penalty) - int160 penaltyAmount = -int160(int256(0.2 ether)); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - penaltyAmount, - 0 - ); - - // Get initial values - uint256 initialTotalAssets = vault.totalAssets(); - uint256 initialTotalShares = vault.totalShares(); - - // Update state to process penalty - vault.updateState(harvestParams); - - // Verify total assets decreased - uint256 finalTotalAssets = vault.totalAssets(); - assertLt(finalTotalAssets, initialTotalAssets, 'Total assets should decrease after penalty'); - - // Verify total shares remained the same (penalties don't affect shares) - uint256 finalTotalShares = vault.totalShares(); - assertEq( - finalTotalShares, - initialTotalShares, - 'Total shares should remain unchanged after penalty' - ); - } - - // Test penalty handling for exiting assets - function test_exiting_assets_penalty() public { - // Enter exit queue with half of owner's shares - uint256 ownerShares = vault.getShares(owner); - uint256 exitShares = ownerShares / 2; - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); - - vm.prank(owner); - uint256 positionTicket = vault.enterExitQueue(exitShares, owner); - uint256 timestamp = vm.getBlockTimestamp(); - - // Record expected exit assets before penalty - uint256 expectedExitAssets = vault.convertToAssets(exitShares); - - // Apply a penalty - int160 penaltyAmount = -int160(int256(0.2 ether)); - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward( - address(vault), - penaltyAmount, - 0 - ); - - // Update state to process penalty and exit queue - vault.updateState(harvestParams); - - // Fast forward time - vm.warp(vm.getBlockTimestamp() + 1 days + 1); - - // Record owner's balance before claiming - uint256 ownerBalanceBefore = owner.balance; - - // Claim exited assets - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket)); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitedAssetsClaimed(owner, positionTicket, 0, 0); - vm.prank(owner); - vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); - - // Verify the received assets are less than expected due to penalty - uint256 receivedAssets = owner.balance - ownerBalanceBefore; - assertLt( - receivedAssets, - expectedExitAssets, - 'Received assets should be less than expected due to penalty' - ); - } - - // Test exit queue processing - function test_exitQueue() public { - // Enter exit queue with half of owner's shares - uint256 ownerShares = vault.getShares(owner); - uint256 exitShares = ownerShares / 2; - - // Record owner's ETH balance before - uint256 ownerBalanceBefore = owner.balance; - (uint128 queuedSharesBefore, , , ,) = vault.getExitQueueData(); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); - - // Enter exit queue - vm.prank(owner); - uint256 timestamp = vm.getBlockTimestamp(); - uint256 positionTicket = vault.enterExitQueue(exitShares, owner); - - // Verify share reduction - uint256 ownerSharesAfter = vault.getShares(owner); - assertEq( - ownerSharesAfter, - ownerShares - exitShares, - 'Owner shares should be reduced by exit amount' - ); - - // Verify queued shares increased - (uint128 queuedShares, , , ,) = vault.getExitQueueData(); - assertEq( - queuedShares, - queuedSharesBefore + exitShares, - 'Queued shares should match exit amount' - ); - - // Update state to process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - vm.expectEmit(true, true, true, false); - emit IVaultState.CheckpointCreated(0, 0); - vault.updateState(harvestParams); - - // Fast forward time past the claiming delay - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - - // Claim exited assets - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket)); - vm.prank(owner); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitedAssetsClaimed(owner, positionTicket, 0, 0); - vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); - - // Verify owner received assets - uint256 ownerBalanceAfter = owner.balance; - assertGt(ownerBalanceAfter, ownerBalanceBefore, 'Owner should receive assets after claiming'); - } - - // Test minting and burning shares through deposit and exit - function test_mintBurnShares() public { - // Get initial total shares - uint256 initialTotalShares = vault.totalShares(); - - // Deposit more to mint shares - uint256 depositAmount = 5 ether; - _depositToVault(address(vault), depositAmount, user1, user1); - - // Verify total shares increased - uint256 totalSharesAfterMint = vault.totalShares(); - assertGt( - totalSharesAfterMint, - initialTotalShares, - 'Total shares should increase after deposit' - ); - - // Enter exit queue to burn shares - uint256 user1Shares = vault.getShares(user1); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); - - vm.prank(user1); - vault.enterExitQueue(user1Shares, user1); - - // Update state to process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - vm.expectEmit(true, true, true, false); - emit IVaultState.CheckpointCreated(0, 0); - vault.updateState(harvestParams); - - // Verify total shares decreased after exit queue is processed - uint256 totalSharesAfterBurn = vault.totalShares(); - assertLt(totalSharesAfterBurn, totalSharesAfterMint, 'Total shares should decrease after exit'); - } - - // Test handling of multiple exit requests - function test_multipleExitRequests() public { - uint256 totalAssetsBefore = vault.totalAssets(); - - // Multiple users deposit - _depositToVault(address(vault), 5 ether, user1, user1); - _depositToVault(address(vault), 5 ether, user2, user2); - - // Users enter exit queue - uint256 user1Shares = vault.getShares(user1); - uint256 user2Shares = vault.getShares(user2); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); - - vm.prank(user1); - uint256 positionTicket1 = vault.enterExitQueue(user1Shares, user1); - uint256 timestamp1 = vm.getBlockTimestamp(); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitQueueEntered(user2, user2, 0, user2Shares); - - vm.prank(user2); - uint256 positionTicket2 = vault.enterExitQueue(user2Shares, user2); - uint256 timestamp2 = vm.getBlockTimestamp(); - - // Update state to process exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - vm.expectEmit(true, true, true, false); - emit IVaultState.CheckpointCreated(0, 0); - vault.updateState(harvestParams); - - // Fast forward time - vm.warp(vm.getBlockTimestamp() + 1 days + 1); - - // Both users claim exited assets - uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket1)); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitedAssetsClaimed(user1, positionTicket1, 0, 0); - vm.prank(user1); - vault.claimExitedAssets(positionTicket1, timestamp1, exitQueueIndex); - - exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket2)); - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitedAssetsClaimed(user2, positionTicket2, 0, 0); - vm.prank(user2); - vault.claimExitedAssets(positionTicket2, timestamp2, exitQueueIndex); - - // Verify withdrawable assets are restored - assertApproxEqAbs( - vault.totalAssets(), - totalAssetsBefore, - 2, - 'Total assets should be restored after all claims' - ); - } + ForkContracts public contracts; + EthVault public vault; + + address public owner; + address public user1; + address public user2; + address public admin; + + uint256 public initialDeposit = 10 ether; + + function setUp() public { + // Set up the test environment + contracts = _activateEthereumFork(); + + // Setup test accounts + owner = makeAddr("owner"); + user1 = makeAddr("user1"); + user2 = makeAddr("user2"); + admin = makeAddr("admin"); + + // Fund accounts + vm.deal(owner, 100 ether); + vm.deal(user1, 100 ether); + vm.deal(user2, 100 ether); + vm.deal(admin, 100 ether); + + // Create a vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets,,) = vault.getExitQueueData(); + vm.deal(address(vault), unclaimedAssets + vault.convertToAssets(queuedShares) + totalExitingAssets); + + // Initial deposit to the vault + _depositToVault(address(vault), initialDeposit, owner, owner); + + // Collateralize the vault + _collateralizeEthVault(address(vault)); + } + + // Test conversion functions + function test_conversion() public view { + // Test convertToShares() + uint256 assetAmount = 1 ether; + uint256 shares = vault.convertToShares(assetAmount); + assertGt(shares, 0, "Shares converted from assets should be greater than 0"); + + // Test convertToAssets() + uint256 shareAmount = 1 ether; + uint256 assets = vault.convertToAssets(shareAmount); + assertGt(assets, 0, "Assets converted from shares should be greater than 0"); + + // Test round-trip conversion + uint256 originalAssets = 2 ether; + uint256 convertedShares = vault.convertToShares(originalAssets); + uint256 convertedBackAssets = vault.convertToAssets(convertedShares); + assertApproxEqAbs( + convertedBackAssets, originalAssets, 1, "Round-trip conversion should approximately preserve value" + ); + } + + // Test withdrawable assets + function test_withdrawableAssets() public { + // Test withdrawableAssets() before exit queue + uint256 withdrawableBefore = vault.withdrawableAssets(); + + // Enter exit queue with half of owner's shares + uint256 ownerShares = vault.getShares(owner); + uint256 exitShares = ownerShares / 2; + + vm.prank(owner); + vault.enterExitQueue(exitShares, owner); + + // Test withdrawableAssets() after exit queue + uint256 withdrawableAfter = vault.withdrawableAssets(); + uint256 exitingAssets = vault.convertToAssets(exitShares); + assertEq( + withdrawableAfter, withdrawableBefore - exitingAssets, "Exiting assets should reduce withdrawable assets" + ); + } + + // Test state update + function test_stateUpdate() public { + // Force state update required + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + IKeeperRewards.HarvestParams memory harvestParams = + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Test isStateUpdateRequired() + bool needsUpdate = contracts.keeper.isHarvestRequired(address(vault)); + assertTrue(needsUpdate, "Vault should need state update"); + + // Test updateState() + uint256 totalAssetsBefore = vault.totalAssets(); + vault.updateState(harvestParams); + uint256 totalAssetsAfter = vault.totalAssets(); + assertGt(totalAssetsAfter, totalAssetsBefore, "Total assets should increase after positive reward"); + } + + // Test update state called multiple times without new rewards + function test_updateState_multiple_calls() public { + // Apply a reward + int160 rewardAmount = int160(int256(0.5 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), rewardAmount, 0); + + // First update + vault.updateState(harvestParams); + uint256 totalAssetsAfterFirstUpdate = vault.totalAssets(); + + // Second update with same params (should be no-op) + vault.updateState(harvestParams); + uint256 totalAssetsAfterSecondUpdate = vault.totalAssets(); + + // Verify assets didn't change after second update + assertEq( + totalAssetsAfterSecondUpdate, + totalAssetsAfterFirstUpdate, + "Assets shouldn't change on second update with same params" + ); + } + + // Test process total assets delta with positive reward + function test_processTotalAssetsDelta_positiveReward() public { + // Apply positive reward + int160 rewardAmount = int160(int256(0.5 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), rewardAmount, 0); + + // Get initial values + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + address feeRecipient = vault.feeRecipient(); + + // Update state to process reward + vm.expectEmit(true, true, true, false); + emit IVaultState.FeeSharesMinted(feeRecipient, 0, 0); + vault.updateState(harvestParams); + + // Verify total assets increased + uint256 finalTotalAssets = vault.totalAssets(); + assertGt(finalTotalAssets, initialTotalAssets, "Total assets should increase after reward"); + + // Verify fee recipient received shares + uint256 feeRecipientShares = vault.getShares(feeRecipient); + assertGt(feeRecipientShares, 0, "Fee recipient should receive shares"); + + // Verify total shares increased + uint256 finalTotalShares = vault.totalShares(); + assertGt(finalTotalShares, initialTotalShares, "Total shares should increase after reward"); + } + + // Test process total assets delta with negative reward (penalty) + function test_processTotalAssetsDelta_negativeReward() public { + // Apply negative reward (penalty) + int160 penaltyAmount = -int160(int256(0.2 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), penaltyAmount, 0); + + // Get initial values + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + + // Update state to process penalty + vault.updateState(harvestParams); + + // Verify total assets decreased + uint256 finalTotalAssets = vault.totalAssets(); + assertLt(finalTotalAssets, initialTotalAssets, "Total assets should decrease after penalty"); + + // Verify total shares remained the same (penalties don't affect shares) + uint256 finalTotalShares = vault.totalShares(); + assertEq(finalTotalShares, initialTotalShares, "Total shares should remain unchanged after penalty"); + } + + // Test penalty handling for exiting assets + function test_exiting_assets_penalty() public { + // Enter exit queue with half of owner's shares + uint256 ownerShares = vault.getShares(owner); + uint256 exitShares = ownerShares / 2; + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); + + vm.prank(owner); + uint256 positionTicket = vault.enterExitQueue(exitShares, owner); + uint256 timestamp = vm.getBlockTimestamp(); + + // Record expected exit assets before penalty + uint256 expectedExitAssets = vault.convertToAssets(exitShares); + + // Apply a penalty + int160 penaltyAmount = -int160(int256(0.2 ether)); + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), penaltyAmount, 0); + + // Update state to process penalty and exit queue + vault.updateState(harvestParams); + + // Fast forward time + vm.warp(vm.getBlockTimestamp() + 1 days + 1); + + // Record owner's balance before claiming + uint256 ownerBalanceBefore = owner.balance; + + // Claim exited assets + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket)); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(owner, positionTicket, 0, 0); + vm.prank(owner); + vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + + // Verify the received assets are less than expected due to penalty + uint256 receivedAssets = owner.balance - ownerBalanceBefore; + assertLt(receivedAssets, expectedExitAssets, "Received assets should be less than expected due to penalty"); + } + + // Test exit queue processing + function test_exitQueue() public { + // Enter exit queue with half of owner's shares + uint256 ownerShares = vault.getShares(owner); + uint256 exitShares = ownerShares / 2; - // Test entering exit queue when not collateralized - function test_exitQueue_notCollateralized() public { - // Create a new vault that is not collateralized - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'test' - }) - ); - address newVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); - EthVault newVault = EthVault(payable(newVaultAddr)); + // Record owner's ETH balance before + uint256 ownerBalanceBefore = owner.balance; + (uint128 queuedSharesBefore,,,,) = vault.getExitQueueData(); - // Deposit to vault - _depositToVault(address(newVault), 5 ether, user1, user1); + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(owner, owner, 0, exitShares); - // Enter exit queue in non-collateralized vault - uint256 user1Shares = newVault.getShares(user1); + // Enter exit queue + vm.prank(owner); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(exitShares, owner); - uint256 user1BalanceBefore = user1.balance; + // Verify share reduction + uint256 ownerSharesAfter = vault.getShares(owner); + assertEq(ownerSharesAfter, ownerShares - exitShares, "Owner shares should be reduced by exit amount"); - vm.expectEmit(true, true, true, true); - emit IVaultEnterExit.Redeemed(user1, user1, user1Shares, user1Shares); - - vm.prank(user1); - uint256 positionTicket = newVault.enterExitQueue(user1Shares, user1); - - // Verify immediate redemption - uint256 user1BalanceAfter = user1.balance; - assertGt(user1BalanceAfter, user1BalanceBefore, 'User should immediately receive assets'); - assertEq( - positionTicket, - type(uint256).max, - 'Position ticket should be max uint256 for immediate redemption' - ); - } - - // Test update exit queue with no queued shares - function test_updateExitQueue_noQueuedShares() public { - // No one has entered exit queue - - // Update state - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Should not revert and should be a no-op - vault.updateState(harvestParams); - } - - // Test an exit position processed across multiple checkpoints - function test_exitQueue_multipleCheckpoints() public { - // Step 1: User deposits a large amount - _depositToVault(address(vault), 20 ether, user1, user1); - - // Step 2: User enters exit queue with all shares - uint256 user1Shares = vault.getShares(user1); - - (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, ,) = vault - .getExitQueueData(); - uint256 vaultBalance = totalExitingAssets + - vault.convertToAssets(queuedShares) + - unclaimedAssets; - - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); - - vm.prank(user1); - uint256 positionTicket = vault.enterExitQueue(user1Shares, user1); - uint256 timestamp = vm.getBlockTimestamp(); - - // Step 3: Artificially limit vault assets by moving ETH out - uint256 exitAssetsNeeded = vault.convertToAssets(user1Shares); - - // Move ETH out to simulate limited availability (leave only 30% of what's needed) - uint256 partialAmount = (exitAssetsNeeded * 30) / 100; - vm.deal(address(vault), vaultBalance + partialAmount); - - // Step 4: Process first checkpoint with limited assets - IKeeperRewards.HarvestParams memory harvestParams1 = _setEthVaultReward(address(vault), 0, 0); - - vm.expectEmit(true, true, true, false); - emit IVaultState.CheckpointCreated(0, 0); - - vault.updateState(harvestParams1); - - // Step 5: Restore full assets for second checkpoint - vm.deal(address(vault), vaultBalance + exitAssetsNeeded); - - // Step 6: Process second checkpoint - IKeeperRewards.HarvestParams memory harvestParams2 = _setEthVaultReward(address(vault), 0, 0); - - vm.expectEmit(true, true, true, false); - emit IVaultState.CheckpointCreated(0, 0); - vault.updateState(harvestParams2); - - // Step 7: Fast forward time past the claiming delay - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - - // Step 8: Claim exited assets - uint256 user1BalanceBefore = user1.balance; - - // Get the exit queue index - int256 exitQueueIndexInt = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndexInt, -1, 'Exit queue index should be valid'); - uint256 exitQueueIndex = uint256(exitQueueIndexInt); + // Verify queued shares increased + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + assertEq(queuedShares, queuedSharesBefore + exitShares, "Queued shares should match exit amount"); - vm.expectEmit(true, true, true, false); - emit IVaultEnterExit.ExitedAssetsClaimed(user1, positionTicket, 0, exitAssetsNeeded); + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - vm.prank(user1); - vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams); - // Step 9: Verify user received all expected assets despite multiple checkpoints - uint256 user1BalanceAfter = user1.balance; - uint256 receivedAssets = user1BalanceAfter - user1BalanceBefore; + // Fast forward time past the claiming delay + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - // The user should receive approximately what they put in, minor differences due to fees/rounding - assertApproxEqRel( - receivedAssets, - exitAssetsNeeded, - 0.01e18, // 1% tolerance - 'User should receive all expected assets across multiple checkpoints' - ); - } + // Claim exited assets + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket)); + vm.prank(owner); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(owner, positionTicket, 0, 0); + vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + + // Verify owner received assets + uint256 ownerBalanceAfter = owner.balance; + assertGt(ownerBalanceAfter, ownerBalanceBefore, "Owner should receive assets after claiming"); + } + + // Test minting and burning shares through deposit and exit + function test_mintBurnShares() public { + // Get initial total shares + uint256 initialTotalShares = vault.totalShares(); + + // Deposit more to mint shares + uint256 depositAmount = 5 ether; + _depositToVault(address(vault), depositAmount, user1, user1); + + // Verify total shares increased + uint256 totalSharesAfterMint = vault.totalShares(); + assertGt(totalSharesAfterMint, initialTotalShares, "Total shares should increase after deposit"); + + // Enter exit queue to burn shares + uint256 user1Shares = vault.getShares(user1); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); + + vm.prank(user1); + vault.enterExitQueue(user1Shares, user1); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams); + + // Verify total shares decreased after exit queue is processed + uint256 totalSharesAfterBurn = vault.totalShares(); + assertLt(totalSharesAfterBurn, totalSharesAfterMint, "Total shares should decrease after exit"); + } + + // Test handling of multiple exit requests + function test_multipleExitRequests() public { + uint256 totalAssetsBefore = vault.totalAssets(); + + // Multiple users deposit + _depositToVault(address(vault), 5 ether, user1, user1); + _depositToVault(address(vault), 5 ether, user2, user2); + + // Users enter exit queue + uint256 user1Shares = vault.getShares(user1); + uint256 user2Shares = vault.getShares(user2); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); + + vm.prank(user1); + uint256 positionTicket1 = vault.enterExitQueue(user1Shares, user1); + uint256 timestamp1 = vm.getBlockTimestamp(); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user2, user2, 0, user2Shares); + + vm.prank(user2); + uint256 positionTicket2 = vault.enterExitQueue(user2Shares, user2); + uint256 timestamp2 = vm.getBlockTimestamp(); + + // Update state to process exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams); + + // Fast forward time + vm.warp(vm.getBlockTimestamp() + 1 days + 1); + + // Both users claim exited assets + uint256 exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket1)); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(user1, positionTicket1, 0, 0); + vm.prank(user1); + vault.claimExitedAssets(positionTicket1, timestamp1, exitQueueIndex); + + exitQueueIndex = uint256(vault.getExitQueueIndex(positionTicket2)); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(user2, positionTicket2, 0, 0); + vm.prank(user2); + vault.claimExitedAssets(positionTicket2, timestamp2, exitQueueIndex); + + // Verify withdrawable assets are restored + assertApproxEqAbs(vault.totalAssets(), totalAssetsBefore, 2, "Total assets should be restored after all claims"); + } + + // Test entering exit queue when not collateralized + function test_exitQueue_notCollateralized() public { + // Create a new vault that is not collateralized + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "test" + }) + ); + address newVaultAddr = _createVault(VaultType.EthVault, admin, initParams, false); + EthVault newVault = EthVault(payable(newVaultAddr)); + + // Deposit to vault + _depositToVault(address(newVault), 5 ether, user1, user1); + + // Enter exit queue in non-collateralized vault + uint256 user1Shares = newVault.getShares(user1); + + uint256 user1BalanceBefore = user1.balance; + + vm.expectEmit(true, true, true, true); + emit IVaultEnterExit.Redeemed(user1, user1, user1Shares, user1Shares); + + vm.prank(user1); + uint256 positionTicket = newVault.enterExitQueue(user1Shares, user1); + + // Verify immediate redemption + uint256 user1BalanceAfter = user1.balance; + assertGt(user1BalanceAfter, user1BalanceBefore, "User should immediately receive assets"); + assertEq(positionTicket, type(uint256).max, "Position ticket should be max uint256 for immediate redemption"); + } + + // Test update exit queue with no queued shares + function test_updateExitQueue_noQueuedShares() public { + // No one has entered exit queue + + // Update state + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Should not revert and should be a no-op + vault.updateState(harvestParams); + } + + // Test an exit position processed across multiple checkpoints + function test_exitQueue_multipleCheckpoints() public { + // Step 1: User deposits a large amount + _depositToVault(address(vault), 20 ether, user1, user1); + + // Step 2: User enters exit queue with all shares + uint256 user1Shares = vault.getShares(user1); + + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets,,) = vault.getExitQueueData(); + uint256 vaultBalance = totalExitingAssets + vault.convertToAssets(queuedShares) + unclaimedAssets; + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitQueueEntered(user1, user1, 0, user1Shares); + + vm.prank(user1); + uint256 positionTicket = vault.enterExitQueue(user1Shares, user1); + uint256 timestamp = vm.getBlockTimestamp(); + + // Step 3: Artificially limit vault assets by moving ETH out + uint256 exitAssetsNeeded = vault.convertToAssets(user1Shares); + + // Move ETH out to simulate limited availability (leave only 30% of what's needed) + uint256 partialAmount = (exitAssetsNeeded * 30) / 100; + vm.deal(address(vault), vaultBalance + partialAmount); + + // Step 4: Process first checkpoint with limited assets + IKeeperRewards.HarvestParams memory harvestParams1 = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + + vault.updateState(harvestParams1); + + // Step 5: Restore full assets for second checkpoint + vm.deal(address(vault), vaultBalance + exitAssetsNeeded); + + // Step 6: Process second checkpoint + IKeeperRewards.HarvestParams memory harvestParams2 = _setEthVaultReward(address(vault), 0, 0); + + vm.expectEmit(true, true, true, false); + emit IVaultState.CheckpointCreated(0, 0); + vault.updateState(harvestParams2); + + // Step 7: Fast forward time past the claiming delay + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Step 8: Claim exited assets + uint256 user1BalanceBefore = user1.balance; + + // Get the exit queue index + int256 exitQueueIndexInt = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndexInt, -1, "Exit queue index should be valid"); + uint256 exitQueueIndex = uint256(exitQueueIndexInt); + + vm.expectEmit(true, true, true, false); + emit IVaultEnterExit.ExitedAssetsClaimed(user1, positionTicket, 0, exitAssetsNeeded); + + vm.prank(user1); + vault.claimExitedAssets(positionTicket, timestamp, exitQueueIndex); + + // Step 9: Verify user received all expected assets despite multiple checkpoints + uint256 user1BalanceAfter = user1.balance; + uint256 receivedAssets = user1BalanceAfter - user1BalanceBefore; + + // The user should receive approximately what they put in, minor differences due to fees/rounding + assertApproxEqRel( + receivedAssets, + exitAssetsNeeded, + 0.01e18, // 1% tolerance + "User should receive all expected assets across multiple checkpoints" + ); + } } diff --git a/test/VaultToken.t.sol b/test/VaultToken.t.sol index 2d011022..29b5794e 100644 --- a/test/VaultToken.t.sol +++ b/test/VaultToken.t.sol @@ -1,636 +1,602 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IKeeperRewards} from '../contracts/interfaces/IKeeperRewards.sol'; -import {IEthErc20Vault} from '../contracts/interfaces/IEthErc20Vault.sol'; -import {EthErc20Vault} from '../contracts/vaults/ethereum/EthErc20Vault.sol'; -import {EthVaultFactory} from '../contracts/vaults/ethereum/EthVaultFactory.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; +import {EthErc20Vault} from "../contracts/vaults/ethereum/EthErc20Vault.sol"; +import {EthVaultFactory} from "../contracts/vaults/ethereum/EthVaultFactory.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; contract VaultTokenTest is Test, EthHelpers { - ForkContracts public contracts; - EthErc20Vault public vault; - - address public owner; - address public user1; - address public user2; - address public admin; - - uint256 public depositAmount = 5 ether; - - function setUp() public { - // Set up the test environment - contracts = _activateEthereumFork(); - - // Setup test accounts - owner = makeAddr('owner'); - user1 = makeAddr('user1'); - user2 = makeAddr('user2'); - admin = makeAddr('admin'); - - // Fund accounts - vm.deal(owner, 100 ether); - vm.deal(user1, 100 ether); - vm.deal(user2, 100 ether); - vm.deal(admin, 100 ether); - - // Create an EthErc20Vault which implements VaultToken module - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); - vault = EthErc20Vault(payable(vaultAddr)); - - // Initial deposit to the vault - _depositToVault(address(vault), depositAmount, owner, owner); - - // Collateralize the vault - _collateralizeEthVault(address(vault)); - } - - // Test basic metadata like name, symbol, decimals - function test_tokenMetadata() public { - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - name: 'SW ETH Vault', - symbol: 'SW-ETH-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createVault(VaultType.EthErc20Vault, admin, initParams, false); - vault = EthErc20Vault(payable(vaultAddr)); - assertEq(vault.name(), 'SW ETH Vault', 'Name should match initialization parameters'); - assertEq(vault.symbol(), 'SW-ETH-1', 'Symbol should match initialization parameters'); - assertEq(vault.decimals(), 18, 'Decimals should be 18'); - } - - // Test totalSupply and balanceOf functions - function test_totalSupplyAndBalanceOf() public { - // Initial values - uint256 initialTotalSupply = vault.totalSupply(); - uint256 initialBalance = vault.balanceOf(owner); - - // Should have positive values after initial deposit - assertGt(initialTotalSupply, 0, 'Total supply should be greater than 0'); - assertGt(initialBalance, 0, 'Owner balance should be greater than 0'); - - // Make another deposit to increase supply - _depositToVault(address(vault), depositAmount, user1, user1); - - // Verify total supply increased - uint256 newTotalSupply = vault.totalSupply(); - assertGt(newTotalSupply, initialTotalSupply, 'Total supply should increase after deposit'); - - // Verify user1's balance - uint256 user1Balance = vault.balanceOf(user1); - assertGt(user1Balance, 0, 'User1 balance should be greater than 0'); - } - - // Test transfer function - function test_transfer() public { - // Get initial balances - uint256 ownerInitialBalance = vault.balanceOf(owner); - uint256 user1InitialBalance = vault.balanceOf(user1); - - // Transfer some tokens from owner to user1 - uint256 transferAmount = ownerInitialBalance / 2; - - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_transfer'); - bool success = vault.transfer(user1, transferAmount); - _stopSnapshotGas(); - - assertTrue(success, 'Transfer should succeed'); - - // Verify balances after transfer - uint256 ownerFinalBalance = vault.balanceOf(owner); - uint256 user1FinalBalance = vault.balanceOf(user1); - - assertEq( - ownerFinalBalance, - ownerInitialBalance - transferAmount, - 'Owner balance should decrease' - ); - assertEq( - user1FinalBalance, - user1InitialBalance + transferAmount, - 'User1 balance should increase' - ); - } - - // Test transferFrom function - function test_transferFrom() public { - // Get initial balances - uint256 ownerInitialBalance = vault.balanceOf(owner); - uint256 user1InitialBalance = vault.balanceOf(user1); - - // Approve user1 to spend owner's tokens - uint256 approvalAmount = ownerInitialBalance / 2; - - vm.prank(owner); - vault.approve(user1, approvalAmount); - - // Check allowance - assertEq(vault.allowance(owner, user1), approvalAmount, 'Allowance should be set correctly'); - - // User1 transfers tokens from owner to themselves - vm.prank(user1); - _startSnapshotGas('VaultTokenTest_test_transferFrom'); - bool success = vault.transferFrom(owner, user1, approvalAmount); - _stopSnapshotGas(); - - assertTrue(success, 'TransferFrom should succeed'); - - // Verify balances after transfer - uint256 ownerFinalBalance = vault.balanceOf(owner); - uint256 user1FinalBalance = vault.balanceOf(user1); - - assertEq( - ownerFinalBalance, - ownerInitialBalance - approvalAmount, - 'Owner balance should decrease' - ); - assertEq( - user1FinalBalance, - user1InitialBalance + approvalAmount, - 'User1 balance should increase' - ); - - // Verify allowance was reduced - assertEq(vault.allowance(owner, user1), 0, 'Allowance should be reduced'); - } - - // Test approve function - function test_approve() public { - // Initial allowance should be 0 - assertEq(vault.allowance(owner, user1), 0, 'Initial allowance should be 0'); - - // Approve user1 to spend owner's tokens - uint256 approvalAmount = 100 ether; - - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_approve'); - bool success = vault.approve(user1, approvalAmount); - _stopSnapshotGas(); - - assertTrue(success, 'Approve should succeed'); - - // Verify allowance - assertEq(vault.allowance(owner, user1), approvalAmount, 'Allowance should be set correctly'); - - // Change approval - uint256 newApprovalAmount = 50 ether; - - vm.prank(owner); - success = vault.approve(user1, newApprovalAmount); - - assertTrue(success, 'Approve should succeed'); - - // Verify new allowance - assertEq(vault.allowance(owner, user1), newApprovalAmount, 'Allowance should be updated'); - } - - // Test unlimited allowance (MAX_UINT256) - function test_unlimitedAllowance() public { - // Approve user1 to spend unlimited tokens - uint256 maxUint = type(uint256).max; - - vm.prank(owner); - vault.approve(user1, maxUint); - - // Verify allowance - assertEq(vault.allowance(owner, user1), maxUint, 'Allowance should be set to max'); - - // Get initial balances - uint256 ownerInitialBalance = vault.balanceOf(owner); - uint256 user1InitialBalance = vault.balanceOf(user1); - - // Transfer some tokens - uint256 transferAmount = ownerInitialBalance / 2; - - vm.prank(user1); - _startSnapshotGas('VaultTokenTest_test_unlimitedAllowance'); - vault.transferFrom(owner, user1, transferAmount); - _stopSnapshotGas(); - - // Verify allowance remains unchanged with unlimited approval - assertEq(vault.allowance(owner, user1), maxUint, 'Allowance should remain unchanged'); - - // Verify balances after transfer - uint256 ownerFinalBalance = vault.balanceOf(owner); - uint256 user1FinalBalance = vault.balanceOf(user1); - - assertEq( - ownerFinalBalance, - ownerInitialBalance - transferAmount, - 'Owner balance should decrease' - ); - assertEq( - user1FinalBalance, - user1InitialBalance + transferAmount, - 'User1 balance should increase' - ); - } - - // Test transfer to zero address - function test_transferToZeroAddress() public { - // Try to transfer to zero address - uint256 transferAmount = vault.balanceOf(owner) / 2; - - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_transferToZeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.transfer(address(0), transferAmount); - _stopSnapshotGas(); - } - - // Test transfer from zero address - function test_transferFromZeroAddress() public { - // Try to transfer from zero address (should be unreachable in practice) - uint256 transferAmount = 1 ether; - - // When transferring from address(0), the function will revert with an arithmetic error - // when checking allowances before it even gets to the zero address check - _startSnapshotGas('VaultTokenTest_test_transferFromZeroAddress'); - vm.expectRevert(); // Expect any revert, which will be an arithmetic underflow - vault.transferFrom(address(0), user1, transferAmount); - _stopSnapshotGas(); - } - - // Test approve zero address - function test_approveZeroAddress() public { - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_approveZeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.approve(address(0), 1 ether); - _stopSnapshotGas(); - } - - // Test transfer more than balance - function test_transferMoreThanBalance() public { - uint256 ownerBalance = vault.balanceOf(owner); - - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_transferMoreThanBalance'); - vm.expectRevert(); // Should revert with arithmetic underflow - vault.transfer(user1, ownerBalance + 1); - _stopSnapshotGas(); - } - - // Test transferFrom more than balance - function test_transferFromMoreThanBalance() public { - uint256 ownerBalance = vault.balanceOf(owner); - - // Approve user1 to spend more than owner's balance - vm.prank(owner); - vault.approve(user1, ownerBalance * 2); - - vm.prank(user1); - _startSnapshotGas('VaultTokenTest_test_transferFromMoreThanBalance'); - vm.expectRevert(); // Should revert with arithmetic underflow - vault.transferFrom(owner, user1, ownerBalance + 1); - _stopSnapshotGas(); - } - - // Test transferFrom more than allowance - function test_transferFromMoreThanAllowance() public { - uint256 ownerBalance = vault.balanceOf(owner); - uint256 allowanceAmount = ownerBalance / 2; - - // Approve user1 to spend half of owner's balance - vm.prank(owner); - vault.approve(user1, allowanceAmount); - - vm.prank(user1); - _startSnapshotGas('VaultTokenTest_test_transferFromMoreThanAllowance'); - vm.expectRevert(); // Should revert with arithmetic underflow - vault.transferFrom(owner, user1, allowanceAmount + 1); - _stopSnapshotGas(); - } - - // Test enterExitQueue emits Transfer event - function test_enterExitQueueEmitsTransferEvent() public { - uint256 exitShares = vault.balanceOf(owner) / 2; - - // Expect a Transfer event from owner to vault - vm.expectEmit(true, true, true, true); - emit IERC20.Transfer(owner, address(vault), exitShares); - - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_enterExitQueueEmitsTransferEvent'); - vault.enterExitQueue(exitShares, owner); - _stopSnapshotGas(); - } - - // Test vault transfers shares to vault when entering exit queue - function test_enterExitQueueTransfersToVault() public { - uint256 ownerInitialBalance = vault.balanceOf(owner); - uint256 exitShares = ownerInitialBalance / 2; - - vm.prank(owner); - vault.enterExitQueue(exitShares, owner); - - // Verify owner's balance decreased - uint256 ownerFinalBalance = vault.balanceOf(owner); - assertEq(ownerFinalBalance, ownerInitialBalance - exitShares, 'Owner balance should decrease'); - - // Verify queued shares - (uint128 queuedShares, , , ,) = vault.getExitQueueData(); - assertEq(queuedShares, exitShares, 'Queued shares should match exit amount'); - } - - // Test _updateExitQueue burns shares and emits Transfer - function test_updateExitQueueBurnsShares() public { - // First, enter exit queue - uint256 exitShares = vault.balanceOf(owner) / 2; - - vm.prank(owner); - vault.enterExitQueue(exitShares, owner); - - // Record total supply before update - uint256 totalSupplyBefore = vault.totalSupply(); - - // Set up reward parameters - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); - - // Expect a Transfer event to zero address for burned shares - vm.expectEmit(true, true, true, false); - emit IERC20.Transfer(address(vault), address(0), exitShares); - - // Update state to process exit queue - _startSnapshotGas('VaultTokenTest_test_updateExitQueueBurnsShares'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify total supply decreased - uint256 totalSupplyAfter = vault.totalSupply(); - assertLt(totalSupplyAfter, totalSupplyBefore, 'Total supply should decrease'); - assertApproxEqAbs( - totalSupplyBefore - totalSupplyAfter, - exitShares, - 2, // small tolerance for rounding - 'Decrease should match exit shares' - ); - } - - // Test transfers are blocked for osToken positions - function test_transferWithOsTokenPosition() public { - // First mint osToken to create a position - vm.prank(owner); - vault.mintOsToken(owner, type(uint256).max, address(0)); - - // Try to transfer more shares than allowed by LTV - uint256 transferAmount = vault.balanceOf(owner) / 2; - - vm.prank(owner); - _startSnapshotGas('VaultTokenTest_test_transferWithOsTokenPosition'); - vm.expectRevert(Errors.LowLtv.selector); - vault.transfer(user1, transferAmount); - _stopSnapshotGas(); - } - - // Test mint shares emits Transfer event - function test_depositEmitsTransferEvent() public { - // Expect Transfer event from zero address to user1 - uint256 depositTokens = 2 ether; - uint256 expectedShares = vault.convertToShares(depositTokens); - - vm.expectEmit(true, true, true, false); - emit IERC20.Transfer(address(0), user1, expectedShares); - - _startSnapshotGas('VaultTokenTest_test_depositEmitsTransferEvent'); - _depositToVault(address(vault), depositTokens, user1, user1); - _stopSnapshotGas(); - } - - // Test permit functionality (ERC-20 permit) - function test_permit() public { - uint256 privateKey = 0x1234; // Demo private key (never use in production) - address signer = vm.addr(privateKey); - - // Fund signer and make a deposit - vm.deal(signer, 5 ether); - _depositToVault(address(vault), 2 ether, signer, signer); - - // Get current nonce - uint256 nonce = vault.nonces(signer); - assertEq(nonce, 0, 'Initial nonce should be 0'); - - // Create permit parameters - uint256 permitAmount = 1 ether; - uint256 deadline = block.timestamp + 1 days; - - // Create signature - bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); - - bytes32 permitTypehash = keccak256( - 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' - ); - - bytes32 structHash = keccak256( - abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline) - ); - - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); - - // Execute permit - _startSnapshotGas('VaultTokenTest_test_permit'); - vault.permit(signer, user1, permitAmount, deadline, v, r, s); - _stopSnapshotGas(); - - // Verify allowance was set - assertEq(vault.allowance(signer, user1), permitAmount, 'Allowance should be set by permit'); + ForkContracts public contracts; + EthErc20Vault public vault; + + address public owner; + address public user1; + address public user2; + address public admin; + + uint256 public depositAmount = 5 ether; + + function setUp() public { + // Set up the test environment + contracts = _activateEthereumFork(); + + // Setup test accounts + owner = makeAddr("owner"); + user1 = makeAddr("user1"); + user2 = makeAddr("user2"); + admin = makeAddr("admin"); + + // Fund accounts + vm.deal(owner, 100 ether); + vm.deal(user1, 100 ether); + vm.deal(user2, 100 ether); + vm.deal(admin, 100 ether); + + // Create an EthErc20Vault which implements VaultToken module + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(vaultAddr)); + + // Initial deposit to the vault + _depositToVault(address(vault), depositAmount, owner, owner); + + // Collateralize the vault + _collateralizeEthVault(address(vault)); + } + + // Test basic metadata like name, symbol, decimals + function test_tokenMetadata() public { + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: "SW ETH Vault", + symbol: "SW-ETH-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.EthErc20Vault, admin, initParams, false); + vault = EthErc20Vault(payable(vaultAddr)); + assertEq(vault.name(), "SW ETH Vault", "Name should match initialization parameters"); + assertEq(vault.symbol(), "SW-ETH-1", "Symbol should match initialization parameters"); + assertEq(vault.decimals(), 18, "Decimals should be 18"); + } + + // Test totalSupply and balanceOf functions + function test_totalSupplyAndBalanceOf() public { + // Initial values + uint256 initialTotalSupply = vault.totalSupply(); + uint256 initialBalance = vault.balanceOf(owner); + + // Should have positive values after initial deposit + assertGt(initialTotalSupply, 0, "Total supply should be greater than 0"); + assertGt(initialBalance, 0, "Owner balance should be greater than 0"); + + // Make another deposit to increase supply + _depositToVault(address(vault), depositAmount, user1, user1); + + // Verify total supply increased + uint256 newTotalSupply = vault.totalSupply(); + assertGt(newTotalSupply, initialTotalSupply, "Total supply should increase after deposit"); + + // Verify user1's balance + uint256 user1Balance = vault.balanceOf(user1); + assertGt(user1Balance, 0, "User1 balance should be greater than 0"); + } + + // Test transfer function + function test_transfer() public { + // Get initial balances + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 user1InitialBalance = vault.balanceOf(user1); + + // Transfer some tokens from owner to user1 + uint256 transferAmount = ownerInitialBalance / 2; + + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_transfer"); + bool success = vault.transfer(user1, transferAmount); + _stopSnapshotGas(); + + assertTrue(success, "Transfer should succeed"); + + // Verify balances after transfer + uint256 ownerFinalBalance = vault.balanceOf(owner); + uint256 user1FinalBalance = vault.balanceOf(user1); + + assertEq(ownerFinalBalance, ownerInitialBalance - transferAmount, "Owner balance should decrease"); + assertEq(user1FinalBalance, user1InitialBalance + transferAmount, "User1 balance should increase"); + } + + // Test transferFrom function + function test_transferFrom() public { + // Get initial balances + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 user1InitialBalance = vault.balanceOf(user1); + + // Approve user1 to spend owner's tokens + uint256 approvalAmount = ownerInitialBalance / 2; + + vm.prank(owner); + vault.approve(user1, approvalAmount); + + // Check allowance + assertEq(vault.allowance(owner, user1), approvalAmount, "Allowance should be set correctly"); + + // User1 transfers tokens from owner to themselves + vm.prank(user1); + _startSnapshotGas("VaultTokenTest_test_transferFrom"); + bool success = vault.transferFrom(owner, user1, approvalAmount); + _stopSnapshotGas(); + + assertTrue(success, "TransferFrom should succeed"); + + // Verify balances after transfer + uint256 ownerFinalBalance = vault.balanceOf(owner); + uint256 user1FinalBalance = vault.balanceOf(user1); + + assertEq(ownerFinalBalance, ownerInitialBalance - approvalAmount, "Owner balance should decrease"); + assertEq(user1FinalBalance, user1InitialBalance + approvalAmount, "User1 balance should increase"); + + // Verify allowance was reduced + assertEq(vault.allowance(owner, user1), 0, "Allowance should be reduced"); + } + + // Test approve function + function test_approve() public { + // Initial allowance should be 0 + assertEq(vault.allowance(owner, user1), 0, "Initial allowance should be 0"); + + // Approve user1 to spend owner's tokens + uint256 approvalAmount = 100 ether; + + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_approve"); + bool success = vault.approve(user1, approvalAmount); + _stopSnapshotGas(); + + assertTrue(success, "Approve should succeed"); + + // Verify allowance + assertEq(vault.allowance(owner, user1), approvalAmount, "Allowance should be set correctly"); + + // Change approval + uint256 newApprovalAmount = 50 ether; + + vm.prank(owner); + success = vault.approve(user1, newApprovalAmount); + + assertTrue(success, "Approve should succeed"); + + // Verify new allowance + assertEq(vault.allowance(owner, user1), newApprovalAmount, "Allowance should be updated"); + } + + // Test unlimited allowance (MAX_UINT256) + function test_unlimitedAllowance() public { + // Approve user1 to spend unlimited tokens + uint256 maxUint = type(uint256).max; + + vm.prank(owner); + vault.approve(user1, maxUint); + + // Verify allowance + assertEq(vault.allowance(owner, user1), maxUint, "Allowance should be set to max"); + + // Get initial balances + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 user1InitialBalance = vault.balanceOf(user1); + + // Transfer some tokens + uint256 transferAmount = ownerInitialBalance / 2; + + vm.prank(user1); + _startSnapshotGas("VaultTokenTest_test_unlimitedAllowance"); + vault.transferFrom(owner, user1, transferAmount); + _stopSnapshotGas(); + + // Verify allowance remains unchanged with unlimited approval + assertEq(vault.allowance(owner, user1), maxUint, "Allowance should remain unchanged"); + + // Verify balances after transfer + uint256 ownerFinalBalance = vault.balanceOf(owner); + uint256 user1FinalBalance = vault.balanceOf(user1); + + assertEq(ownerFinalBalance, ownerInitialBalance - transferAmount, "Owner balance should decrease"); + assertEq(user1FinalBalance, user1InitialBalance + transferAmount, "User1 balance should increase"); + } + + // Test transfer to zero address + function test_transferToZeroAddress() public { + // Try to transfer to zero address + uint256 transferAmount = vault.balanceOf(owner) / 2; + + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_transferToZeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.transfer(address(0), transferAmount); + _stopSnapshotGas(); + } + + // Test transfer from zero address + function test_transferFromZeroAddress() public { + // Try to transfer from zero address (should be unreachable in practice) + uint256 transferAmount = 1 ether; + + // When transferring from address(0), the function will revert with an arithmetic error + // when checking allowances before it even gets to the zero address check + _startSnapshotGas("VaultTokenTest_test_transferFromZeroAddress"); + vm.expectRevert(); // Expect any revert, which will be an arithmetic underflow + vault.transferFrom(address(0), user1, transferAmount); + _stopSnapshotGas(); + } + + // Test approve zero address + function test_approveZeroAddress() public { + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_approveZeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.approve(address(0), 1 ether); + _stopSnapshotGas(); + } + + // Test transfer more than balance + function test_transferMoreThanBalance() public { + uint256 ownerBalance = vault.balanceOf(owner); + + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_transferMoreThanBalance"); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.transfer(user1, ownerBalance + 1); + _stopSnapshotGas(); + } + + // Test transferFrom more than balance + function test_transferFromMoreThanBalance() public { + uint256 ownerBalance = vault.balanceOf(owner); + + // Approve user1 to spend more than owner's balance + vm.prank(owner); + vault.approve(user1, ownerBalance * 2); + + vm.prank(user1); + _startSnapshotGas("VaultTokenTest_test_transferFromMoreThanBalance"); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.transferFrom(owner, user1, ownerBalance + 1); + _stopSnapshotGas(); + } + + // Test transferFrom more than allowance + function test_transferFromMoreThanAllowance() public { + uint256 ownerBalance = vault.balanceOf(owner); + uint256 allowanceAmount = ownerBalance / 2; + + // Approve user1 to spend half of owner's balance + vm.prank(owner); + vault.approve(user1, allowanceAmount); + + vm.prank(user1); + _startSnapshotGas("VaultTokenTest_test_transferFromMoreThanAllowance"); + vm.expectRevert(); // Should revert with arithmetic underflow + vault.transferFrom(owner, user1, allowanceAmount + 1); + _stopSnapshotGas(); + } + + // Test enterExitQueue emits Transfer event + function test_enterExitQueueEmitsTransferEvent() public { + uint256 exitShares = vault.balanceOf(owner) / 2; + + // Expect a Transfer event from owner to vault + vm.expectEmit(true, true, true, true); + emit IERC20.Transfer(owner, address(vault), exitShares); + + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_enterExitQueueEmitsTransferEvent"); + vault.enterExitQueue(exitShares, owner); + _stopSnapshotGas(); + } + + // Test vault transfers shares to vault when entering exit queue + function test_enterExitQueueTransfersToVault() public { + uint256 ownerInitialBalance = vault.balanceOf(owner); + uint256 exitShares = ownerInitialBalance / 2; + + vm.prank(owner); + vault.enterExitQueue(exitShares, owner); + + // Verify owner's balance decreased + uint256 ownerFinalBalance = vault.balanceOf(owner); + assertEq(ownerFinalBalance, ownerInitialBalance - exitShares, "Owner balance should decrease"); + + // Verify queued shares + (uint128 queuedShares,,,,) = vault.getExitQueueData(); + assertEq(queuedShares, exitShares, "Queued shares should match exit amount"); + } + + // Test _updateExitQueue burns shares and emits Transfer + function test_updateExitQueueBurnsShares() public { + // First, enter exit queue + uint256 exitShares = vault.balanceOf(owner) / 2; + + vm.prank(owner); + vault.enterExitQueue(exitShares, owner); + + // Record total supply before update + uint256 totalSupplyBefore = vault.totalSupply(); + + // Set up reward parameters + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + + // Expect a Transfer event to zero address for burned shares + vm.expectEmit(true, true, true, false); + emit IERC20.Transfer(address(vault), address(0), exitShares); + + // Update state to process exit queue + _startSnapshotGas("VaultTokenTest_test_updateExitQueueBurnsShares"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify total supply decreased + uint256 totalSupplyAfter = vault.totalSupply(); + assertLt(totalSupplyAfter, totalSupplyBefore, "Total supply should decrease"); + assertApproxEqAbs( + totalSupplyBefore - totalSupplyAfter, + exitShares, + 2, // small tolerance for rounding + "Decrease should match exit shares" + ); + } + + // Test transfers are blocked for osToken positions + function test_transferWithOsTokenPosition() public { + // First mint osToken to create a position + vm.prank(owner); + vault.mintOsToken(owner, type(uint256).max, address(0)); + + // Try to transfer more shares than allowed by LTV + uint256 transferAmount = vault.balanceOf(owner) / 2; + + vm.prank(owner); + _startSnapshotGas("VaultTokenTest_test_transferWithOsTokenPosition"); + vm.expectRevert(Errors.LowLtv.selector); + vault.transfer(user1, transferAmount); + _stopSnapshotGas(); + } + + // Test mint shares emits Transfer event + function test_depositEmitsTransferEvent() public { + // Expect Transfer event from zero address to user1 + uint256 depositTokens = 2 ether; + uint256 expectedShares = vault.convertToShares(depositTokens); + + vm.expectEmit(true, true, true, false); + emit IERC20.Transfer(address(0), user1, expectedShares); + + _startSnapshotGas("VaultTokenTest_test_depositEmitsTransferEvent"); + _depositToVault(address(vault), depositTokens, user1, user1); + _stopSnapshotGas(); + } + + // Test permit functionality (ERC-20 permit) + function test_permit() public { + uint256 privateKey = 0x1234; // Demo private key (never use in production) + address signer = vm.addr(privateKey); - // Verify nonce was incremented - assertEq(vault.nonces(signer), 1, 'Nonce should be incremented'); - } + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); - // Test using permit with invalid signer - function test_permitInvalidSigner() public { - uint256 privateKey = 0x1234; - address signer = vm.addr(privateKey); - uint256 wrongPrivateKey = 0x5678; - - // Fund signer and make a deposit - vm.deal(signer, 5 ether); - _depositToVault(address(vault), 2 ether, signer, signer); - - // Get current nonce - uint256 nonce = vault.nonces(signer); - - // Create permit parameters - uint256 permitAmount = 1 ether; - uint256 deadline = block.timestamp + 1 days; - - // Create signature with wrong key - bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); - - bytes32 permitTypehash = keccak256( - 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' - ); - - bytes32 structHash = keccak256( - abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline) - ); - - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, digest); - - // Execute permit with invalid signature - _startSnapshotGas('VaultTokenTest_test_permitInvalidSigner'); - vm.expectRevert(Errors.PermitInvalidSigner.selector); - vault.permit(signer, user1, permitAmount, deadline, v, r, s); - _stopSnapshotGas(); - } - - // Test permit with expired deadline - function test_permitExpiredDeadline() public { - uint256 privateKey = 0x1234; - address signer = vm.addr(privateKey); - - // Fund signer and make a deposit - vm.deal(signer, 5 ether); - _depositToVault(address(vault), 2 ether, signer, signer); - - // Get current nonce - uint256 nonce = vault.nonces(signer); - - // Create permit parameters with expired deadline - uint256 permitAmount = 1 ether; - uint256 deadline = block.timestamp - 1; // Expired - - // Create signature - bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); - - bytes32 permitTypehash = keccak256( - 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' - ); - - bytes32 structHash = keccak256( - abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline) - ); - - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); - - // Execute permit with expired deadline - _startSnapshotGas('VaultTokenTest_test_permitExpiredDeadline'); - vm.expectRevert(Errors.DeadlineExpired.selector); - vault.permit(signer, user1, permitAmount, deadline, v, r, s); - _stopSnapshotGas(); - } - - // Test permit with zero address spender - function test_permitZeroAddressSpender() public { - uint256 privateKey = 0x1234; - address signer = vm.addr(privateKey); - - // Fund signer and make a deposit - vm.deal(signer, 5 ether); - _depositToVault(address(vault), 2 ether, signer, signer); - - // Get current nonce - uint256 nonce = vault.nonces(signer); - - // Create permit parameters with zero address spender - uint256 permitAmount = 1 ether; - uint256 deadline = block.timestamp + 1 days; - - // Create signature - bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); - - bytes32 permitTypehash = keccak256( - 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)' - ); - - bytes32 structHash = keccak256( - abi.encode( - permitTypehash, - signer, - address(0), // Zero address - permitAmount, - nonce, - deadline - ) - ); - - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); - - // Execute permit with zero address spender - _startSnapshotGas('VaultTokenTest_test_permitZeroAddressSpender'); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.permit(signer, address(0), permitAmount, deadline, v, r, s); - _stopSnapshotGas(); - } - - // Test InvalidTokenMeta error for token name too long - function test_invalidTokenMetaNameTooLong() public { - // Create a new admin for this test - address newAdmin = makeAddr('newAdmin'); - vm.deal(newAdmin, 10 ether); - - // Try to create vault with name longer than 30 characters - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - name: 'This is a very long name that exceeds thirty characters limit for ERC20 tokens', - symbol: 'LONG', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - EthVaultFactory factory = _getOrCreateFactory(VaultType.EthErc20Vault); - vm.deal(admin, admin.balance + _securityDeposit); - - _startSnapshotGas('VaultTokenTest_test_invalidTokenMetaNameTooLong'); - vm.expectRevert(Errors.InvalidTokenMeta.selector); - vm.prank(admin); - factory.createVault{value: _securityDeposit}(initParams, true); - _stopSnapshotGas(); - } - - // Test InvalidTokenMeta error for token symbol too long - function test_invalidTokenMetaSymbolTooLong() public { - // Create a new admin for this test - address newAdmin = makeAddr('newAdmin'); - vm.deal(newAdmin, 10 ether); - - // Try to create vault with symbol longer than 10 characters - bytes memory initParams = abi.encode( - IEthErc20Vault.EthErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - name: 'Valid Name', - symbol: 'VERYLONGSYMBOL', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - EthVaultFactory factory = _getOrCreateFactory(VaultType.EthErc20Vault); - vm.deal(admin, admin.balance + _securityDeposit); - - _startSnapshotGas('VaultTokenTest_test_invalidTokenMetaSymbolTooLong'); - vm.expectRevert(Errors.InvalidTokenMeta.selector); - vm.prank(admin); - factory.createVault{value: _securityDeposit}(initParams, false); - _stopSnapshotGas(); - } + // Get current nonce + uint256 nonce = vault.nonces(signer); + assertEq(nonce, 0, "Initial nonce should be 0"); + + // Create permit parameters + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp + 1 days; + + // Create signature + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 structHash = keccak256(abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline)); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + // Execute permit + _startSnapshotGas("VaultTokenTest_test_permit"); + vault.permit(signer, user1, permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + + // Verify allowance was set + assertEq(vault.allowance(signer, user1), permitAmount, "Allowance should be set by permit"); + + // Verify nonce was incremented + assertEq(vault.nonces(signer), 1, "Nonce should be incremented"); + } + + // Test using permit with invalid signer + function test_permitInvalidSigner() public { + uint256 privateKey = 0x1234; + address signer = vm.addr(privateKey); + uint256 wrongPrivateKey = 0x5678; + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + + // Create permit parameters + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp + 1 days; + + // Create signature with wrong key + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 structHash = keccak256(abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline)); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, digest); + + // Execute permit with invalid signature + _startSnapshotGas("VaultTokenTest_test_permitInvalidSigner"); + vm.expectRevert(Errors.PermitInvalidSigner.selector); + vault.permit(signer, user1, permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with expired deadline + function test_permitExpiredDeadline() public { + uint256 privateKey = 0x1234; + address signer = vm.addr(privateKey); + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + + // Create permit parameters with expired deadline + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp - 1; // Expired + + // Create signature + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 structHash = keccak256(abi.encode(permitTypehash, signer, user1, permitAmount, nonce, deadline)); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + // Execute permit with expired deadline + _startSnapshotGas("VaultTokenTest_test_permitExpiredDeadline"); + vm.expectRevert(Errors.DeadlineExpired.selector); + vault.permit(signer, user1, permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test permit with zero address spender + function test_permitZeroAddressSpender() public { + uint256 privateKey = 0x1234; + address signer = vm.addr(privateKey); + + // Fund signer and make a deposit + vm.deal(signer, 5 ether); + _depositToVault(address(vault), 2 ether, signer, signer); + + // Get current nonce + uint256 nonce = vault.nonces(signer); + + // Create permit parameters with zero address spender + uint256 permitAmount = 1 ether; + uint256 deadline = block.timestamp + 1 days; + + // Create signature + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + + bytes32 permitTypehash = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 structHash = keccak256( + abi.encode( + permitTypehash, + signer, + address(0), // Zero address + permitAmount, + nonce, + deadline + ) + ); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + + // Execute permit with zero address spender + _startSnapshotGas("VaultTokenTest_test_permitZeroAddressSpender"); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.permit(signer, address(0), permitAmount, deadline, v, r, s); + _stopSnapshotGas(); + } + + // Test InvalidTokenMeta error for token name too long + function test_invalidTokenMetaNameTooLong() public { + // Create a new admin for this test + address newAdmin = makeAddr("newAdmin"); + vm.deal(newAdmin, 10 ether); + + // Try to create vault with name longer than 30 characters + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: "This is a very long name that exceeds thirty characters limit for ERC20 tokens", + symbol: "LONG", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + EthVaultFactory factory = _getOrCreateFactory(VaultType.EthErc20Vault); + vm.deal(admin, admin.balance + _securityDeposit); + + _startSnapshotGas("VaultTokenTest_test_invalidTokenMetaNameTooLong"); + vm.expectRevert(Errors.InvalidTokenMeta.selector); + vm.prank(admin); + factory.createVault{value: _securityDeposit}(initParams, true); + _stopSnapshotGas(); + } + + // Test InvalidTokenMeta error for token symbol too long + function test_invalidTokenMetaSymbolTooLong() public { + // Create a new admin for this test + address newAdmin = makeAddr("newAdmin"); + vm.deal(newAdmin, 10 ether); + + // Try to create vault with symbol longer than 10 characters + bytes memory initParams = abi.encode( + IEthErc20Vault.EthErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + name: "Valid Name", + symbol: "VERYLONGSYMBOL", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + EthVaultFactory factory = _getOrCreateFactory(VaultType.EthErc20Vault); + vm.deal(admin, admin.balance + _securityDeposit); + + _startSnapshotGas("VaultTokenTest_test_invalidTokenMetaSymbolTooLong"); + vm.expectRevert(Errors.InvalidTokenMeta.selector); + vm.prank(admin); + factory.createVault{value: _securityDeposit}(initParams, false); + _stopSnapshotGas(); + } } diff --git a/test/VaultValidators.t.sol b/test/VaultValidators.t.sol index ced6ef85..1e037e12 100644 --- a/test/VaultValidators.t.sol +++ b/test/VaultValidators.t.sol @@ -1,1498 +1,1338 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperValidators} from '../contracts/interfaces/IKeeperValidators.sol'; -import {IVaultValidators} from '../contracts/interfaces/IVaultValidators.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperValidators} from "../contracts/interfaces/IKeeperValidators.sol"; +import {IVaultValidators} from "../contracts/interfaces/IVaultValidators.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; contract VaultValidatorsTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - - address public admin; - address public user; - address public validatorsManager; - address public nonManager; - uint256 public validatorsManagerPrivateKey; - - uint256 public validatorDeposit = 32 ether; - string public exitSignatureIpfsHash = 'ipfsHash'; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - nonManager = makeAddr('nonManager'); - (validatorsManager, validatorsManagerPrivateKey) = makeAddrAndKey('validatorsManager'); - - // Fund accounts with ETH for testing - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - vm.deal(validatorsManager, 100 ether); - vm.deal(nonManager, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Set validators manager - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - - // Deposit ETH to the vault for registration - _depositToVault(address(vault), validatorDeposit, user, user); - } - - // Test successful validator registration by validator manager - function test_registerValidators_byManager() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Extract the public key from validators data (first 48 bytes) - bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - - // Expect ValidatorRegistered event emission - vm.expectEmit(true, true, true, true); - emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); - - // Call registerValidators from validatorsManager - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_byManager'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test validator registration with manager signature - function test_registerValidators_withSignature() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Extract the public key from validators data - bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - - // Create validator manager signature - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - approvalParams.validatorsRegistryRoot, - approvalParams.validators - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); - bytes memory signature = abi.encodePacked(r, s, v); - - // Expect ValidatorRegistered event emission - vm.expectEmit(true, true, true, true); - emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); - - // Call registerValidators from a non-manager address but with valid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_withSignature'); - vault.registerValidators(approvalParams, signature); - _stopSnapshotGas(); - - // Verify nonce was incremented - assertEq(vault.validatorsManagerNonce(), 1, 'Validators manager nonce should be incremented'); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure when called by non-manager without signature - function test_registerValidators_notManager() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Call registerValidators from non-manager without signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_notManager'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure with invalid signature - function test_registerValidators_invalidSignature() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Create invalid signature (wrong signer) - (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - approvalParams.validatorsRegistryRoot, - approvalParams.validators - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); - bytes memory signature = abi.encodePacked(r, s, v); - - // Call registerValidators with invalid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidSignature'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.registerValidators(approvalParams, signature); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure with invalid validators data - function test_registerValidators_invalidValidators() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters but create empty validators data - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - approvalParams.validators = new bytes(0); // Make validators empty - - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' - ), - approvalParams.validatorsRegistryRoot, - address(vault), - keccak256(approvalParams.validators), - keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), - approvalParams.deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - approvalParams.signatures = abi.encodePacked(r, s, v); - - // Call registerValidators with empty validators - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidValidators'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure with invalid validator length - function test_registerValidators_invalidValidatorLength() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters but modify validators length - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Cut validators data to create invalid length - approvalParams.validators = _extractBytes(approvalParams.validators, 0, 100); - - bytes32 digest = _hashKeeperTypedData( - address(contracts.keeper), - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' - ), - approvalParams.validatorsRegistryRoot, - address(vault), - keccak256(approvalParams.validators), - keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), - approvalParams.deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - approvalParams.signatures = abi.encodePacked(r, s, v); - - // Call registerValidators with invalid validator length - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_invalidValidatorLength'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure when deposit amount is too small - function test_registerValidators_insufficientAssets() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Withdraw all assets from vault to make it insufficient - uint256 userShares = vault.getShares(user); - vm.prank(user); - vault.enterExitQueue(userShares, user); - - // Process exit queue to remove assets - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay); // Fast forward time to process exit - vault.updateState(_setEthVaultReward(address(vault), 0, 0)); - - // Call registerValidators with insufficient assets - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_insufficientAssets'); - vm.expectRevert(); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure when vault not harvested - function test_registerValidators_notHarvested() public { - // Collateralize vault to enable rewards - _collateralizeEthVault(address(vault)); - - // Force vault to need harvesting by updating rewards twice - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - - // Verify the vault needs harvesting - assertTrue(contracts.keeper.isHarvestRequired(address(vault)), 'Vault should need harvesting'); - - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Call registerValidators when vault needs harvesting - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_notHarvested'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test multiple validators registration - function test_registerValidators_multipleValidators() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Deposit enough for multiple validators - _depositToVault(address(vault), validatorDeposit * 2, user, user); - - // Prepare approval params for multiple validators - uint256[] memory deposits = new uint256[](2); - deposits[0] = 32 ether / 1 gwei; - deposits[1] = 32 ether / 1 gwei; - - IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - address(vault), - exitSignatureIpfsHash, - deposits, - false - ); - - // Calculate validator length for each validator - uint256 validatorLength = 184; // Length for V2 validator - - // Extract first validator's public key and expect its event - bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); - vm.expectEmit(true, true, true, true); - emit IVaultValidators.V2ValidatorRegistered(publicKey1, validatorDeposit); - - // Extract second validator's public key and expect its event - bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); - vm.expectEmit(true, true, true, true); - emit IVaultValidators.V2ValidatorRegistered(publicKey2, validatorDeposit); - - // Call registerValidators with multiple validators - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_multipleValidators'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test V1 validator registration (with 0x01 prefix) - function test_registerValidators_v1Validators() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters for V1 validator - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - true // Use V1 validator - ); - - // Extract the public key from validators data - bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - vm.assertFalse(vault.v2Validators(keccak256(publicKey)), 'Validator should not be tracked'); - - // For V1 validators, the event is emitted without deposit amount - vm.expectEmit(true, true, true, false); - emit IVaultValidators.ValidatorRegistered(publicKey); - - // Call registerValidators with V1 validator - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_v1Validators'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - - vm.assertFalse(vault.v2Validators(keccak256(publicKey)), 'Validator should not be tracked'); - } - - // Test V2 validator registration (with 0x02 prefix) - function test_registerValidators_v2Validators() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters for V2 validator - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false // Use V2 validator - ); - - // Extract the public key from validators data - bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - vm.assertFalse(vault.v2Validators(keccak256(publicKey)), 'Validator should not be tracked'); - - // For V2 validators, the event includes deposit amount - vm.expectEmit(true, true, true, true); - emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); - - // Call registerValidators with V2 validator - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_v2Validators'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - vm.assertTrue(vault.v2Validators(keccak256(publicKey)), 'Validator should be tracked'); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test same signature can't be reused (nonce verification) - function test_registerValidators_nonceIncrement() public { - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Get validator approval parameters - IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( - address(vault), - validatorDeposit, - exitSignatureIpfsHash, - false - ); - - // Extract the public key from validators data - bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); - - // Create validator manager signature - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - approvalParams.validatorsRegistryRoot, - approvalParams.validators - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); - bytes memory signature = abi.encodePacked(r, s, v); - - // Expect event for first use - vm.expectEmit(true, true, true, true); - emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); - - // Use the signature once - vm.prank(nonManager); - vault.registerValidators(approvalParams, signature); - - // Record nonce after first use - uint256 nonceAfterFirstUse = vault.validatorsManagerNonce(); - - // Try to use the same signature again - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_registerValidators_nonceIncrement'); - vm.expectRevert(Errors.InvalidValidatorsRegistryRoot.selector); - vault.registerValidators(approvalParams, signature); - _stopSnapshotGas(); - - // Verify nonce wasn't incremented on failed attempt - assertEq( - vault.validatorsManagerNonce(), - nonceAfterFirstUse, - 'Nonce should not increment on failed attempt' - ); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Helper function to get the message that would be signed by the validators manager - function _getValidatorsManagerSigningMessage( - address _vault, - bytes32 validatorsRegistryRoot, - bytes memory validators - ) internal view returns (bytes32) { - bytes32 domainSeparator = keccak256( - abi.encode( - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256(bytes('VaultValidators')), - keccak256('1'), - block.chainid, - _vault - ) - ); - - bytes32 structHash = keccak256( - abi.encode( - keccak256('VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)'), - validatorsRegistryRoot, - keccak256(validators) - ) - ); - - return MessageHashUtils.toTypedDataHash(domainSeparator, structHash); - } - - // Test successful validator funding by validator manager - function test_fundValidators_byManager() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // Prepare top-up data - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create valid top-up data - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Check for ValidatorFunded event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); - - // Call fundValidators from validatorsManager - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_byManager'); - vault.fundValidators(validTopUpData, ''); - _stopSnapshotGas(); - } - - // Test validator funding with manager signature - function test_fundValidators_withSignature() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // Prepare top-up data - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create valid top-up data - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Create validator manager signature - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - bytes32(vault.validatorsManagerNonce()), - validTopUpData - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); - bytes memory validatorManagerSignature = abi.encodePacked(r, s, v); - - // Record current nonce - uint256 currentNonce = vault.validatorsManagerNonce(); - - // Check for ValidatorFunded event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); - - // Call fundValidators from non-manager with valid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_withSignature'); - vault.fundValidators(validTopUpData, validatorManagerSignature); - _stopSnapshotGas(); - - // Verify nonce was incremented - assertEq( - vault.validatorsManagerNonce(), - currentNonce + 1, - 'Validators manager nonce should be incremented' - ); - } - - // Test failure when trying to fund a non-existing validator - function test_fundValidators_nonExistingValidator() public { - _collateralizeEthVault(address(vault)); - - // Deposit enough ETH for funding - _depositToVault(address(vault), validatorDeposit, user, user); - - // Create a non-existing validator public key - bytes memory nonExistingPublicKey = vm.randomBytes(48); - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - nonExistingPublicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create top-up data for non-existing validator - bytes memory invalidTopUpData = bytes.concat( - nonExistingPublicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Call fundValidators with non-existing validator - should fail - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_nonExistingValidator'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.fundValidators(invalidTopUpData, ''); - _stopSnapshotGas(); - } - - // Test failure when called by non-manager without signature - function test_fundValidators_notManager() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // Prepare top-up data - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create valid top-up data - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Call fundValidators from non-manager without signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_notManager'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.fundValidators(validTopUpData, ''); - _stopSnapshotGas(); - } - - // Test failure with invalid signature - function test_fundValidators_invalidSignature() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // Prepare top-up data - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create valid top-up data - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Create invalid signature (wrong signer) - (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - bytes32(vault.validatorsManagerNonce()), - validTopUpData - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); - bytes memory invalidSignature = abi.encodePacked(r, s, v); - - // Call fundValidators with invalid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_invalidSignature'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.fundValidators(validTopUpData, invalidSignature); - _stopSnapshotGas(); - } - - // Test failure with invalid validators data - function test_fundValidators_invalidValidators() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - _registerEthValidator(address(vault), validatorDeposit, false); - - // Create empty validators data - bytes memory emptyValidatorsData = new bytes(0); - - // Call fundValidators with empty validators data - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_invalidValidators'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.fundValidators(emptyValidatorsData, ''); - _stopSnapshotGas(); - } - - // Test failure with insufficient assets - function test_fundValidators_insufficientAssets() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit + 0.5 ether, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // Prepare top-up data with more ETH than available in the vault - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create valid top-up data - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Drain most of the vault's funds to make it insufficient - uint256 exitShares = vault.getShares(user) - vault.convertToShares(0.1 ether); - vm.prank(user); - vault.enterExitQueue(exitShares, user); - - // Process exit queue to remove assets - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay); - vault.updateState(_setEthVaultReward(address(vault), 0, 0)); - - // Call fundValidators with insufficient assets - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_insufficientAssets'); - vm.expectRevert(); - vault.fundValidators(validTopUpData, ''); - _stopSnapshotGas(); - } - - // Test failure when vault not harvested - function test_fundValidators_notHarvested() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // Collateralize vault to enable rewards - _collateralizeEthVault(address(vault)); - - // Force vault to need harvesting by updating rewards twice - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); - - // Verify the vault needs harvesting - assertTrue(contracts.keeper.isHarvestRequired(address(vault)), 'Vault should need harvesting'); - - // Prepare top-up data - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create valid top-up data - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Call fundValidators when vault needs harvesting - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_notHarvested'); - vm.expectRevert(Errors.NotHarvested.selector); - vault.fundValidators(validTopUpData, ''); - _stopSnapshotGas(); - } - - // Test that V1 validators can't be topped up - function test_fundValidators_v1Validators() public { - // First register a V1 validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, true); // V1 validator - - // Prepare top-up data for V1 validator - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x01), bytes11(0x0), vault); // V1 prefix - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create top-up data for V1 validator - actual validator format needs to be V1 - bytes memory invalidTopUpData = bytes.concat(publicKey, signature, depositDataRoot); - - // Call fundValidators with V1 validator - should fail - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_v1Validators'); - vm.expectRevert(Errors.CannotTopUpV1Validators.selector); - vault.fundValidators(invalidTopUpData, ''); - _stopSnapshotGas(); - } - - // Test funding multiple validators in one call - function test_fundValidators_multipleValidators() public { - vm.deal(user, 200 ether); - - // Register multiple validators to make them tracked - _depositToVault(address(vault), validatorDeposit * 4, user, user); - - // Setup oracle for approval - _startOracleImpersonate(address(contracts.keeper)); - - // Register two validators - uint256[] memory initialDeposits = new uint256[](2); - initialDeposits[0] = 32 ether / 1 gwei; - initialDeposits[1] = 32 ether / 1 gwei; - - IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( - address(contracts.keeper), - address(contracts.validatorsRegistry), - address(vault), - exitSignatureIpfsHash, - initialDeposits, - false - ); - - vm.prank(validatorsManager); - vault.registerValidators(approvalParams, ''); - - // Calculate validator length for each validator - uint256 validatorLength = 184; // Length for V2 validator - - // Extract validator public keys - bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); - bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); - - // Prepare top-up data for both validators - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - - // Create deposit data for first validator - bytes32 depositDataRoot1 = _getDepositDataRoot( - publicKey1, - signature, - withdrawalCredentials, - topUpAmount - ); - bytes memory validatorData1 = bytes.concat( - publicKey1, - signature, - depositDataRoot1, - bytes8(uint64(topUpAmount)) - ); - - // Create deposit data for second validator - bytes32 depositDataRoot2 = _getDepositDataRoot( - publicKey2, - signature, - withdrawalCredentials, - topUpAmount - ); - bytes memory validatorData2 = bytes.concat( - publicKey2, - signature, - depositDataRoot2, - bytes8(uint64(topUpAmount)) - ); - - // Combine data for both validators - bytes memory combinedValidatorsData = bytes.concat(validatorData1, validatorData2); - - // Expect validator funded events - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey1, 1 ether); - - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey2, 1 ether); - - // Call fundValidators with multiple validators - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_fundValidators_multipleValidators'); - vault.fundValidators(combinedValidatorsData, ''); - _stopSnapshotGas(); - - // Cleanup - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test successful validator withdrawal by validator manager - function test_withdrawValidators_byManager() public { - // 1. First register a validator to track it and provide funds to withdraw - _depositToVault(address(vault), validatorDeposit, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data - for Ethereum validators, - // _validatorWithdrawalLength is 56 (48 bytes publicKey + 8 bytes amount) - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); - - // 3. Mock the withdrawal fee - uint256 withdrawalFee = 0.1 ether; - vm.deal(validatorsManager, withdrawalFee); - - // 4. Expect ValidatorWithdrawalSubmitted event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, withdrawalFee); - - // 5. Call withdrawValidators from validatorsManager - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_byManager'); - vault.withdrawValidators{value: withdrawalFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - // Test validator withdrawal with manager signature - function test_withdrawValidators_withSignature() public { - // 1. First register a validator - _depositToVault(address(vault), validatorDeposit, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); - - // 3. Create validator manager signature - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - bytes32(vault.validatorsManagerNonce()), - withdrawalData - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); - bytes memory signature = abi.encodePacked(r, s, v); - - // 4. Record current nonce - uint256 currentNonce = vault.validatorsManagerNonce(); - - // 5. Fund non-manager for withdrawal fee - uint256 withdrawalFee = 0.1 ether; - vm.deal(nonManager, withdrawalFee); - - // 6. Expect ValidatorWithdrawalSubmitted event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, withdrawalFee); - - // 7. Call withdrawValidators from non-manager with valid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_withSignature'); - vault.withdrawValidators{value: withdrawalFee}(withdrawalData, signature); - _stopSnapshotGas(); - - // 8. Verify nonce was incremented - assertEq( - vault.validatorsManagerNonce(), - currentNonce + 1, - 'Validators manager nonce should be incremented' - ); - } - - // Test withdrawal by osToken redeemer - function test_withdrawValidators_byRedeemer() public { - // 1. Register a validator - _depositToVault(address(vault), validatorDeposit, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); - - // 3. Get the redeemer from osTokenConfig - address redeemer = contracts.osTokenConfig.redeemer(); - vm.deal(redeemer, 0.1 ether); - - // 4. Expect ValidatorWithdrawalSubmitted event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, 0.1 ether); - - // 5. Call withdrawValidators from redeemer - vm.prank(redeemer); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_byRedeemer'); - vault.withdrawValidators{value: 0.1 ether}(withdrawalData, ''); - _stopSnapshotGas(); - } - - // Test failed withdrawal by unauthorized user - function test_withdrawValidators_notAuthorized() public { - // 1. Register a validator - _depositToVault(address(vault), validatorDeposit, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); - - // 3. Fund unauthorized user - vm.deal(nonManager, 0.1 ether); - - // 4. Call withdrawValidators from unauthorized user without signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_notAuthorized'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: 0.1 ether}(withdrawalData, ''); - _stopSnapshotGas(); - } - - // Test failed withdrawal with invalid signature - function test_withdrawValidators_invalidSignature() public { - // 1. Register a validator - _depositToVault(address(vault), validatorDeposit, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); - - // 3. Create invalid signature (wrong signer) - (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - bytes32(vault.validatorsManagerNonce()), - withdrawalData - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); - bytes memory invalidSignature = abi.encodePacked(r, s, v); - - // 4. Fund unauthorized user - vm.deal(nonManager, 0.1 ether); - - // 5. Call withdrawValidators with invalid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidSignature'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: 0.1 ether}(withdrawalData, invalidSignature); - _stopSnapshotGas(); - } - - // Test failed withdrawal with invalid validator data - function test_withdrawValidators_invalidValidators() public { - _collateralizeEthVault(address(vault)); - - // 1. Prepare invalid withdrawal data (zero length) - bytes memory invalidWithdrawalData = new bytes(0); - - // 2. Fund validator manager - vm.deal(validatorsManager, 0.1 ether); - - // 3. Call withdrawValidators with empty data - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: 0.1 ether}(invalidWithdrawalData, ''); - _stopSnapshotGas(); - - // 4. Test with invalid length (not a multiple of _validatorWithdrawalLength) - // For Ethereum validators, _validatorWithdrawalLength is 56 (48 bytes publicKey + 8 bytes amount) - bytes memory invalidLengthData = new bytes(30); // Not a multiple of 56 - - // 5. Call withdrawValidators with invalid length data - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_invalidValidatorsLength'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.withdrawValidators{value: 0.1 ether}(invalidLengthData, ''); - _stopSnapshotGas(); - } - - // Test fee handling and refunds - function test_withdrawValidators_feeHandling() public { - // 1. Register a validator - _depositToVault(address(vault), validatorDeposit, user, user); - bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); - - // 3. Set excess fee (more than needed) - uint256 actualFee = 0.1 ether; - uint256 excessFee = 0.5 ether; // Overpay - vm.deal(validatorsManager, excessFee); - - // 4. Record initial balance - uint256 initialBalance = validatorsManager.balance; - - // 5. Call withdrawValidators with excess fee - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_feeHandling'); - vault.withdrawValidators{value: excessFee}(withdrawalData, ''); - _stopSnapshotGas(); - - // 6. Verify the correct fee was deducted and excess was refunded - uint256 finalBalance = validatorsManager.balance; - assertEq(finalBalance, initialBalance - actualFee, 'Excess fee should be refunded'); - } - - // Test withdrawing multiple validators in a single call - function test_withdrawValidators_multipleValidators() public { - // 1. First register multiple validators - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory publicKey1 = _registerEthValidator(address(vault), validatorDeposit, false); - bytes memory publicKey2 = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare withdrawal data for both validators - uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei - bytes memory withdrawalData1 = abi.encodePacked(publicKey1, bytes8(uint64(withdrawalAmount))); - bytes memory withdrawalData2 = abi.encodePacked(publicKey2, bytes8(uint64(withdrawalAmount))); - bytes memory combinedData = bytes.concat(withdrawalData1, withdrawalData2); - - // 3. Set fee for two withdrawals - uint256 feePerValidator = 0.1 ether; - uint256 totalFee = feePerValidator * 2; - vm.deal(validatorsManager, totalFee); - - // 4. Expect events for both withdrawals - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey1, 1 ether, feePerValidator); - - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey2, 1 ether, feePerValidator); - - // 5. Call withdrawValidators with combined data - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_withdrawValidators_multipleValidators'); - vault.withdrawValidators{value: totalFee}(combinedData, ''); - _stopSnapshotGas(); - } - - // Test successful validator consolidation by validator manager - function test_consolidateValidators_byManager() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); - - // Register a second validator to use as destination (must be tracked to avoid oracle requirement) - bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(validatorsManager, consolidationFee); - - // Call consolidateValidators from validatorsManager - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_byManager'); - vault.consolidateValidators{value: consolidationFee}(consolidationData, '', ''); - _stopSnapshotGas(); - } - - // Test validator consolidation with manager signature - function test_consolidateValidators_withSignature() public { - // First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); - - // Register a second validator to use as destination (must be tracked) - bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // Create validator manager signature - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - bytes32(vault.validatorsManagerNonce()), - consolidationData - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); - bytes memory signature = abi.encodePacked(r, s, v); - - // Record current nonce - uint256 currentNonce = vault.validatorsManagerNonce(); - - // Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(nonManager, consolidationFee); - - // Call consolidateValidators from non-manager with valid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_withSignature'); - vault.consolidateValidators{value: consolidationFee}(consolidationData, signature, ''); - _stopSnapshotGas(); - - // Verify nonce was incremented - assertEq( - vault.validatorsManagerNonce(), - currentNonce + 1, - 'Validators manager nonce should be incremented' - ); - } - - // Test validator consolidation with oracle signatures - function test_consolidateValidators_withOracleSignatures() public { - // Register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); - - // Prepare consolidation data (to an untracked destination validator) - bytes memory destPublicKey = vm.randomBytes(48); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // Create oracle signature using our known oracle private key - bytes32 digest = keccak256( - abi.encodePacked( - '\x19\x01', - keccak256( - abi.encode( + ForkContracts public contracts; + EthVault public vault; + + address public admin; + address public user; + address public validatorsManager; + address public nonManager; + uint256 public validatorsManagerPrivateKey; + + uint256 public validatorDeposit = 32 ether; + string public exitSignatureIpfsHash = "ipfsHash"; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + nonManager = makeAddr("nonManager"); + (validatorsManager, validatorsManagerPrivateKey) = makeAddrAndKey("validatorsManager"); + + // Fund accounts with ETH for testing + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + vm.deal(validatorsManager, 100 ether); + vm.deal(nonManager, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Set validators manager + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + // Deposit ETH to the vault for registration + _depositToVault(address(vault), validatorDeposit, user, user); + } + + // Test successful validator registration by validator manager + function test_registerValidators_byManager() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Extract the public key from validators data (first 48 bytes) + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + + // Expect ValidatorRegistered event emission + vm.expectEmit(true, true, true, true); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); + + // Call registerValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_byManager"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test validator registration with manager signature + function test_registerValidators_withSignature() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), approvalParams.validatorsRegistryRoot, approvalParams.validators + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Expect ValidatorRegistered event emission + vm.expectEmit(true, true, true, true); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); + + // Call registerValidators from a non-manager address but with valid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_withSignature"); + vault.registerValidators(approvalParams, signature); + _stopSnapshotGas(); + + // Verify nonce was incremented + assertEq(vault.validatorsManagerNonce(), 1, "Validators manager nonce should be incremented"); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when called by non-manager without signature + function test_registerValidators_notManager() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Call registerValidators from non-manager without signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_notManager"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure with invalid signature + function test_registerValidators_invalidSignature() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey("wrong"); + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), approvalParams.validatorsRegistryRoot, approvalParams.validators + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Call registerValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_invalidSignature"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.registerValidators(approvalParams, signature); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure with invalid validators data + function test_registerValidators_invalidValidators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters but create empty validators data + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + approvalParams.validators = new bytes(0); // Make validators empty + + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ), - keccak256('ConsolidationsChecker'), - keccak256('1'), - block.chainid, - address(contracts.consolidationsChecker) - ) - ), - keccak256( - abi.encode( - keccak256('ConsolidationsChecker(address vault,bytes validators)'), + abi.encode( + keccak256( + "KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)" + ), + approvalParams.validatorsRegistryRoot, + address(vault), + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); + + // Call registerValidators with empty validators + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_invalidValidators"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure with invalid validator length + function test_registerValidators_invalidValidatorLength() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters but modify validators length + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Cut validators data to create invalid length + approvalParams.validators = _extractBytes(approvalParams.validators, 0, 100); + + bytes32 digest = _hashKeeperTypedData( + address(contracts.keeper), + keccak256( + abi.encode( + keccak256( + "KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)" + ), + approvalParams.validatorsRegistryRoot, + address(vault), + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); + + // Call registerValidators with invalid validator length + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_invalidValidatorLength"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when deposit amount is too small + function test_registerValidators_insufficientAssets() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Withdraw all assets from vault to make it insufficient + uint256 userShares = vault.getShares(user); + vm.prank(user); + vault.enterExitQueue(userShares, user); + + // Process exit queue to remove assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay); // Fast forward time to process exit + vault.updateState(_setEthVaultReward(address(vault), 0, 0)); + + // Call registerValidators with insufficient assets + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_insufficientAssets"); + vm.expectRevert(); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when vault not harvested + function test_registerValidators_notHarvested() public { + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Force vault to need harvesting by updating rewards twice + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Verify the vault needs harvesting + assertTrue(contracts.keeper.isHarvestRequired(address(vault)), "Vault should need harvesting"); + + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Call registerValidators when vault needs harvesting + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_notHarvested"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test multiple validators registration + function test_registerValidators_multipleValidators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Deposit enough for multiple validators + _depositToVault(address(vault), validatorDeposit * 2, user, user); + + // Prepare approval params for multiple validators + uint256[] memory deposits = new uint256[](2); + deposits[0] = 32 ether / 1 gwei; + deposits[1] = 32 ether / 1 gwei; + + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), + address(vault), + exitSignatureIpfsHash, + deposits, + false + ); + + // Calculate validator length for each validator + uint256 validatorLength = 184; // Length for V2 validator + + // Extract first validator's public key and expect its event + bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); + vm.expectEmit(true, true, true, true); + emit IVaultValidators.V2ValidatorRegistered(publicKey1, validatorDeposit); + + // Extract second validator's public key and expect its event + bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); + vm.expectEmit(true, true, true, true); + emit IVaultValidators.V2ValidatorRegistered(publicKey2, validatorDeposit); + + // Call registerValidators with multiple validators + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_multipleValidators"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test V1 validator registration (with 0x01 prefix) + function test_registerValidators_v1Validators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters for V1 validator + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + true // Use V1 validator + ); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + vm.assertFalse(vault.v2Validators(keccak256(publicKey)), "Validator should not be tracked"); + + // For V1 validators, the event is emitted without deposit amount + vm.expectEmit(true, true, true, false); + emit IVaultValidators.ValidatorRegistered(publicKey); + + // Call registerValidators with V1 validator + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_v1Validators"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + + vm.assertFalse(vault.v2Validators(keccak256(publicKey)), "Validator should not be tracked"); + } + + // Test V2 validator registration (with 0x02 prefix) + function test_registerValidators_v2Validators() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters for V2 validator + IKeeperValidators.ApprovalParams memory approvalParams = _getEthValidatorApproval( + address(vault), + validatorDeposit, + exitSignatureIpfsHash, + false // Use V2 validator + ); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + vm.assertFalse(vault.v2Validators(keccak256(publicKey)), "Validator should not be tracked"); + + // For V2 validators, the event includes deposit amount + vm.expectEmit(true, true, true, true); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); + + // Call registerValidators with V2 validator + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_v2Validators"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + vm.assertTrue(vault.v2Validators(keccak256(publicKey)), "Validator should be tracked"); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test same signature can't be reused (nonce verification) + function test_registerValidators_nonceIncrement() public { + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Get validator approval parameters + IKeeperValidators.ApprovalParams memory approvalParams = + _getEthValidatorApproval(address(vault), validatorDeposit, exitSignatureIpfsHash, false); + + // Extract the public key from validators data + bytes memory publicKey = _extractBytes(approvalParams.validators, 0, 48); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), approvalParams.validatorsRegistryRoot, approvalParams.validators + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Expect event for first use + vm.expectEmit(true, true, true, true); + emit IVaultValidators.V2ValidatorRegistered(publicKey, validatorDeposit); + + // Use the signature once + vm.prank(nonManager); + vault.registerValidators(approvalParams, signature); + + // Record nonce after first use + uint256 nonceAfterFirstUse = vault.validatorsManagerNonce(); + + // Try to use the same signature again + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_registerValidators_nonceIncrement"); + vm.expectRevert(Errors.InvalidValidatorsRegistryRoot.selector); + vault.registerValidators(approvalParams, signature); + _stopSnapshotGas(); + + // Verify nonce wasn't incremented on failed attempt + assertEq(vault.validatorsManagerNonce(), nonceAfterFirstUse, "Nonce should not increment on failed attempt"); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Helper function to get the message that would be signed by the validators manager + function _getValidatorsManagerSigningMessage( + address _vault, + bytes32 validatorsRegistryRoot, + bytes memory validators + ) internal view returns (bytes32) { + bytes32 domainSeparator = keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes("VaultValidators")), + keccak256("1"), + block.chainid, + _vault + ) + ); + + bytes32 structHash = keccak256( + abi.encode( + keccak256("VaultValidators(bytes32 validatorsRegistryRoot,bytes validators)"), + validatorsRegistryRoot, + keccak256(validators) + ) + ); + + return MessageHashUtils.toTypedDataHash(domainSeparator, structHash); + } + + // Test successful validator funding by validator manager + function test_fundValidators_byManager() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + // Call fundValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_byManager"); + vault.fundValidators(validTopUpData, ""); + _stopSnapshotGas(); + } + + // Test validator funding with manager signature + function test_fundValidators_withSignature() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Create validator manager signature + bytes32 message = + _getValidatorsManagerSigningMessage(address(vault), bytes32(vault.validatorsManagerNonce()), validTopUpData); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory validatorManagerSignature = abi.encodePacked(r, s, v); + + // Record current nonce + uint256 currentNonce = vault.validatorsManagerNonce(); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 1 ether); + + // Call fundValidators from non-manager with valid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_withSignature"); + vault.fundValidators(validTopUpData, validatorManagerSignature); + _stopSnapshotGas(); + + // Verify nonce was incremented + assertEq(vault.validatorsManagerNonce(), currentNonce + 1, "Validators manager nonce should be incremented"); + } + + // Test failure when trying to fund a non-existing validator + function test_fundValidators_nonExistingValidator() public { + _collateralizeEthVault(address(vault)); + + // Deposit enough ETH for funding + _depositToVault(address(vault), validatorDeposit, user, user); + + // Create a non-existing validator public key + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory nonExistingPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = + _getDepositDataRoot(nonExistingPublicKey, signature, withdrawalCredentials, topUpAmount); + + // Create top-up data for non-existing validator + bytes memory invalidTopUpData = + bytes.concat(nonExistingPublicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Call fundValidators with non-existing validator - should fail + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_nonExistingValidator"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(invalidTopUpData, ""); + _stopSnapshotGas(); + } + + // Test failure when called by non-manager without signature + function test_fundValidators_notManager() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Call fundValidators from non-manager without signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_notManager"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.fundValidators(validTopUpData, ""); + _stopSnapshotGas(); + } + + // Test failure with invalid signature + function test_fundValidators_invalidSignature() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey("wrong"); + bytes32 message = + _getValidatorsManagerSigningMessage(address(vault), bytes32(vault.validatorsManagerNonce()), validTopUpData); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory invalidSignature = abi.encodePacked(r, s, v); + + // Call fundValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_invalidSignature"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.fundValidators(validTopUpData, invalidSignature); + _stopSnapshotGas(); + } + + // Test failure with invalid validators data + function test_fundValidators_invalidValidators() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + _registerEthValidator(address(vault), validatorDeposit, false); + + // Create empty validators data + bytes memory emptyValidatorsData = new bytes(0); + + // Call fundValidators with empty validators data + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_invalidValidators"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.fundValidators(emptyValidatorsData, ""); + _stopSnapshotGas(); + } + + // Test failure with insufficient assets + function test_fundValidators_insufficientAssets() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit + 0.5 ether, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Prepare top-up data with more ETH than available in the vault + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Drain most of the vault's funds to make it insufficient + uint256 exitShares = vault.getShares(user) - vault.convertToShares(0.1 ether); + vm.prank(user); + vault.enterExitQueue(exitShares, user); + + // Process exit queue to remove assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay); + vault.updateState(_setEthVaultReward(address(vault), 0, 0)); + + // Call fundValidators with insufficient assets + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_insufficientAssets"); + vm.expectRevert(); + vault.fundValidators(validTopUpData, ""); + _stopSnapshotGas(); + } + + // Test failure when vault not harvested + function test_fundValidators_notHarvested() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // Collateralize vault to enable rewards + _collateralizeEthVault(address(vault)); + + // Force vault to need harvesting by updating rewards twice + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + _setEthVaultReward(address(vault), int160(int256(0.1 ether)), 0); + + // Verify the vault needs harvesting + assertTrue(contracts.keeper.isHarvestRequired(address(vault)), "Vault should need harvesting"); + + // Prepare top-up data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create valid top-up data + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Call fundValidators when vault needs harvesting + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_notHarvested"); + vm.expectRevert(Errors.NotHarvested.selector); + vault.fundValidators(validTopUpData, ""); + _stopSnapshotGas(); + } + + // Test that V1 validators can't be topped up + function test_fundValidators_v1Validators() public { + // First register a V1 validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, true); // V1 validator + + // Prepare top-up data for V1 validator + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x01), bytes11(0x0), vault); // V1 prefix + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + + // Create top-up data for V1 validator - actual validator format needs to be V1 + bytes memory invalidTopUpData = bytes.concat(publicKey, signature, depositDataRoot); + + // Call fundValidators with V1 validator - should fail + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_v1Validators"); + vm.expectRevert(Errors.CannotTopUpV1Validators.selector); + vault.fundValidators(invalidTopUpData, ""); + _stopSnapshotGas(); + } + + // Test funding multiple validators in one call + function test_fundValidators_multipleValidators() public { + vm.deal(user, 200 ether); + + // Register multiple validators to make them tracked + _depositToVault(address(vault), validatorDeposit * 4, user, user); + + // Setup oracle for approval + _startOracleImpersonate(address(contracts.keeper)); + + // Register two validators + uint256[] memory initialDeposits = new uint256[](2); + initialDeposits[0] = 32 ether / 1 gwei; + initialDeposits[1] = 32 ether / 1 gwei; + + IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( + address(contracts.keeper), + address(contracts.validatorsRegistry), address(vault), - keccak256(consolidationData) - ) - ) - ) - ); - - // setup oracles - _startOracleImpersonate(address(contracts.keeper)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - bytes memory oracleSignatures = abi.encodePacked(r, s, v); - - // Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(validatorsManager, consolidationFee); - - // Verify the destination validator is not tracked initially - assertFalse( - vault.v2Validators(keccak256(destPublicKey)), - 'Destination validator should not be tracked initially' - ); - - // Call consolidateValidators with oracle signatures - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_withOracleSignatures'); - vault.consolidateValidators{value: consolidationFee}(consolidationData, '', oracleSignatures); - _stopSnapshotGas(); - - // Verify the destination validator is now tracked - assertTrue( - vault.v2Validators(keccak256(destPublicKey)), - 'Destination validator should be tracked after consolidation with oracle approval' - ); - - _stopOracleImpersonate(address(contracts.keeper)); - } - - // Test failure when called by non-manager without signature - function test_consolidateValidators_notManager() public { - // 1. First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare consolidation data - bytes memory destPublicKey = vm.randomBytes(48); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // 3. Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(nonManager, consolidationFee); - - // 4. Call consolidateValidators from non-manager without signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_notManager'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.consolidateValidators{value: consolidationFee}(consolidationData, '', ''); - _stopSnapshotGas(); - } - - // Test failure with invalid signature - function test_consolidateValidators_invalidSignature() public { - // 1. First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare consolidation data - bytes memory destPublicKey = vm.randomBytes(48); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // 3. Create invalid signature (wrong signer) - (, uint256 wrongPrivateKey) = makeAddrAndKey('wrong'); - bytes32 message = _getValidatorsManagerSigningMessage( - address(vault), - bytes32(vault.validatorsManagerNonce()), - consolidationData - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); - bytes memory invalidSignature = abi.encodePacked(r, s, v); - - // 4. Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(nonManager, consolidationFee); - - // 5. Call consolidateValidators with invalid signature - vm.prank(nonManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidSignature'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.consolidateValidators{value: consolidationFee}(consolidationData, invalidSignature, ''); - _stopSnapshotGas(); - } - - // Test failure with invalid validators data - function test_consolidateValidators_invalidValidators() public { - _collateralizeEthVault(address(vault)); - - // 1. Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(validatorsManager, consolidationFee); - - // 2. Create empty validators data - bytes memory emptyValidatorsData = new bytes(0); - - // 3. Call consolidateValidators with empty validators data - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.consolidateValidators{value: consolidationFee}(emptyValidatorsData, '', ''); - _stopSnapshotGas(); - - // 4. Test with invalid length (not a multiple of _validatorConsolidationLength) - // For consolidation, _validatorConsolidationLength is 96 (48 bytes sourcePublicKey + 48 bytes destPublicKey) - bytes memory invalidLengthData = new bytes(50); // Not a multiple of 96 - - // 5. Call consolidateValidators with invalid length data - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_invalidValidatorsLength'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.consolidateValidators{value: consolidationFee}(invalidLengthData, '', ''); - _stopSnapshotGas(); - } - - // Test failure for untracked destination without oracle approval - function test_consolidateValidators_untrackedDestination() public { - // 1. First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare consolidation data with untracked destination - bytes memory destPublicKey = vm.randomBytes(48); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // 3. Verify destination is not tracked - assertFalse( - vault.v2Validators(keccak256(destPublicKey)), - 'Destination validator should not be tracked initially' - ); - - // 4. Set up the consolidation fee - uint256 consolidationFee = 0.1 ether; - vm.deal(validatorsManager, consolidationFee); - - // 5. Attempt consolidation without oracle signatures - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_untrackedDestination'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.consolidateValidators{value: consolidationFee}(consolidationData, '', ''); - _stopSnapshotGas(); - } - - // Test fee handling and refunds - function test_consolidateValidators_feeHandling() public { - // 1. First register a validator to make it tracked - _depositToVault(address(vault), validatorDeposit * 2, user, user); - bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - - // 2. Prepare consolidation data (to another tracked validator) - bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); - bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); - - // 3. Set excess fee (more than needed) - uint256 actualFee = 0.1 ether; - uint256 excessFee = 0.5 ether; // Overpay - vm.deal(validatorsManager, excessFee); - - // 4. Record initial balance - uint256 initialBalance = validatorsManager.balance; - - // 5. Call consolidateValidators with excess fee - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_feeHandling'); - vault.consolidateValidators{value: excessFee}(consolidationData, '', ''); - _stopSnapshotGas(); - - // 6. Verify the correct fee was deducted and excess was refunded - uint256 finalBalance = validatorsManager.balance; - assertEq(finalBalance, initialBalance - actualFee, 'Excess fee should be refunded'); - } - - // Test consolidating multiple validators in a single call - function test_consolidateValidators_multipleValidators() public { - vm.deal(user, 200 ether); - - // Register source validators - _depositToVault(address(vault), validatorDeposit * 3, user, user); - bytes memory sourcePublicKey1 = _registerEthValidator(address(vault), validatorDeposit, true); - bytes memory destPublicKey1 = _registerEthValidator(address(vault), validatorDeposit, false); - - // Consolidate the same validator - bytes memory sourcePublicKey2 = _registerEthValidator(address(vault), validatorDeposit, false); - - // Combine data for both consolidations - bytes memory consolidationData1 = bytes.concat(sourcePublicKey1, destPublicKey1); - bytes memory consolidationData2 = bytes.concat(sourcePublicKey2, sourcePublicKey2); - bytes memory combinedData = bytes.concat(consolidationData1, consolidationData2); - - // setup oracle - _stopOracleImpersonate(address(contracts.keeper)); - - // Set fee for two consolidations - uint256 feePerConsolidation = 0.1 ether; - uint256 totalFee = feePerConsolidation * 2; - vm.deal(validatorsManager, totalFee); - - // Call consolidateValidators with multiple validators - vm.prank(validatorsManager); - _startSnapshotGas('VaultValidatorsTest_test_consolidateValidators_multipleValidators'); - vault.consolidateValidators{value: totalFee}(combinedData, '', ''); - _stopSnapshotGas(); - - // remove oracle - _stopOracleImpersonate(address(contracts.keeper)); - } + exitSignatureIpfsHash, + initialDeposits, + false + ); + + vm.prank(validatorsManager); + vault.registerValidators(approvalParams, ""); + + // Calculate validator length for each validator + uint256 validatorLength = 184; // Length for V2 validator + + // Extract validator public keys + bytes memory publicKey1 = _extractBytes(approvalParams.validators, 0, 48); + bytes memory publicKey2 = _extractBytes(approvalParams.validators, validatorLength, 48); + + // Prepare top-up data for both validators + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + + // Create deposit data for first validator + bytes32 depositDataRoot1 = _getDepositDataRoot(publicKey1, signature, withdrawalCredentials, topUpAmount); + bytes memory validatorData1 = bytes.concat(publicKey1, signature, depositDataRoot1, bytes8(uint64(topUpAmount))); + + // Create deposit data for second validator + bytes32 depositDataRoot2 = _getDepositDataRoot(publicKey2, signature, withdrawalCredentials, topUpAmount); + bytes memory validatorData2 = bytes.concat(publicKey2, signature, depositDataRoot2, bytes8(uint64(topUpAmount))); + + // Combine data for both validators + bytes memory combinedValidatorsData = bytes.concat(validatorData1, validatorData2); + + // Expect validator funded events + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey1, 1 ether); + + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey2, 1 ether); + + // Call fundValidators with multiple validators + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_fundValidators_multipleValidators"); + vault.fundValidators(combinedValidatorsData, ""); + _stopSnapshotGas(); + + // Cleanup + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test successful validator withdrawal by validator manager + function test_withdrawValidators_byManager() public { + // 1. First register a validator to track it and provide funds to withdraw + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data - for Ethereum validators, + // _validatorWithdrawalLength is 56 (48 bytes publicKey + 8 bytes amount) + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Mock the withdrawal fee + uint256 withdrawalFee = 0.1 ether; + vm.deal(validatorsManager, withdrawalFee); + + // 4. Expect ValidatorWithdrawalSubmitted event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, withdrawalFee); + + // 5. Call withdrawValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_byManager"); + vault.withdrawValidators{value: withdrawalFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + // Test validator withdrawal with manager signature + function test_withdrawValidators_withSignature() public { + // 1. First register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Create validator manager signature + bytes32 message = + _getValidatorsManagerSigningMessage(address(vault), bytes32(vault.validatorsManagerNonce()), withdrawalData); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // 4. Record current nonce + uint256 currentNonce = vault.validatorsManagerNonce(); + + // 5. Fund non-manager for withdrawal fee + uint256 withdrawalFee = 0.1 ether; + vm.deal(nonManager, withdrawalFee); + + // 6. Expect ValidatorWithdrawalSubmitted event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, withdrawalFee); + + // 7. Call withdrawValidators from non-manager with valid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_withSignature"); + vault.withdrawValidators{value: withdrawalFee}(withdrawalData, signature); + _stopSnapshotGas(); + + // 8. Verify nonce was incremented + assertEq(vault.validatorsManagerNonce(), currentNonce + 1, "Validators manager nonce should be incremented"); + } + + // Test withdrawal by osToken redeemer + function test_withdrawValidators_byRedeemer() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Get the redeemer from osTokenConfig + address redeemer = contracts.osTokenConfig.redeemer(); + vm.deal(redeemer, 0.1 ether); + + // 4. Expect ValidatorWithdrawalSubmitted event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey, 1 ether, 0.1 ether); + + // 5. Call withdrawValidators from redeemer + vm.prank(redeemer); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_byRedeemer"); + vault.withdrawValidators{value: 0.1 ether}(withdrawalData, ""); + _stopSnapshotGas(); + } + + // Test failed withdrawal by unauthorized user + function test_withdrawValidators_notAuthorized() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Fund unauthorized user + vm.deal(nonManager, 0.1 ether); + + // 4. Call withdrawValidators from unauthorized user without signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_notAuthorized"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: 0.1 ether}(withdrawalData, ""); + _stopSnapshotGas(); + } + + // Test failed withdrawal with invalid signature + function test_withdrawValidators_invalidSignature() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey("wrong"); + bytes32 message = + _getValidatorsManagerSigningMessage(address(vault), bytes32(vault.validatorsManagerNonce()), withdrawalData); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory invalidSignature = abi.encodePacked(r, s, v); + + // 4. Fund unauthorized user + vm.deal(nonManager, 0.1 ether); + + // 5. Call withdrawValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_invalidSignature"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: 0.1 ether}(withdrawalData, invalidSignature); + _stopSnapshotGas(); + } + + // Test failed withdrawal with invalid validator data + function test_withdrawValidators_invalidValidators() public { + _collateralizeEthVault(address(vault)); + + // 1. Prepare invalid withdrawal data (zero length) + bytes memory invalidWithdrawalData = new bytes(0); + + // 2. Fund validator manager + vm.deal(validatorsManager, 0.1 ether); + + // 3. Call withdrawValidators with empty data + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: 0.1 ether}(invalidWithdrawalData, ""); + _stopSnapshotGas(); + + // 4. Test with invalid length (not a multiple of _validatorWithdrawalLength) + // For Ethereum validators, _validatorWithdrawalLength is 56 (48 bytes publicKey + 8 bytes amount) + bytes memory invalidLengthData = new bytes(30); // Not a multiple of 56 + + // 5. Call withdrawValidators with invalid length data + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_invalidValidatorsLength"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.withdrawValidators{value: 0.1 ether}(invalidLengthData, ""); + _stopSnapshotGas(); + } + + // Test fee handling and refunds + function test_withdrawValidators_feeHandling() public { + // 1. Register a validator + _depositToVault(address(vault), validatorDeposit, user, user); + bytes memory publicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(withdrawalAmount))); + + // 3. Set excess fee (more than needed) + uint256 actualFee = 0.1 ether; + uint256 excessFee = 0.5 ether; // Overpay + vm.deal(validatorsManager, excessFee); + + // 4. Record initial balance + uint256 initialBalance = validatorsManager.balance; + + // 5. Call withdrawValidators with excess fee + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_feeHandling"); + vault.withdrawValidators{value: excessFee}(withdrawalData, ""); + _stopSnapshotGas(); + + // 6. Verify the correct fee was deducted and excess was refunded + uint256 finalBalance = validatorsManager.balance; + assertEq(finalBalance, initialBalance - actualFee, "Excess fee should be refunded"); + } + + // Test withdrawing multiple validators in a single call + function test_withdrawValidators_multipleValidators() public { + // 1. First register multiple validators + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory publicKey1 = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory publicKey2 = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare withdrawal data for both validators + uint256 withdrawalAmount = 1 ether / 1 gwei; // 1 ETH in Gwei + bytes memory withdrawalData1 = abi.encodePacked(publicKey1, bytes8(uint64(withdrawalAmount))); + bytes memory withdrawalData2 = abi.encodePacked(publicKey2, bytes8(uint64(withdrawalAmount))); + bytes memory combinedData = bytes.concat(withdrawalData1, withdrawalData2); + + // 3. Set fee for two withdrawals + uint256 feePerValidator = 0.1 ether; + uint256 totalFee = feePerValidator * 2; + vm.deal(validatorsManager, totalFee); + + // 4. Expect events for both withdrawals + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey1, 1 ether, feePerValidator); + + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorWithdrawalSubmitted(publicKey2, 1 ether, feePerValidator); + + // 5. Call withdrawValidators with combined data + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_withdrawValidators_multipleValidators"); + vault.withdrawValidators{value: totalFee}(combinedData, ""); + _stopSnapshotGas(); + } + + // Test successful validator consolidation by validator manager + function test_consolidateValidators_byManager() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); + + // Register a second validator to use as destination (must be tracked to avoid oracle requirement) + bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // Call consolidateValidators from validatorsManager + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_byManager"); + vault.consolidateValidators{value: consolidationFee}(consolidationData, "", ""); + _stopSnapshotGas(); + } + + // Test validator consolidation with manager signature + function test_consolidateValidators_withSignature() public { + // First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); + + // Register a second validator to use as destination (must be tracked) + bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create validator manager signature + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), bytes32(vault.validatorsManagerNonce()), consolidationData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(validatorsManagerPrivateKey, message); + bytes memory signature = abi.encodePacked(r, s, v); + + // Record current nonce + uint256 currentNonce = vault.validatorsManagerNonce(); + + // Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(nonManager, consolidationFee); + + // Call consolidateValidators from non-manager with valid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_withSignature"); + vault.consolidateValidators{value: consolidationFee}(consolidationData, signature, ""); + _stopSnapshotGas(); + + // Verify nonce was incremented + assertEq(vault.validatorsManagerNonce(), currentNonce + 1, "Validators manager nonce should be incremented"); + } + + // Test validator consolidation with oracle signatures + function test_consolidateValidators_withOracleSignatures() public { + // Register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, true); + + // Prepare consolidation data (to an untracked destination validator) + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory destPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // Create oracle signature using our known oracle private key + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256("ConsolidationsChecker"), + keccak256("1"), + block.chainid, + address(contracts.consolidationsChecker) + ) + ), + keccak256( + abi.encode( + keccak256("ConsolidationsChecker(address vault,bytes validators)"), + address(vault), + keccak256(consolidationData) + ) + ) + ) + ); + + // setup oracles + _startOracleImpersonate(address(contracts.keeper)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + bytes memory oracleSignatures = abi.encodePacked(r, s, v); + + // Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // Verify the destination validator is not tracked initially + assertFalse( + vault.v2Validators(keccak256(destPublicKey)), "Destination validator should not be tracked initially" + ); + + // Call consolidateValidators with oracle signatures + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_withOracleSignatures"); + vault.consolidateValidators{value: consolidationFee}(consolidationData, "", oracleSignatures); + _stopSnapshotGas(); + + // Verify the destination validator is now tracked + assertTrue( + vault.v2Validators(keccak256(destPublicKey)), + "Destination validator should be tracked after consolidation with oracle approval" + ); + + _stopOracleImpersonate(address(contracts.keeper)); + } + + // Test failure when called by non-manager without signature + function test_consolidateValidators_notManager() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory destPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(nonManager, consolidationFee); + + // 4. Call consolidateValidators from non-manager without signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_notManager"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.consolidateValidators{value: consolidationFee}(consolidationData, "", ""); + _stopSnapshotGas(); + } + + // Test failure with invalid signature + function test_consolidateValidators_invalidSignature() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory destPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Create invalid signature (wrong signer) + (, uint256 wrongPrivateKey) = makeAddrAndKey("wrong"); + bytes32 message = _getValidatorsManagerSigningMessage( + address(vault), bytes32(vault.validatorsManagerNonce()), consolidationData + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wrongPrivateKey, message); + bytes memory invalidSignature = abi.encodePacked(r, s, v); + + // 4. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(nonManager, consolidationFee); + + // 5. Call consolidateValidators with invalid signature + vm.prank(nonManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_invalidSignature"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.consolidateValidators{value: consolidationFee}(consolidationData, invalidSignature, ""); + _stopSnapshotGas(); + } + + // Test failure with invalid validators data + function test_consolidateValidators_invalidValidators() public { + _collateralizeEthVault(address(vault)); + + // 1. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // 2. Create empty validators data + bytes memory emptyValidatorsData = new bytes(0); + + // 3. Call consolidateValidators with empty validators data + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.consolidateValidators{value: consolidationFee}(emptyValidatorsData, "", ""); + _stopSnapshotGas(); + + // 4. Test with invalid length (not a multiple of _validatorConsolidationLength) + // For consolidation, _validatorConsolidationLength is 96 (48 bytes sourcePublicKey + 48 bytes destPublicKey) + bytes memory invalidLengthData = new bytes(50); // Not a multiple of 96 + + // 5. Call consolidateValidators with invalid length data + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_invalidValidatorsLength"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.consolidateValidators{value: consolidationFee}(invalidLengthData, "", ""); + _stopSnapshotGas(); + } + + // Test failure for untracked destination without oracle approval + function test_consolidateValidators_untrackedDestination() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data with untracked destination + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory destPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Verify destination is not tracked + assertFalse( + vault.v2Validators(keccak256(destPublicKey)), "Destination validator should not be tracked initially" + ); + + // 4. Set up the consolidation fee + uint256 consolidationFee = 0.1 ether; + vm.deal(validatorsManager, consolidationFee); + + // 5. Attempt consolidation without oracle signatures + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_untrackedDestination"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.consolidateValidators{value: consolidationFee}(consolidationData, "", ""); + _stopSnapshotGas(); + } + + // Test fee handling and refunds + function test_consolidateValidators_feeHandling() public { + // 1. First register a validator to make it tracked + _depositToVault(address(vault), validatorDeposit * 2, user, user); + bytes memory sourcePublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + + // 2. Prepare consolidation data (to another tracked validator) + bytes memory destPublicKey = _registerEthValidator(address(vault), validatorDeposit, false); + bytes memory consolidationData = bytes.concat(sourcePublicKey, destPublicKey); + + // 3. Set excess fee (more than needed) + uint256 actualFee = 0.1 ether; + uint256 excessFee = 0.5 ether; // Overpay + vm.deal(validatorsManager, excessFee); + + // 4. Record initial balance + uint256 initialBalance = validatorsManager.balance; + + // 5. Call consolidateValidators with excess fee + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_feeHandling"); + vault.consolidateValidators{value: excessFee}(consolidationData, "", ""); + _stopSnapshotGas(); + + // 6. Verify the correct fee was deducted and excess was refunded + uint256 finalBalance = validatorsManager.balance; + assertEq(finalBalance, initialBalance - actualFee, "Excess fee should be refunded"); + } + + // Test consolidating multiple validators in a single call + function test_consolidateValidators_multipleValidators() public { + vm.deal(user, 200 ether); + + // Register source validators + _depositToVault(address(vault), validatorDeposit * 3, user, user); + bytes memory sourcePublicKey1 = _registerEthValidator(address(vault), validatorDeposit, true); + bytes memory destPublicKey1 = _registerEthValidator(address(vault), validatorDeposit, false); + + // Consolidate the same validator + bytes memory sourcePublicKey2 = _registerEthValidator(address(vault), validatorDeposit, false); + + // Combine data for both consolidations + bytes memory consolidationData1 = bytes.concat(sourcePublicKey1, destPublicKey1); + bytes memory consolidationData2 = bytes.concat(sourcePublicKey2, sourcePublicKey2); + bytes memory combinedData = bytes.concat(consolidationData1, consolidationData2); + + // setup oracle + _stopOracleImpersonate(address(contracts.keeper)); + + // Set fee for two consolidations + uint256 feePerConsolidation = 0.1 ether; + uint256 totalFee = feePerConsolidation * 2; + vm.deal(validatorsManager, totalFee); + + // Call consolidateValidators with multiple validators + vm.prank(validatorsManager); + _startSnapshotGas("VaultValidatorsTest_test_consolidateValidators_multipleValidators"); + vault.consolidateValidators{value: totalFee}(combinedData, "", ""); + _stopSnapshotGas(); + + // remove oracle + _stopOracleImpersonate(address(contracts.keeper)); + } } diff --git a/test/VaultVersion.t.sol b/test/VaultVersion.t.sol index b666e4cf..04e8b441 100644 --- a/test/VaultVersion.t.sol +++ b/test/VaultVersion.t.sol @@ -1,283 +1,283 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Test} from '../lib/forge-std/src/Test.sol'; -import {IEthVault} from '../contracts/interfaces/IEthVault.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; -import {EthVaultV6Mock} from '../contracts/mocks/EthVaultV6Mock.sol'; -import {EthVaultV7Mock} from '../contracts/mocks/EthVaultV7Mock.sol'; -import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; -import {EthVault} from '../contracts/vaults/ethereum/EthVault.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Test} from "../lib/forge-std/src/Test.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthVaultV6Mock} from "../contracts/mocks/EthVaultV6Mock.sol"; +import {EthVaultV7Mock} from "../contracts/mocks/EthVaultV7Mock.sol"; +import {VaultsRegistry} from "../contracts/vaults/VaultsRegistry.sol"; +import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; contract VaultVersionTest is Test, EthHelpers { - ForkContracts public contracts; - EthVault public vault; - VaultsRegistry public vaultsRegistry; - - address public admin; - address public user; - - bytes32 public ethVaultId; - bytes32 public ethPrivVaultId; - - address public mockImplV6; - address public mockImplV7; - address public ethPrivVaultImpl; - - function setUp() public { - // Set up contracts - contracts = _activateEthereumFork(); - vaultsRegistry = contracts.vaultsRegistry; - - // Set up accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - vm.deal(admin, 100 ether); - vm.deal(user, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IEthVault.EthVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); - vault = EthVault(payable(vaultAddr)); - - // Deploy mock implementations for testing upgrades - IEthVault.EthVaultConstructorArgs memory args = IEthVault.EthVaultConstructorArgs( - address(contracts.keeper), - address(vaultsRegistry), - address(contracts.validatorsRegistry), - address(_validatorsWithdrawals), - address(_validatorsConsolidations), - address(contracts.consolidationsChecker), - address(contracts.osTokenVaultController), - address(contracts.osTokenConfig), - address(contracts.osTokenVaultEscrow), - address(contracts.sharedMevEscrow), - _depositDataRegistry, - uint64(_exitingAssetsClaimDelay) - ); - - mockImplV6 = address(new EthVaultV6Mock(args)); - mockImplV7 = address(new EthVaultV7Mock(args)); - - // Get vault IDs - ethVaultId = vault.vaultId(); - ethPrivVaultId = keccak256('EthPrivVault'); - - // Deploy EthPrivVault implementation for testing vault ID checks - ethPrivVaultImpl = _getOrCreateVaultImpl(VaultType.EthPrivVault); - - // Add implementations to registry - vm.startPrank(vaultsRegistry.owner()); - vaultsRegistry.addVaultImpl(mockImplV6); - vaultsRegistry.addVaultImpl(mockImplV7); - vm.stopPrank(); - } - - function test_initialVersion() public view { - // Test that the initial version is correct - assertEq(vault.version(), 5, 'Initial version should be 5'); - } - - function test_implementation() public view { - // Test that the implementation address is correct - address impl = vault.implementation(); - assertTrue(impl != address(0), 'Implementation address should not be zero'); - assertEq(EthVault(payable(impl)).version(), 5, 'Implementation version should be 5'); - } - - function test_vaultId() public view { - // Test that vaultId returns the correct value - assertEq(vault.vaultId(), ethVaultId, 'Vault ID should be correct'); - assertEq(ethVaultId, keccak256('EthVault'), 'Vault ID should match expected value'); - } - - function test_upgradeToNextVersion() public { - // Test upgrading to the next version - bytes memory callData = abi.encode(uint128(100)); // Data for initializing V6 - - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeToNextVersion'); - vault.upgradeToAndCall(mockImplV6, callData); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify upgrade was successful - assertEq(vault.version(), 6, 'Version should be updated to 6'); - assertEq(vault.implementation(), mockImplV6, 'Implementation should be updated'); - - // Check that the new functionality is available - EthVaultV6Mock v6Vault = EthVaultV6Mock(payable(address(vault))); - assertEq(v6Vault.newVar(), 100, 'New variable should be initialized'); - assertTrue(v6Vault.somethingNew(), 'New function should be available'); - } - - function test_upgradeToSameVersionFails() public { - // Test that upgrading to the same version fails - address currentImpl = vault.implementation(); - - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeToSameVersionFails'); - vm.expectRevert(Errors.UpgradeFailed.selector); - vault.upgradeToAndCall(currentImpl, '0x'); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - assertEq(vault.implementation(), currentImpl, 'Implementation should remain unchanged'); - } - - function test_upgradeToSkipVersionFails() public { - // Test that skipping a version fails (going from V5 to V7) - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeToSkipVersionFails'); - vm.expectRevert(Errors.UpgradeFailed.selector); - vault.upgradeToAndCall(mockImplV7, '0x'); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - } - - function test_upgradeToDifferentVaultIdFails() public { - // Test that upgrading to an implementation with a different vault ID fails - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeToDifferentVaultIdFails'); - vm.expectRevert(Errors.UpgradeFailed.selector); - vault.upgradeToAndCall(ethPrivVaultImpl, '0x'); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - } - - function test_upgradeNonAdminFails() public { - // Test that non-admin cannot upgrade - vm.startPrank(user); - _startSnapshotGas('VaultVersionTest_test_upgradeNonAdminFails'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.upgradeToAndCall(mockImplV6, '0x'); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - } - - function test_upgradeToZeroAddressFails() public { - // Test that upgrading to zero address fails - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeToZeroAddressFails'); - vm.expectRevert(Errors.UpgradeFailed.selector); - vault.upgradeToAndCall(address(0), '0x'); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - } - - function test_upgradeToUnapprovedImplementationFails() public { - // Deploy a new implementation that's not in the registry - IEthVault.EthVaultConstructorArgs memory args = IEthVault.EthVaultConstructorArgs( - address(contracts.keeper), - address(vaultsRegistry), - address(contracts.validatorsRegistry), - address(_validatorsWithdrawals), - address(_validatorsConsolidations), - address(contracts.consolidationsChecker), - address(contracts.osTokenVaultController), - address(contracts.osTokenConfig), - address(contracts.osTokenVaultEscrow), - address(contracts.sharedMevEscrow), - _depositDataRegistry, - uint64(_exitingAssetsClaimDelay) - ); - - address unapprovedImpl = address(new EthVaultV6Mock(args)); - - // Test that upgrading to an unapproved implementation fails - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeToUnapprovedImplementationFails'); - vm.expectRevert(Errors.UpgradeFailed.selector); - vault.upgradeToAndCall(unapprovedImpl, '0x'); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - } - - function test_vaultIdPreservedAfterUpgrade() public { - // Test that the vault ID is preserved after an upgrade - bytes memory callData = abi.encode(uint128(100)); - - vm.prank(admin); - vault.upgradeToAndCall(mockImplV6, callData); - - // Verify vault ID remains unchanged - assertEq(vault.vaultId(), ethVaultId, 'Vault ID should remain unchanged after upgrade'); - } - - function test_upgradeWithInvalidCallDataFails() public { - // Test that upgrading with invalid call data fails - bytes memory invalidCallData = abi.encode(type(uint256).max); // V6 expects uint128 - - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeWithInvalidCallDataFails'); - vm.expectRevert(); - vault.upgradeToAndCall(mockImplV6, invalidCallData); - _stopSnapshotGas(); - vm.stopPrank(); - - // Verify no changes - assertEq(vault.version(), 5, 'Version should remain 5'); - } - - function test_upgradeMultipleSteps() public { - // Test upgrading through multiple versions - bytes memory callDataV6 = abi.encode(uint128(100)); - - // First upgrade to V6 - vm.prank(admin); - vault.upgradeToAndCall(mockImplV6, callDataV6); - assertEq(vault.version(), 6, 'Version should be 6 after first upgrade'); - - // Now upgrade to V7 - vm.prank(admin); - _startSnapshotGas('VaultVersionTest_test_upgradeMultipleSteps'); - vault.upgradeToAndCall(mockImplV7, '0x'); - _stopSnapshotGas(); - - // Verify second upgrade - assertEq(vault.version(), 7, 'Version should be 7 after second upgrade'); - assertEq(vault.implementation(), mockImplV7, 'Implementation should be V7'); - } - - function test_reinitializeFails() public { - // Test that reinitializing fails after upgrade - bytes memory callData = abi.encode(uint128(100)); - - // Upgrade to V6 - vm.prank(admin); - vault.upgradeToAndCall(mockImplV6, callData); - - // Try to initialize again - vm.startPrank(admin); - _startSnapshotGas('VaultVersionTest_test_reinitializeFails'); - vm.expectRevert(Initializable.InvalidInitialization.selector); - EthVaultV6Mock(payable(address(vault))).initialize(callData); - _stopSnapshotGas(); - vm.stopPrank(); - } + ForkContracts public contracts; + EthVault public vault; + VaultsRegistry public vaultsRegistry; + + address public admin; + address public user; + + bytes32 public ethVaultId; + bytes32 public ethPrivVaultId; + + address public mockImplV6; + address public mockImplV7; + address public ethPrivVaultImpl; + + function setUp() public { + // Set up contracts + contracts = _activateEthereumFork(); + vaultsRegistry = contracts.vaultsRegistry; + + // Set up accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + vm.deal(admin, 100 ether); + vm.deal(user, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Deploy mock implementations for testing upgrades + IEthVault.EthVaultConstructorArgs memory args = IEthVault.EthVaultConstructorArgs( + address(contracts.keeper), + address(vaultsRegistry), + address(contracts.validatorsRegistry), + address(_validatorsWithdrawals), + address(_validatorsConsolidations), + address(contracts.consolidationsChecker), + address(contracts.osTokenVaultController), + address(contracts.osTokenConfig), + address(contracts.osTokenVaultEscrow), + address(contracts.sharedMevEscrow), + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + mockImplV6 = address(new EthVaultV6Mock(args)); + mockImplV7 = address(new EthVaultV7Mock(args)); + + // Get vault IDs + ethVaultId = vault.vaultId(); + ethPrivVaultId = keccak256("EthPrivVault"); + + // Deploy EthPrivVault implementation for testing vault ID checks + ethPrivVaultImpl = _getOrCreateVaultImpl(VaultType.EthPrivVault); + + // Add implementations to registry + vm.startPrank(vaultsRegistry.owner()); + vaultsRegistry.addVaultImpl(mockImplV6); + vaultsRegistry.addVaultImpl(mockImplV7); + vm.stopPrank(); + } + + function test_initialVersion() public view { + // Test that the initial version is correct + assertEq(vault.version(), 5, "Initial version should be 5"); + } + + function test_implementation() public view { + // Test that the implementation address is correct + address impl = vault.implementation(); + assertTrue(impl != address(0), "Implementation address should not be zero"); + assertEq(EthVault(payable(impl)).version(), 5, "Implementation version should be 5"); + } + + function test_vaultId() public view { + // Test that vaultId returns the correct value + assertEq(vault.vaultId(), ethVaultId, "Vault ID should be correct"); + assertEq(ethVaultId, keccak256("EthVault"), "Vault ID should match expected value"); + } + + function test_upgradeToNextVersion() public { + // Test upgrading to the next version + bytes memory callData = abi.encode(uint128(100)); // Data for initializing V6 + + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeToNextVersion"); + vault.upgradeToAndCall(mockImplV6, callData); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify upgrade was successful + assertEq(vault.version(), 6, "Version should be updated to 6"); + assertEq(vault.implementation(), mockImplV6, "Implementation should be updated"); + + // Check that the new functionality is available + EthVaultV6Mock v6Vault = EthVaultV6Mock(payable(address(vault))); + assertEq(v6Vault.newVar(), 100, "New variable should be initialized"); + assertTrue(v6Vault.somethingNew(), "New function should be available"); + } + + function test_upgradeToSameVersionFails() public { + // Test that upgrading to the same version fails + address currentImpl = vault.implementation(); + + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeToSameVersionFails"); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(currentImpl, "0x"); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + assertEq(vault.implementation(), currentImpl, "Implementation should remain unchanged"); + } + + function test_upgradeToSkipVersionFails() public { + // Test that skipping a version fails (going from V5 to V7) + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeToSkipVersionFails"); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(mockImplV7, "0x"); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + } + + function test_upgradeToDifferentVaultIdFails() public { + // Test that upgrading to an implementation with a different vault ID fails + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeToDifferentVaultIdFails"); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(ethPrivVaultImpl, "0x"); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + } + + function test_upgradeNonAdminFails() public { + // Test that non-admin cannot upgrade + vm.startPrank(user); + _startSnapshotGas("VaultVersionTest_test_upgradeNonAdminFails"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.upgradeToAndCall(mockImplV6, "0x"); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + } + + function test_upgradeToZeroAddressFails() public { + // Test that upgrading to zero address fails + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeToZeroAddressFails"); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(address(0), "0x"); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + } + + function test_upgradeToUnapprovedImplementationFails() public { + // Deploy a new implementation that's not in the registry + IEthVault.EthVaultConstructorArgs memory args = IEthVault.EthVaultConstructorArgs( + address(contracts.keeper), + address(vaultsRegistry), + address(contracts.validatorsRegistry), + address(_validatorsWithdrawals), + address(_validatorsConsolidations), + address(contracts.consolidationsChecker), + address(contracts.osTokenVaultController), + address(contracts.osTokenConfig), + address(contracts.osTokenVaultEscrow), + address(contracts.sharedMevEscrow), + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + address unapprovedImpl = address(new EthVaultV6Mock(args)); + + // Test that upgrading to an unapproved implementation fails + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeToUnapprovedImplementationFails"); + vm.expectRevert(Errors.UpgradeFailed.selector); + vault.upgradeToAndCall(unapprovedImpl, "0x"); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + } + + function test_vaultIdPreservedAfterUpgrade() public { + // Test that the vault ID is preserved after an upgrade + bytes memory callData = abi.encode(uint128(100)); + + vm.prank(admin); + vault.upgradeToAndCall(mockImplV6, callData); + + // Verify vault ID remains unchanged + assertEq(vault.vaultId(), ethVaultId, "Vault ID should remain unchanged after upgrade"); + } + + function test_upgradeWithInvalidCallDataFails() public { + // Test that upgrading with invalid call data fails + bytes memory invalidCallData = abi.encode(type(uint256).max); // V6 expects uint128 + + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeWithInvalidCallDataFails"); + vm.expectRevert(); + vault.upgradeToAndCall(mockImplV6, invalidCallData); + _stopSnapshotGas(); + vm.stopPrank(); + + // Verify no changes + assertEq(vault.version(), 5, "Version should remain 5"); + } + + function test_upgradeMultipleSteps() public { + // Test upgrading through multiple versions + bytes memory callDataV6 = abi.encode(uint128(100)); + + // First upgrade to V6 + vm.prank(admin); + vault.upgradeToAndCall(mockImplV6, callDataV6); + assertEq(vault.version(), 6, "Version should be 6 after first upgrade"); + + // Now upgrade to V7 + vm.prank(admin); + _startSnapshotGas("VaultVersionTest_test_upgradeMultipleSteps"); + vault.upgradeToAndCall(mockImplV7, "0x"); + _stopSnapshotGas(); + + // Verify second upgrade + assertEq(vault.version(), 7, "Version should be 7 after second upgrade"); + assertEq(vault.implementation(), mockImplV7, "Implementation should be V7"); + } + + function test_reinitializeFails() public { + // Test that reinitializing fails after upgrade + bytes memory callData = abi.encode(uint128(100)); + + // Upgrade to V6 + vm.prank(admin); + vault.upgradeToAndCall(mockImplV6, callData); + + // Try to initialize again + vm.startPrank(admin); + _startSnapshotGas("VaultVersionTest_test_reinitializeFails"); + vm.expectRevert(Initializable.InvalidInitialization.selector); + EthVaultV6Mock(payable(address(vault))).initialize(callData); + _stopSnapshotGas(); + vm.stopPrank(); + } } diff --git a/test/VaultsRegistry.t.sol b/test/VaultsRegistry.t.sol index 0abf5446..b5373223 100644 --- a/test/VaultsRegistry.t.sol +++ b/test/VaultsRegistry.t.sol @@ -1,292 +1,283 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {VaultsRegistry} from '../contracts/vaults/VaultsRegistry.sol'; -import {IVaultsRegistry} from '../contracts/interfaces/IVaultsRegistry.sol'; -import {EthHelpers} from './helpers/EthHelpers.sol'; -import {Errors} from '../contracts/libraries/Errors.sol'; +import {Test} from "forge-std/Test.sol"; +import {VaultsRegistry} from "../contracts/vaults/VaultsRegistry.sol"; +import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; contract VaultsRegistryTest is Test, EthHelpers { - ForkContracts public contracts; - VaultsRegistry public registry; - - address public owner; - address public nonOwner; - address public mockFactory; - address public mockVaultImpl; - address public mockVault; - - function setUp() public { - // Activate Ethereum fork and get the contracts - contracts = _activateEthereumFork(); - registry = contracts.vaultsRegistry; - - // Set up test accounts - owner = makeAddr('owner'); - nonOwner = makeAddr('nonOwner'); - mockFactory = makeAddr('mockFactory'); - mockVaultImpl = makeAddr('mockVaultImpl'); - mockVault = makeAddr('mockVault'); - - // Since the registry is already deployed on the fork, we need to - // impersonate its owner to perform ownership-restricted actions - vm.startPrank(registry.owner()); - // Transfer ownership to our test owner - registry.transferOwnership(owner); - vm.stopPrank(); - - // Accept ownership - vm.prank(owner); - registry.acceptOwnership(); - } - - function test_initialState() public view { - // Verify the initial state of the registry - assertEq(registry.owner(), owner, 'Registry owner should be set'); - assertFalse(registry.factories(mockFactory), 'Mock factory should not be registered initially'); - assertFalse( - registry.vaultImpls(mockVaultImpl), - 'Mock vault impl should not be registered initially' - ); - assertFalse(registry.vaults(mockVault), 'Mock vault should not be registered initially'); - } - - function test_addFactory() public { - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_addFactory'); - vm.expectEmit(true, false, false, false); - emit IVaultsRegistry.FactoryAdded(mockFactory); - registry.addFactory(mockFactory); - _stopSnapshotGas(); - - assertTrue(registry.factories(mockFactory), 'Factory should be registered'); - } - - function test_removeFactory() public { - // First, add the factory - vm.prank(owner); - registry.addFactory(mockFactory); - assertTrue(registry.factories(mockFactory), 'Factory should be registered'); - - // Now remove it - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_removeFactory'); - vm.expectEmit(true, false, false, false); - emit IVaultsRegistry.FactoryRemoved(mockFactory); - registry.removeFactory(mockFactory); - _stopSnapshotGas(); - - assertFalse(registry.factories(mockFactory), 'Factory should be removed'); - } - - function test_addVaultImpl() public { - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_addVaultImpl'); - vm.expectEmit(true, false, false, false); - emit IVaultsRegistry.VaultImplAdded(mockVaultImpl); - registry.addVaultImpl(mockVaultImpl); - _stopSnapshotGas(); - - assertTrue(registry.vaultImpls(mockVaultImpl), 'Vault implementation should be registered'); - } - - function test_removeVaultImpl() public { - // First, add the vault implementation - vm.prank(owner); - registry.addVaultImpl(mockVaultImpl); - assertTrue(registry.vaultImpls(mockVaultImpl), 'Vault implementation should be registered'); - - // Now remove it - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_removeVaultImpl'); - vm.expectEmit(true, false, false, false); - emit IVaultsRegistry.VaultImplRemoved(mockVaultImpl); - registry.removeVaultImpl(mockVaultImpl); - _stopSnapshotGas(); - - assertFalse(registry.vaultImpls(mockVaultImpl), 'Vault implementation should be removed'); - } - - function test_addVault() public { - // First, add the factory - vm.prank(owner); - registry.addFactory(mockFactory); - - // Add vault as factory - vm.prank(mockFactory); - _startSnapshotGas('VaultsRegistryTest_test_addVault'); - vm.expectEmit(true, true, false, false); - emit IVaultsRegistry.VaultAdded(mockFactory, mockVault); - registry.addVault(mockVault); - _stopSnapshotGas(); - - assertTrue(registry.vaults(mockVault), 'Vault should be registered'); - } - - function test_addVault_asOwner() public { - // Add vault as owner - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_addVault_asOwner'); - vm.expectEmit(true, true, false, false); - emit IVaultsRegistry.VaultAdded(owner, mockVault); - registry.addVault(mockVault); - _stopSnapshotGas(); - - assertTrue(registry.vaults(mockVault), 'Vault should be registered'); - } - - function test_initialize() public { - // Deploy a new VaultsRegistry contract to test initialization - VaultsRegistry newRegistry = new VaultsRegistry(); - - address newOwner = makeAddr('newOwner'); - - vm.prank(newRegistry.owner()); - _startSnapshotGas('VaultsRegistryTest_test_initialize'); - newRegistry.initialize(newOwner); - _stopSnapshotGas(); - - assertEq(newRegistry.owner(), newOwner, 'Owner should be set after initialization'); - } - - // Access control tests - - function test_addFactory_notOwner() public { - vm.prank(nonOwner); - _startSnapshotGas('VaultsRegistryTest_test_addFactory_notOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - registry.addFactory(mockFactory); - _stopSnapshotGas(); - - assertFalse(registry.factories(mockFactory), 'Factory should not be registered'); - } - - function test_removeFactory_notOwner() public { - // First, add the factory - vm.prank(owner); - registry.addFactory(mockFactory); - - vm.prank(nonOwner); - _startSnapshotGas('VaultsRegistryTest_test_removeFactory_notOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - registry.removeFactory(mockFactory); - _stopSnapshotGas(); - - assertTrue(registry.factories(mockFactory), 'Factory should still be registered'); - } - - function test_addVaultImpl_notOwner() public { - vm.prank(nonOwner); - _startSnapshotGas('VaultsRegistryTest_test_addVaultImpl_notOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - registry.addVaultImpl(mockVaultImpl); - _stopSnapshotGas(); - - assertFalse( - registry.vaultImpls(mockVaultImpl), - 'Vault implementation should not be registered' - ); - } - - function test_removeVaultImpl_notOwner() public { - // First, add the vault implementation - vm.prank(owner); - registry.addVaultImpl(mockVaultImpl); - - vm.prank(nonOwner); - _startSnapshotGas('VaultsRegistryTest_test_removeVaultImpl_notOwner'); - vm.expectRevert(abi.encodeWithSignature('OwnableUnauthorizedAccount(address)', nonOwner)); - registry.removeVaultImpl(mockVaultImpl); - _stopSnapshotGas(); - - assertTrue( - registry.vaultImpls(mockVaultImpl), - 'Vault implementation should still be registered' - ); - } - - function test_addVault_notFactoryOrOwner() public { - vm.prank(nonOwner); - _startSnapshotGas('VaultsRegistryTest_test_addVault_notFactoryOrOwner'); - vm.expectRevert(Errors.AccessDenied.selector); - registry.addVault(mockVault); - _stopSnapshotGas(); - - assertFalse(registry.vaults(mockVault), 'Vault should not be registered'); - } - - function test_initialize_alreadyInitialized() public { - // Create a new registry and initialize it once - VaultsRegistry newRegistry = new VaultsRegistry(); - - address newOwner = makeAddr('newOwner'); - address anotherOwner = makeAddr('anotherOwner'); - - vm.prank(newRegistry.owner()); - newRegistry.initialize(newOwner); - - // Try to initialize again, should fail - vm.prank(newOwner); - _startSnapshotGas('VaultsRegistryTest_test_initialize_alreadyInitialized'); - vm.expectRevert(Errors.AccessDenied.selector); - newRegistry.initialize(anotherOwner); - _stopSnapshotGas(); - - assertEq(newRegistry.owner(), newOwner, 'Owner should not have changed'); - } - - function test_initialize_zeroAddress() public { - VaultsRegistry newRegistry = new VaultsRegistry(); - - vm.prank(newRegistry.owner()); - _startSnapshotGas('VaultsRegistryTest_test_initialize_zeroAddress'); - vm.expectRevert(Errors.ZeroAddress.selector); - newRegistry.initialize(address(0)); - _stopSnapshotGas(); - } - - function test_addFactory_alreadyAdded() public { - // Add factory first time - vm.prank(owner); - registry.addFactory(mockFactory); - - // Try to add again - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_addFactory_alreadyAdded'); - vm.expectRevert(Errors.AlreadyAdded.selector); - registry.addFactory(mockFactory); - _stopSnapshotGas(); - } - - function test_removeFactory_alreadyRemoved() public { - // Try to remove factory that isn't registered - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_removeFactory_alreadyRemoved'); - vm.expectRevert(Errors.AlreadyRemoved.selector); - registry.removeFactory(mockFactory); - _stopSnapshotGas(); - } - - function test_addVaultImpl_alreadyAdded() public { - // Add vault implementation first time - vm.prank(owner); - registry.addVaultImpl(mockVaultImpl); - - // Try to add again - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_addVaultImpl_alreadyAdded'); - vm.expectRevert(Errors.AlreadyAdded.selector); - registry.addVaultImpl(mockVaultImpl); - _stopSnapshotGas(); - } - - function test_removeVaultImpl_alreadyRemoved() public { - // Try to remove vault implementation that isn't registered - vm.prank(owner); - _startSnapshotGas('VaultsRegistryTest_test_removeVaultImpl_alreadyRemoved'); - vm.expectRevert(Errors.AlreadyRemoved.selector); - registry.removeVaultImpl(mockVaultImpl); - _stopSnapshotGas(); - } + ForkContracts public contracts; + VaultsRegistry public registry; + + address public owner; + address public nonOwner; + address public mockFactory; + address public mockVaultImpl; + address public mockVault; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + registry = contracts.vaultsRegistry; + + // Set up test accounts + owner = makeAddr("owner"); + nonOwner = makeAddr("nonOwner"); + mockFactory = makeAddr("mockFactory"); + mockVaultImpl = makeAddr("mockVaultImpl"); + mockVault = makeAddr("mockVault"); + + // Since the registry is already deployed on the fork, we need to + // impersonate its owner to perform ownership-restricted actions + vm.startPrank(registry.owner()); + // Transfer ownership to our test owner + registry.transferOwnership(owner); + vm.stopPrank(); + + // Accept ownership + vm.prank(owner); + registry.acceptOwnership(); + } + + function test_initialState() public view { + // Verify the initial state of the registry + assertEq(registry.owner(), owner, "Registry owner should be set"); + assertFalse(registry.factories(mockFactory), "Mock factory should not be registered initially"); + assertFalse(registry.vaultImpls(mockVaultImpl), "Mock vault impl should not be registered initially"); + assertFalse(registry.vaults(mockVault), "Mock vault should not be registered initially"); + } + + function test_addFactory() public { + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_addFactory"); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.FactoryAdded(mockFactory); + registry.addFactory(mockFactory); + _stopSnapshotGas(); + + assertTrue(registry.factories(mockFactory), "Factory should be registered"); + } + + function test_removeFactory() public { + // First, add the factory + vm.prank(owner); + registry.addFactory(mockFactory); + assertTrue(registry.factories(mockFactory), "Factory should be registered"); + + // Now remove it + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_removeFactory"); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.FactoryRemoved(mockFactory); + registry.removeFactory(mockFactory); + _stopSnapshotGas(); + + assertFalse(registry.factories(mockFactory), "Factory should be removed"); + } + + function test_addVaultImpl() public { + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_addVaultImpl"); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.VaultImplAdded(mockVaultImpl); + registry.addVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertTrue(registry.vaultImpls(mockVaultImpl), "Vault implementation should be registered"); + } + + function test_removeVaultImpl() public { + // First, add the vault implementation + vm.prank(owner); + registry.addVaultImpl(mockVaultImpl); + assertTrue(registry.vaultImpls(mockVaultImpl), "Vault implementation should be registered"); + + // Now remove it + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_removeVaultImpl"); + vm.expectEmit(true, false, false, false); + emit IVaultsRegistry.VaultImplRemoved(mockVaultImpl); + registry.removeVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertFalse(registry.vaultImpls(mockVaultImpl), "Vault implementation should be removed"); + } + + function test_addVault() public { + // First, add the factory + vm.prank(owner); + registry.addFactory(mockFactory); + + // Add vault as factory + vm.prank(mockFactory); + _startSnapshotGas("VaultsRegistryTest_test_addVault"); + vm.expectEmit(true, true, false, false); + emit IVaultsRegistry.VaultAdded(mockFactory, mockVault); + registry.addVault(mockVault); + _stopSnapshotGas(); + + assertTrue(registry.vaults(mockVault), "Vault should be registered"); + } + + function test_addVault_asOwner() public { + // Add vault as owner + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_addVault_asOwner"); + vm.expectEmit(true, true, false, false); + emit IVaultsRegistry.VaultAdded(owner, mockVault); + registry.addVault(mockVault); + _stopSnapshotGas(); + + assertTrue(registry.vaults(mockVault), "Vault should be registered"); + } + + function test_initialize() public { + // Deploy a new VaultsRegistry contract to test initialization + VaultsRegistry newRegistry = new VaultsRegistry(); + + address newOwner = makeAddr("newOwner"); + + vm.prank(newRegistry.owner()); + _startSnapshotGas("VaultsRegistryTest_test_initialize"); + newRegistry.initialize(newOwner); + _stopSnapshotGas(); + + assertEq(newRegistry.owner(), newOwner, "Owner should be set after initialization"); + } + + // Access control tests + + function test_addFactory_notOwner() public { + vm.prank(nonOwner); + _startSnapshotGas("VaultsRegistryTest_test_addFactory_notOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.addFactory(mockFactory); + _stopSnapshotGas(); + + assertFalse(registry.factories(mockFactory), "Factory should not be registered"); + } + + function test_removeFactory_notOwner() public { + // First, add the factory + vm.prank(owner); + registry.addFactory(mockFactory); + + vm.prank(nonOwner); + _startSnapshotGas("VaultsRegistryTest_test_removeFactory_notOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.removeFactory(mockFactory); + _stopSnapshotGas(); + + assertTrue(registry.factories(mockFactory), "Factory should still be registered"); + } + + function test_addVaultImpl_notOwner() public { + vm.prank(nonOwner); + _startSnapshotGas("VaultsRegistryTest_test_addVaultImpl_notOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.addVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertFalse(registry.vaultImpls(mockVaultImpl), "Vault implementation should not be registered"); + } + + function test_removeVaultImpl_notOwner() public { + // First, add the vault implementation + vm.prank(owner); + registry.addVaultImpl(mockVaultImpl); + + vm.prank(nonOwner); + _startSnapshotGas("VaultsRegistryTest_test_removeVaultImpl_notOwner"); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.removeVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + + assertTrue(registry.vaultImpls(mockVaultImpl), "Vault implementation should still be registered"); + } + + function test_addVault_notFactoryOrOwner() public { + vm.prank(nonOwner); + _startSnapshotGas("VaultsRegistryTest_test_addVault_notFactoryOrOwner"); + vm.expectRevert(Errors.AccessDenied.selector); + registry.addVault(mockVault); + _stopSnapshotGas(); + + assertFalse(registry.vaults(mockVault), "Vault should not be registered"); + } + + function test_initialize_alreadyInitialized() public { + // Create a new registry and initialize it once + VaultsRegistry newRegistry = new VaultsRegistry(); + + address newOwner = makeAddr("newOwner"); + address anotherOwner = makeAddr("anotherOwner"); + + vm.prank(newRegistry.owner()); + newRegistry.initialize(newOwner); + + // Try to initialize again, should fail + vm.prank(newOwner); + _startSnapshotGas("VaultsRegistryTest_test_initialize_alreadyInitialized"); + vm.expectRevert(Errors.AccessDenied.selector); + newRegistry.initialize(anotherOwner); + _stopSnapshotGas(); + + assertEq(newRegistry.owner(), newOwner, "Owner should not have changed"); + } + + function test_initialize_zeroAddress() public { + VaultsRegistry newRegistry = new VaultsRegistry(); + + vm.prank(newRegistry.owner()); + _startSnapshotGas("VaultsRegistryTest_test_initialize_zeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + newRegistry.initialize(address(0)); + _stopSnapshotGas(); + } + + function test_addFactory_alreadyAdded() public { + // Add factory first time + vm.prank(owner); + registry.addFactory(mockFactory); + + // Try to add again + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_addFactory_alreadyAdded"); + vm.expectRevert(Errors.AlreadyAdded.selector); + registry.addFactory(mockFactory); + _stopSnapshotGas(); + } + + function test_removeFactory_alreadyRemoved() public { + // Try to remove factory that isn't registered + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_removeFactory_alreadyRemoved"); + vm.expectRevert(Errors.AlreadyRemoved.selector); + registry.removeFactory(mockFactory); + _stopSnapshotGas(); + } + + function test_addVaultImpl_alreadyAdded() public { + // Add vault implementation first time + vm.prank(owner); + registry.addVaultImpl(mockVaultImpl); + + // Try to add again + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_addVaultImpl_alreadyAdded"); + vm.expectRevert(Errors.AlreadyAdded.selector); + registry.addVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + } + + function test_removeVaultImpl_alreadyRemoved() public { + // Try to remove vault implementation that isn't registered + vm.prank(owner); + _startSnapshotGas("VaultsRegistryTest_test_removeVaultImpl_alreadyRemoved"); + vm.expectRevert(Errors.AlreadyRemoved.selector); + registry.removeVaultImpl(mockVaultImpl); + _stopSnapshotGas(); + } } diff --git a/test/gnosis/GnoBlocklistErc20Vault.t.sol b/test/gnosis/GnoBlocklistErc20Vault.t.sol index c7d1931d..0df685ce 100644 --- a/test/gnosis/GnoBlocklistErc20Vault.t.sol +++ b/test/gnosis/GnoBlocklistErc20Vault.t.sol @@ -1,345 +1,333 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; -import {GnoBlocklistErc20Vault} from '../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol'; +import {Test} from "forge-std/Test.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {IGnoErc20Vault} from "../../contracts/interfaces/IGnoErc20Vault.sol"; +import {GnoBlocklistErc20Vault} from "../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoBlocklistErc20VaultTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoBlocklistErc20Vault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public blocklistManager; - address public referrer = address(0); - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - blocklistManager = makeAddr('blocklistManager'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(other, 100 ether); - _mintGnoToken(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, false); - vault = GnoBlocklistErc20Vault(payable(_vault)); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('GnoBlocklistErc20Vault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 3); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_transfer() public { - uint256 amount = 1 ether; - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Transfer tokens - vm.prank(sender); - _startSnapshotGas('GnoBlocklistErc20VaultTest_test_transfer'); - vault.transfer(other, amount); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.balanceOf(sender), 0); - assertEq(vault.balanceOf(other), amount); - } - - function test_cannotTransferToBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Try to transfer to blocked user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotTransferFromBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Deposit GNO for both users - _depositGno(amount, sender, sender); - _depositGno(amount, other, other); - - // Block sender - vm.prank(blocklistManager); - vault.updateBlocklist(sender, true); - - // Try to transfer from blocked user to other - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotDepositFromBlockedSender() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit from blocked user - vm.startPrank(other); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, receiver, referrer); - vm.stopPrank(); - } - - function test_cannotDepositToBlockedReceiver() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, other, referrer); - vm.stopPrank(); - } - - function test_canDepositAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Deposit as non-blocked user - _startSnapshotGas('GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser'); - _depositGno(amount, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertEq(vault.balanceOf(receiver), amount); - } - - function test_cannotMintOsTokenFromBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Set blocklist manager and block sender - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(sender, true); - - // Try to mint osToken from blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Mint osToken as non-blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('GnoBlocklistErc20VaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, true); - _stopSnapshotGas(); - GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingAssets, - uint256 totalTickets, - ) = blocklistVault.getExitQueueData(); - assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); - assertEq(blocklistVault.version(), 3); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.totalShares(), _securityDeposit); - assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(queuedShares, 0); - assertEq(totalExitingAssets, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalTickets, 0); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(blocklistVault.totalSupply(), _securityDeposit); - assertEq(blocklistVault.symbol(), 'SW-GNO-1'); - assertEq(blocklistVault.name(), 'SW GNO Vault'); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault( - VaultType.GnoBlocklistErc20Vault, - admin, - initParams, - true - ); - GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); - - _depositToVault(address(blocklistVault), 15 ether, sender, sender); - _registerGnoValidator(address(blocklistVault), 1 ether, true); - - vm.prank(sender); - blocklistVault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = blocklistVault.totalShares(); - uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 senderBalanceBefore = blocklistVault.getShares(sender); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(blocklistVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV2(address(blocklistVault)).queuedShares(); - - assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); - assertEq(blocklistVault.version(), 2); - assertEq( - contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), - 0 - ); - - _startSnapshotGas('GnoBlocklistErc20VaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoBlocklistErc20Vault, address(blocklistVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); - assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistErc20Vault')); - assertEq(blocklistVault.version(), 3); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(queuedShares, queuedSharesBefore); - assertEq(blocklistVault.totalShares(), totalSharesBefore); - assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(blocklistVault.getShares(sender), senderBalanceBefore); - assertEq( - contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - assertEq(blocklistVault.totalSupply(), totalSharesBefore); - assertEq(blocklistVault.symbol(), 'SW-GNO-1'); - assertEq(blocklistVault.name(), 'SW GNO Vault'); - } - - // Helper function to deposit GNO to the vault - function _depositGno(uint256 amount, address from, address to) internal { - _depositToVault(address(vault), amount, from, to); - } + ForkContracts public contracts; + GnoBlocklistErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + blocklistManager = makeAddr("blocklistManager"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, false); + vault = GnoBlocklistErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("GnoBlocklistErc20Vault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 3); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_transfer() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas("GnoBlocklistErc20VaultTest_test_transfer"); + vault.transfer(other, amount); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(sender), 0); + assertEq(vault.balanceOf(other), amount); + } + + function test_cannotTransferToBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Try to transfer to blocked user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferFromBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit GNO for both users + _depositGno(amount, sender, sender); + _depositGno(amount, other, other); + + // Block sender + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to transfer from blocked user to other + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit as non-blocked user + _startSnapshotGas("GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser"); + _depositGno(amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertEq(vault.balanceOf(receiver), amount); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("GnoBlocklistErc20VaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); + + (uint128 queuedShares, uint128 unclaimedAssets, uint128 totalExitingAssets, uint256 totalTickets,) = + blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256("GnoBlocklistErc20Vault")); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(queuedShares, 0); + assertEq(totalExitingAssets, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalTickets, 0); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.totalSupply(), _securityDeposit); + assertEq(blocklistVault.symbol(), "SW-GNO-1"); + assertEq(blocklistVault.name(), "SW GNO Vault"); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoBlocklistErc20Vault, admin, initParams, true); + GnoBlocklistErc20Vault blocklistVault = GnoBlocklistErc20Vault(payable(_vault)); + + _depositToVault(address(blocklistVault), 15 ether, sender, sender); + _registerGnoValidator(address(blocklistVault), 1 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 senderBalanceBefore = blocklistVault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(blocklistVault)).queuedShares(); + + assertEq(blocklistVault.vaultId(), keccak256("GnoBlocklistErc20Vault")); + assertEq(blocklistVault.version(), 2); + assertEq(contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), 0); + + _startSnapshotGas("GnoBlocklistErc20VaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoBlocklistErc20Vault, address(blocklistVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256("GnoBlocklistErc20Vault")); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(queuedShares, queuedSharesBefore); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + assertEq(blocklistVault.totalSupply(), totalSharesBefore); + assertEq(blocklistVault.symbol(), "SW-GNO-1"); + assertEq(blocklistVault.name(), "SW GNO Vault"); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } } diff --git a/test/gnosis/GnoBlocklistVault.t.sol b/test/gnosis/GnoBlocklistVault.t.sol index b5fa9ef5..48ddaca5 100644 --- a/test/gnosis/GnoBlocklistVault.t.sol +++ b/test/gnosis/GnoBlocklistVault.t.sol @@ -1,262 +1,259 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {GnoBlocklistVault} from '../../contracts/vaults/gnosis/GnoBlocklistVault.sol'; +import {Test} from "forge-std/Test.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {GnoBlocklistVault} from "../../contracts/vaults/gnosis/GnoBlocklistVault.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoBlocklistVaultTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoBlocklistVault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public blocklistManager; - address public referrer = address(0); - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - blocklistManager = makeAddr('blocklistManager'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(other, 100 ether); - _mintGnoToken(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.GnoBlocklistVault, admin, initParams, false); - vault = GnoBlocklistVault(payable(_vault)); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_cannotDepositFromBlockedSender() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit from blocked user - vm.startPrank(other); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, receiver, referrer); - vm.stopPrank(); - } - - function test_cannotDepositToBlockedReceiver() public { - uint256 amount = 1 ether; - - // Set blocklist manager and block other - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(other, true); - - // Try to deposit to blocked receiver - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, other, referrer); - vm.stopPrank(); - } - - function test_canDepositAsNonBlockedUser() public { - uint256 assets = 1 ether; - uint256 shares = vault.convertToShares(assets); - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Deposit as non-blocked user - _startSnapshotGas('GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser'); - _depositGno(assets, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(receiver), shares, 1); - } - - function test_cannotMintOsTokenFromBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Set blocklist manager and block sender - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - vm.prank(blocklistManager); - vault.updateBlocklist(sender, true); - - // Try to mint osToken from blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsNonBlockedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Set blocklist manager - vm.prank(admin); - vault.setBlocklistManager(blocklistManager); - - // Mint osToken as non-blocked user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('GnoBlocklistVaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.GnoBlocklistVault, admin, initParams, false); - _stopSnapshotGas(); - GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = blocklistVault.getExitQueueData(); - - assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); - assertEq(blocklistVault.version(), 3); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.totalShares(), _securityDeposit); - assertEq(blocklistVault.totalAssets(), _securityDeposit); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.GnoBlocklistVault, admin, initParams, false); - GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); - - _depositToVault(address(blocklistVault), 15 ether, sender, sender); - _registerGnoValidator(address(blocklistVault), 1 ether, true); - - vm.prank(sender); - blocklistVault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = blocklistVault.totalShares(); - uint256 totalAssetsBefore = blocklistVault.totalAssets(); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(blocklistVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV2(address(blocklistVault)).queuedShares(); - uint256 senderBalanceBefore = blocklistVault.getShares(sender); - - assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); - assertEq(blocklistVault.version(), 2); - assertEq( - contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), - 0 - ); - - _startSnapshotGas('GnoBlocklistVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoBlocklistVault, address(blocklistVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = blocklistVault.getExitQueueData(); - assertEq(blocklistVault.vaultId(), keccak256('GnoBlocklistVault')); - assertEq(blocklistVault.version(), 3); - assertEq(blocklistVault.admin(), admin); - assertEq(blocklistVault.blocklistManager(), admin); - assertEq(blocklistVault.capacity(), 1000 ether); - assertEq(blocklistVault.feePercent(), 1000); - assertEq(blocklistVault.feeRecipient(), admin); - assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); - assertEq(blocklistVault.totalShares(), totalSharesBefore); - assertEq(blocklistVault.totalAssets(), totalAssetsBefore); - assertEq(blocklistVault.validatorsManagerNonce(), 0); - assertEq(blocklistVault.getShares(sender), senderBalanceBefore); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq( - contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - } - - // Helper function to deposit GNO to the vault - function _depositGno(uint256 amount, address from, address to) internal { - _depositToVault(address(vault), amount, from, to); - } + ForkContracts public contracts; + GnoBlocklistVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public blocklistManager; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + blocklistManager = makeAddr("blocklistManager"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoBlocklistVault, admin, initParams, false); + vault = GnoBlocklistVault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_cannotDepositFromBlockedSender() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit from blocked user + vm.startPrank(other); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToBlockedReceiver() public { + uint256 amount = 1 ether; + + // Set blocklist manager and block other + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(other, true); + + // Try to deposit to blocked receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, other, referrer); + vm.stopPrank(); + } + + function test_canDepositAsNonBlockedUser() public { + uint256 assets = 1 ether; + uint256 shares = vault.convertToShares(assets); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Deposit as non-blocked user + _startSnapshotGas("GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser"); + _depositGno(assets, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_cannotMintOsTokenFromBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager and block sender + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + vm.prank(blocklistManager); + vault.updateBlocklist(sender, true); + + // Try to mint osToken from blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsNonBlockedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Set blocklist manager + vm.prank(admin); + vault.setBlocklistManager(blocklistManager); + + // Mint osToken as non-blocked user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("GnoBlocklistVaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.GnoBlocklistVault, admin, initParams, false); + _stopSnapshotGas(); + GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = blocklistVault.getExitQueueData(); + + assertEq(blocklistVault.vaultId(), keccak256("GnoBlocklistVault")); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.totalShares(), _securityDeposit); + assertEq(blocklistVault.totalAssets(), _securityDeposit); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoBlocklistVault, admin, initParams, false); + GnoBlocklistVault blocklistVault = GnoBlocklistVault(payable(_vault)); + + _depositToVault(address(blocklistVault), 15 ether, sender, sender); + _registerGnoValidator(address(blocklistVault), 1 ether, true); + + vm.prank(sender); + blocklistVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = blocklistVault.totalShares(); + uint256 totalAssetsBefore = blocklistVault.totalAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(blocklistVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(blocklistVault)).queuedShares(); + uint256 senderBalanceBefore = blocklistVault.getShares(sender); + + assertEq(blocklistVault.vaultId(), keccak256("GnoBlocklistVault")); + assertEq(blocklistVault.version(), 2); + assertEq(contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), 0); + + _startSnapshotGas("GnoBlocklistVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoBlocklistVault, address(blocklistVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = blocklistVault.getExitQueueData(); + assertEq(blocklistVault.vaultId(), keccak256("GnoBlocklistVault")); + assertEq(blocklistVault.version(), 3); + assertEq(blocklistVault.admin(), admin); + assertEq(blocklistVault.blocklistManager(), admin); + assertEq(blocklistVault.capacity(), 1000 ether); + assertEq(blocklistVault.feePercent(), 1000); + assertEq(blocklistVault.feeRecipient(), admin); + assertEq(blocklistVault.validatorsManager(), _depositDataRegistry); + assertEq(blocklistVault.totalShares(), totalSharesBefore); + assertEq(blocklistVault.totalAssets(), totalAssetsBefore); + assertEq(blocklistVault.validatorsManagerNonce(), 0); + assertEq(blocklistVault.getShares(sender), senderBalanceBefore); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq( + contracts.gnoToken.allowance(address(blocklistVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } } diff --git a/test/gnosis/GnoErc20Vault.t.sol b/test/gnosis/GnoErc20Vault.t.sol index 391653cc..1f1372cb 100644 --- a/test/gnosis/GnoErc20Vault.t.sol +++ b/test/gnosis/GnoErc20Vault.t.sol @@ -1,376 +1,372 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {GnoErc20Vault} from '../../contracts/vaults/gnosis/GnoErc20Vault.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IGnoErc20Vault} from "../../contracts/interfaces/IGnoErc20Vault.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {GnoErc20Vault} from "../../contracts/vaults/gnosis/GnoErc20Vault.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoErc20VaultTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoErc20Vault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public referrer = address(0); - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(other, 100 ether); - _mintGnoToken(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.GnoErc20Vault, admin, initParams, false); - vault = GnoErc20Vault(payable(_vault)); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('GnoErc20VaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.GnoErc20Vault, admin, initParams, false); - _stopSnapshotGas(); - GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = erc20Vault.getExitQueueData(); - - assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); - assertEq(erc20Vault.version(), 3); - assertEq(erc20Vault.admin(), admin); - assertEq(erc20Vault.capacity(), 1000 ether); - assertEq(erc20Vault.feePercent(), 1000); - assertEq(erc20Vault.feeRecipient(), admin); - assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.totalShares(), _securityDeposit); - assertEq(erc20Vault.totalAssets(), _securityDeposit); - assertEq(erc20Vault.validatorsManagerNonce(), 0); - assertEq(erc20Vault.totalSupply(), _securityDeposit); - assertEq(erc20Vault.symbol(), 'SW-GNO-1'); - assertEq(erc20Vault.name(), 'SW GNO Vault'); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.GnoErc20Vault, admin, initParams, false); - GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); - - _depositToVault(address(erc20Vault), 15 ether, sender, sender); - _registerGnoValidator(address(erc20Vault), 1 ether, true); - - vm.prank(sender); - erc20Vault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = erc20Vault.totalShares(); - uint256 totalAssetsBefore = erc20Vault.totalAssets(); - uint256 senderBalanceBefore = erc20Vault.getShares(sender); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(erc20Vault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV2(address(erc20Vault)).queuedShares(); - - assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); - assertEq(erc20Vault.version(), 2); - assertEq( - contracts.gnoToken.allowance(address(erc20Vault), address(contracts.validatorsRegistry)), - 0 - ); - - _startSnapshotGas('GnoErc20VaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoErc20Vault, address(erc20Vault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = erc20Vault.getExitQueueData(); - assertEq(erc20Vault.vaultId(), keccak256('GnoErc20Vault')); - assertEq(erc20Vault.version(), 3); - assertEq(erc20Vault.admin(), admin); - assertEq(erc20Vault.capacity(), 1000 ether); - assertEq(erc20Vault.feePercent(), 1000); - assertEq(erc20Vault.feeRecipient(), admin); - assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(erc20Vault.totalShares(), totalSharesBefore); - assertEq(erc20Vault.totalAssets(), totalAssetsBefore); - assertEq(erc20Vault.validatorsManagerNonce(), 0); - assertEq(erc20Vault.getShares(sender), senderBalanceBefore); - assertEq( - contracts.gnoToken.allowance(address(erc20Vault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - assertEq(erc20Vault.totalSupply(), totalSharesBefore); - assertEq(erc20Vault.symbol(), 'SW-GNO-1'); - assertEq(erc20Vault.name(), 'SW GNO Vault'); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - } - - function test_deposit_emitsTransfer() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Approve GNO for the vault first - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - - // When depositing, the vault will mint shares to the receiver - // So we should expect a Transfer event from address(0) to the receiver - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(address(0), sender, shares); - - // Call deposit directly instead of the helper - _startSnapshotGas('GnoErc20VaultTest_test_deposit_emitsTransfer'); - vault.deposit(amount, sender, referrer); - _stopSnapshotGas(); - vm.stopPrank(); - } - - function test_enterExitQueue_emitsTransfer() public { - _collateralizeGnoVault(address(vault)); - - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // First deposit - _depositGno(amount, sender, sender); - - // Expect Transfer event when entering exit queue - vm.expectEmit(true, true, true, false, address(vault)); - emit IERC20.Transfer(sender, address(vault), shares); - - // Enter exit queue - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - _startSnapshotGas('GnoErc20VaultTest_test_enterExitQueue_emitsTransfer'); - uint256 positionTicket = vault.enterExitQueue(shares, sender); - _stopSnapshotGas(); - - // Process the exit queue (update state) - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Claim exited assets - vm.prank(sender); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - } - - function test_redeem_emitsEvent() public { - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createVault(VaultType.GnoErc20Vault, admin, initParams, false); - GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); - - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // First deposit - _depositToVault(_vault, amount, sender, sender); - - // Expect Transfer event when entering exit queue - vm.expectEmit(true, true, true, false, _vault); - emit IERC20.Transfer(sender, address(0), shares); - - // Redeem - vm.prank(sender); - _startSnapshotGas('GnoErc20VaultTest_test_redeem_emitsEvent'); - uint256 positionTicket = erc20Vault.enterExitQueue(shares, sender); - _stopSnapshotGas(); - - assertEq(positionTicket, type(uint256).max); - } - - function test_cannotTransferFromSharesWithLowLtv() public { - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - uint256 depositAmount = 10 ether; - - // Deposit GNO - _depositGno(depositAmount, sender, sender); - - // First mint the maximum amount of osToken - vm.prank(sender); - vault.mintOsToken(sender, type(uint256).max, referrer); - - // Approve other to transfer a significant amount - vm.prank(sender); - vault.approve(other, depositAmount / 4); - - // Try to transferFrom a significant amount - vm.prank(other); - _startSnapshotGas('GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv'); - vm.expectRevert(Errors.LowLtv.selector); - vault.transferFrom(sender, other, depositAmount / 4); // 25% of collateral - _stopSnapshotGas(); - } - - function test_canTransferFromSharesWithHighLtv() public { - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - uint256 depositAmount = 10 ether; - uint256 depositShares = vault.convertToShares(depositAmount); - - // Deposit GNO - _depositGno(depositAmount, sender, sender); - - // Mint a very small amount of osToken - vm.prank(sender); - vault.mintOsToken(sender, depositShares / 100, referrer); // Just 1% of deposit - - // Approve other to transfer shares - vm.prank(sender); - vault.approve(other, depositShares / 2); - - // Should be able to transferFrom most shares - vm.prank(other); - _startSnapshotGas('GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv'); - vault.transferFrom(sender, other, depositShares / 2); - _stopSnapshotGas(); - - // Verify the transfer succeeded - assertApproxEqAbs(vault.balanceOf(sender), depositShares - depositShares / 2, 1); - assertApproxEqAbs(vault.balanceOf(other), depositShares / 2, 1); - } - - function test_withdrawValidator_validatorsManager() public { - // 1. Set validators manager - address validatorsManager = makeAddr('validatorsManager'); - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // 2. First deposit and register a validator - _depositGno(10 ether, sender, sender); - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(validatorsManager); - _startSnapshotGas('VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_withdrawValidator_osTokenRedeemer() public { - // 1. Set osToken redeemer - address osTokenRedeemer = makeAddr('osTokenRedeemer'); - vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); - contracts.osTokenConfig.setRedeemer(osTokenRedeemer); - - uint256 withdrawFee = 0.1 ether; - vm.deal(osTokenRedeemer, withdrawFee); - - // 2. First deposit and mint osToken - _depositGno(10 ether, sender, sender); - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(osTokenRedeemer); - _startSnapshotGas('VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_withdrawValidator_unknown() public { - // 1. Set unknown address - address unknown = makeAddr('unknown'); - - uint256 withdrawFee = 0.1 ether; - vm.deal(unknown, withdrawFee); - - // 2. First deposit and mint osToken - _depositGno(10 ether, sender, sender); - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // 3. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(unknown); - _startSnapshotGas('VaultGnoErc20VaultTest_test_withdrawValidator_unknown'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - // Helper function to deposit GNO to the vault - function _depositGno(uint256 amount, address from, address to) internal { - _depositToVault(address(vault), amount, from, to); - } + ForkContracts public contracts; + GnoErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoErc20Vault, admin, initParams, false); + vault = GnoErc20Vault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("GnoErc20VaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.GnoErc20Vault, admin, initParams, false); + _stopSnapshotGas(); + GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = erc20Vault.getExitQueueData(); + + assertEq(erc20Vault.vaultId(), keccak256("GnoErc20Vault")); + assertEq(erc20Vault.version(), 3); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.totalShares(), _securityDeposit); + assertEq(erc20Vault.totalAssets(), _securityDeposit); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.totalSupply(), _securityDeposit); + assertEq(erc20Vault.symbol(), "SW-GNO-1"); + assertEq(erc20Vault.name(), "SW GNO Vault"); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoErc20Vault, admin, initParams, false); + GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + + _depositToVault(address(erc20Vault), 15 ether, sender, sender); + _registerGnoValidator(address(erc20Vault), 1 ether, true); + + vm.prank(sender); + erc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = erc20Vault.totalShares(); + uint256 totalAssetsBefore = erc20Vault.totalAssets(); + uint256 senderBalanceBefore = erc20Vault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(erc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(erc20Vault)).queuedShares(); + + assertEq(erc20Vault.vaultId(), keccak256("GnoErc20Vault")); + assertEq(erc20Vault.version(), 2); + assertEq(contracts.gnoToken.allowance(address(erc20Vault), address(contracts.validatorsRegistry)), 0); + + _startSnapshotGas("GnoErc20VaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoErc20Vault, address(erc20Vault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = erc20Vault.getExitQueueData(); + assertEq(erc20Vault.vaultId(), keccak256("GnoErc20Vault")); + assertEq(erc20Vault.version(), 3); + assertEq(erc20Vault.admin(), admin); + assertEq(erc20Vault.capacity(), 1000 ether); + assertEq(erc20Vault.feePercent(), 1000); + assertEq(erc20Vault.feeRecipient(), admin); + assertEq(erc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(erc20Vault.totalShares(), totalSharesBefore); + assertEq(erc20Vault.totalAssets(), totalAssetsBefore); + assertEq(erc20Vault.validatorsManagerNonce(), 0); + assertEq(erc20Vault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(erc20Vault), address(contracts.validatorsRegistry)), type(uint256).max + ); + assertEq(erc20Vault.totalSupply(), totalSharesBefore); + assertEq(erc20Vault.symbol(), "SW-GNO-1"); + assertEq(erc20Vault.name(), "SW GNO Vault"); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + } + + function test_deposit_emitsTransfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Approve GNO for the vault first + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + + // When depositing, the vault will mint shares to the receiver + // So we should expect a Transfer event from address(0) to the receiver + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(address(0), sender, shares); + + // Call deposit directly instead of the helper + _startSnapshotGas("GnoErc20VaultTest_test_deposit_emitsTransfer"); + vault.deposit(amount, sender, referrer); + _stopSnapshotGas(); + vm.stopPrank(); + } + + function test_enterExitQueue_emitsTransfer() public { + _collateralizeGnoVault(address(vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositGno(amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, address(vault)); + emit IERC20.Transfer(sender, address(vault), shares); + + // Enter exit queue + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas("GnoErc20VaultTest_test_enterExitQueue_emitsTransfer"); + uint256 positionTicket = vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Claim exited assets + vm.prank(sender); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_redeem_emitsEvent() public { + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createVault(VaultType.GnoErc20Vault, admin, initParams, false); + GnoErc20Vault erc20Vault = GnoErc20Vault(payable(_vault)); + + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // First deposit + _depositToVault(_vault, amount, sender, sender); + + // Expect Transfer event when entering exit queue + vm.expectEmit(true, true, true, false, _vault); + emit IERC20.Transfer(sender, address(0), shares); + + // Redeem + vm.prank(sender); + _startSnapshotGas("GnoErc20VaultTest_test_redeem_emitsEvent"); + uint256 positionTicket = erc20Vault.enterExitQueue(shares, sender); + _stopSnapshotGas(); + + assertEq(positionTicket, type(uint256).max); + } + + function test_cannotTransferFromSharesWithLowLtv() public { + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + uint256 depositAmount = 10 ether; + + // Deposit GNO + _depositGno(depositAmount, sender, sender); + + // First mint the maximum amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, type(uint256).max, referrer); + + // Approve other to transfer a significant amount + vm.prank(sender); + vault.approve(other, depositAmount / 4); + + // Try to transferFrom a significant amount + vm.prank(other); + _startSnapshotGas("GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv"); + vm.expectRevert(Errors.LowLtv.selector); + vault.transferFrom(sender, other, depositAmount / 4); // 25% of collateral + _stopSnapshotGas(); + } + + function test_canTransferFromSharesWithHighLtv() public { + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + uint256 depositAmount = 10 ether; + uint256 depositShares = vault.convertToShares(depositAmount); + + // Deposit GNO + _depositGno(depositAmount, sender, sender); + + // Mint a very small amount of osToken + vm.prank(sender); + vault.mintOsToken(sender, depositShares / 100, referrer); // Just 1% of deposit + + // Approve other to transfer shares + vm.prank(sender); + vault.approve(other, depositShares / 2); + + // Should be able to transferFrom most shares + vm.prank(other); + _startSnapshotGas("GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv"); + vault.transferFrom(sender, other, depositShares / 2); + _stopSnapshotGas(); + + // Verify the transfer succeeded + assertApproxEqAbs(vault.balanceOf(sender), depositShares - depositShares / 2, 1); + assertApproxEqAbs(vault.balanceOf(other), depositShares / 2, 1); + } + + function test_withdrawValidator_validatorsManager() public { + // 1. Set validators manager + address validatorsManager = makeAddr("validatorsManager"); + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 2. First deposit and register a validator + _depositGno(10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas("VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_withdrawValidator_osTokenRedeemer() public { + // 1. Set osToken redeemer + address osTokenRedeemer = makeAddr("osTokenRedeemer"); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // 2. First deposit and mint osToken + _depositGno(10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(osTokenRedeemer); + _startSnapshotGas("VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_withdrawValidator_unknown() public { + // 1. Set unknown address + address unknown = makeAddr("unknown"); + + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // 2. First deposit and mint osToken + _depositGno(10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(unknown); + _startSnapshotGas("VaultGnoErc20VaultTest_test_withdrawValidator_unknown"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } } diff --git a/test/gnosis/GnoGenesisVault.t.sol b/test/gnosis/GnoGenesisVault.t.sol index 45ef6ba5..6d618428 100644 --- a/test/gnosis/GnoGenesisVault.t.sol +++ b/test/gnosis/GnoGenesisVault.t.sol @@ -1,236 +1,228 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {IGnoGenesisVault} from '../../contracts/interfaces/IGnoGenesisVault.sol'; -import {GnoGenesisVault} from '../../contracts/vaults/gnosis/GnoGenesisVault.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {IGnoGenesisVault} from "../../contracts/interfaces/IGnoGenesisVault.sol"; +import {GnoGenesisVault} from "../../contracts/vaults/gnosis/GnoGenesisVault.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; interface IVaultStateV3 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoGenesisVaultTest is Test, GnoHelpers { - ForkContracts public contracts; - address public admin; - address public user; - address public poolEscrow; - address public rewardGnoToken; - bytes public initParams; - - function setUp() public { - // Activate Gnosis fork and get contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - - // Provide GNO to the test accounts - _mintGnoToken(admin, 100 ether); - _mintGnoToken(user, 100 ether); - - // Get pool escrow and reward token addresses from the helper - poolEscrow = _poolEscrow; - rewardGnoToken = _rewardGnoToken; - - initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - } - - function test_deployFails() public { - // Deploy the vault directly - vm.deal(admin, 1 ether); - vm.prank(admin); - address impl = _getOrCreateVaultImpl(VaultType.GnoGenesisVault); - address _vault = address(new ERC1967Proxy(impl, '')); - - vm.expectRevert(Errors.UpgradeFailed.selector); - IGnoGenesisVault(_vault).initialize(initParams); - } - - function test_upgradesCorrectly() public { - // Get or create a vault - address vaultAddr = _getForkVault(VaultType.GnoGenesisVault); - GnoGenesisVault existingVault = GnoGenesisVault(payable(vaultAddr)); - - _depositToVault(address(existingVault), 15 ether, user, user); - _registerGnoValidator(address(existingVault), 1 ether, true); - - vm.prank(user); - existingVault.enterExitQueue(10 ether, user); - - // Record initial state - uint256 totalExitingAssetsBefore = IVaultStateV3(address(existingVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV3(address(existingVault)).queuedShares(); - uint256 initialTotalAssets = existingVault.totalAssets(); - uint256 initialTotalShares = existingVault.totalShares(); - uint256 senderBalanceBefore = existingVault.getShares(user); - uint256 initialCapacity = existingVault.capacity(); - uint256 initialFeePercent = existingVault.feePercent(); - address validatorsManager = existingVault.validatorsManager(); - address feeRecipient = existingVault.feeRecipient(); - address adminBefore = existingVault.admin(); - - assertEq(existingVault.vaultId(), keccak256('GnoGenesisVault')); - assertEq(existingVault.version(), 3); - - _startSnapshotGas('GnoGenesisVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoGenesisVault, address(existingVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = existingVault.getExitQueueData(); - assertEq(existingVault.vaultId(), keccak256('GnoGenesisVault')); - assertEq(existingVault.version(), 4); - assertEq(existingVault.admin(), adminBefore); - assertEq(existingVault.capacity(), initialCapacity); - assertEq(existingVault.feePercent(), initialFeePercent); - assertEq(existingVault.feeRecipient(), feeRecipient); - assertEq(existingVault.validatorsManager(), validatorsManager); - assertEq(queuedShares, queuedSharesBefore); - assertEq(existingVault.totalShares(), initialTotalShares); - assertEq(existingVault.totalAssets(), initialTotalAssets); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - assertEq(existingVault.validatorsManagerNonce(), 0); - assertEq(existingVault.getShares(user), senderBalanceBefore); - assertEq( - contracts.gnoToken.allowance(address(existingVault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - } - - function test_cannotInitializeTwice() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - // Try to initialize it again - vm.prank(admin); - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize(initParams); - } - - function test_migrate_failsWithInvalidCaller() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - // Try to migrate with invalid caller (not rewardGnoToken) - vm.prank(user); - vm.expectRevert(Errors.AccessDenied.selector); - vault.migrate(user, 1 ether); - } - - function test_migrate_failsWithNotHarvested() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - // Ensure vault needs harvesting - _setGnoVaultReward(address(vault), 1 ether, 0); - _setGnoVaultReward(address(vault), 2 ether, 0); - - vm.prank(rewardGnoToken); - vm.expectRevert(Errors.NotHarvested.selector); - vault.migrate(user, 1 ether); - } - - function test_migrate_failsWithInvalidReceiver() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - vm.prank(rewardGnoToken); - vm.expectRevert(Errors.ZeroAddress.selector); - vault.migrate(address(0), 1 ether); - } - - function test_migrate_failsWithInvalidAssets() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - vm.prank(rewardGnoToken); - vm.expectRevert(Errors.InvalidAssets.selector); - vault.migrate(user, 0); - } - - function test_migrate_works() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - // Record initial state - uint256 initialTotalAssets = vault.totalAssets(); - uint256 initialTotalShares = vault.totalShares(); - - // Set up migration - uint256 migrateAmount = 10 ether; - uint256 osTokenShares = vault.osTokenPositions(user); - assertEq(osTokenShares, 0, 'OsToken position should be empty'); - - // Perform migration - _startSnapshotGas('GnoGenesisVaultTest_test_migrate_works'); - vm.prank(rewardGnoToken); - uint256 shares = vault.migrate(user, migrateAmount); - _stopSnapshotGas(); - - // Verify results - assertGt(shares, 0, 'Should have minted shares'); - assertEq(vault.getShares(user), shares, 'User should have received shares'); - assertEq( - vault.totalAssets(), - initialTotalAssets + migrateAmount, - 'Total assets should increase' - ); - assertEq(vault.totalShares(), initialTotalShares + shares, 'Total shares should increase'); - - // Verify OsToken position - osTokenShares = vault.osTokenPositions(user); - assertGt(osTokenShares, 0, 'OsToken position should match shares'); - } - - function test_pullWithdrawals_claimEscrowAssets() public { - // Get or create a vault - address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); - GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); - - // Add some GNO to the pool escrow - uint256 escrowAmount = 5 ether; - _mintGnoToken(poolEscrow, escrowAmount); - - // Set up withdrawable amount in the validators registry for the escrow - uint256 withdrawalAmount = 3 ether; - _setGnoWithdrawals(poolEscrow, withdrawalAmount); - - // Record initial balances - uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); - - // Register a validator to trigger _pullWithdrawals - _startSnapshotGas('GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets'); - _registerGnoValidator(address(vault), 1 ether, false); - _stopSnapshotGas(); - - // Verify results - uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); - uint256 escrowFinalBalance = contracts.gnoToken.balanceOf(poolEscrow); - - assertGt( - vaultFinalBalance, - vaultInitialBalance, - 'Vault balance should increase from claiming escrow assets' - ); - - assertLt(escrowFinalBalance, escrowAmount, 'Escrow balance should decrease from withdrawal'); - } + ForkContracts public contracts; + address public admin; + address public user; + address public poolEscrow; + address public rewardGnoToken; + bytes public initParams; + + function setUp() public { + // Activate Gnosis fork and get contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + + // Provide GNO to the test accounts + _mintGnoToken(admin, 100 ether); + _mintGnoToken(user, 100 ether); + + // Get pool escrow and reward token addresses from the helper + poolEscrow = _poolEscrow; + rewardGnoToken = _rewardGnoToken; + + initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + } + + function test_deployFails() public { + // Deploy the vault directly + vm.deal(admin, 1 ether); + vm.prank(admin); + address impl = _getOrCreateVaultImpl(VaultType.GnoGenesisVault); + address _vault = address(new ERC1967Proxy(impl, "")); + + vm.expectRevert(Errors.UpgradeFailed.selector); + IGnoGenesisVault(_vault).initialize(initParams); + } + + function test_upgradesCorrectly() public { + // Get or create a vault + address vaultAddr = _getForkVault(VaultType.GnoGenesisVault); + GnoGenesisVault existingVault = GnoGenesisVault(payable(vaultAddr)); + + _depositToVault(address(existingVault), 15 ether, user, user); + _registerGnoValidator(address(existingVault), 1 ether, true); + + vm.prank(user); + existingVault.enterExitQueue(10 ether, user); + + // Record initial state + uint256 totalExitingAssetsBefore = IVaultStateV3(address(existingVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV3(address(existingVault)).queuedShares(); + uint256 initialTotalAssets = existingVault.totalAssets(); + uint256 initialTotalShares = existingVault.totalShares(); + uint256 senderBalanceBefore = existingVault.getShares(user); + uint256 initialCapacity = existingVault.capacity(); + uint256 initialFeePercent = existingVault.feePercent(); + address validatorsManager = existingVault.validatorsManager(); + address feeRecipient = existingVault.feeRecipient(); + address adminBefore = existingVault.admin(); + + assertEq(existingVault.vaultId(), keccak256("GnoGenesisVault")); + assertEq(existingVault.version(), 3); + + _startSnapshotGas("GnoGenesisVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoGenesisVault, address(existingVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = existingVault.getExitQueueData(); + assertEq(existingVault.vaultId(), keccak256("GnoGenesisVault")); + assertEq(existingVault.version(), 4); + assertEq(existingVault.admin(), adminBefore); + assertEq(existingVault.capacity(), initialCapacity); + assertEq(existingVault.feePercent(), initialFeePercent); + assertEq(existingVault.feeRecipient(), feeRecipient); + assertEq(existingVault.validatorsManager(), validatorsManager); + assertEq(queuedShares, queuedSharesBefore); + assertEq(existingVault.totalShares(), initialTotalShares); + assertEq(existingVault.totalAssets(), initialTotalAssets); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + assertEq(existingVault.validatorsManagerNonce(), 0); + assertEq(existingVault.getShares(user), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(existingVault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + } + + function test_cannotInitializeTwice() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Try to initialize it again + vm.prank(admin); + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize(initParams); + } + + function test_migrate_failsWithInvalidCaller() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Try to migrate with invalid caller (not rewardGnoToken) + vm.prank(user); + vm.expectRevert(Errors.AccessDenied.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithNotHarvested() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Ensure vault needs harvesting + _setGnoVaultReward(address(vault), 1 ether, 0); + _setGnoVaultReward(address(vault), 2 ether, 0); + + vm.prank(rewardGnoToken); + vm.expectRevert(Errors.NotHarvested.selector); + vault.migrate(user, 1 ether); + } + + function test_migrate_failsWithInvalidReceiver() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + vm.prank(rewardGnoToken); + vm.expectRevert(Errors.ZeroAddress.selector); + vault.migrate(address(0), 1 ether); + } + + function test_migrate_failsWithInvalidAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + vm.prank(rewardGnoToken); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.migrate(user, 0); + } + + function test_migrate_works() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Record initial state + uint256 initialTotalAssets = vault.totalAssets(); + uint256 initialTotalShares = vault.totalShares(); + + // Set up migration + uint256 migrateAmount = 10 ether; + uint256 osTokenShares = vault.osTokenPositions(user); + assertEq(osTokenShares, 0, "OsToken position should be empty"); + + // Perform migration + _startSnapshotGas("GnoGenesisVaultTest_test_migrate_works"); + vm.prank(rewardGnoToken); + uint256 shares = vault.migrate(user, migrateAmount); + _stopSnapshotGas(); + + // Verify results + assertGt(shares, 0, "Should have minted shares"); + assertEq(vault.getShares(user), shares, "User should have received shares"); + assertEq(vault.totalAssets(), initialTotalAssets + migrateAmount, "Total assets should increase"); + assertEq(vault.totalShares(), initialTotalShares + shares, "Total shares should increase"); + + // Verify OsToken position + osTokenShares = vault.osTokenPositions(user); + assertGt(osTokenShares, 0, "OsToken position should match shares"); + } + + function test_pullWithdrawals_claimEscrowAssets() public { + // Get or create a vault + address vaultAddr = _getOrCreateVault(VaultType.GnoGenesisVault, admin, initParams, false); + GnoGenesisVault vault = GnoGenesisVault(payable(vaultAddr)); + + // Add some GNO to the pool escrow + uint256 escrowAmount = 5 ether; + _mintGnoToken(poolEscrow, escrowAmount); + + // Set up withdrawable amount in the validators registry for the escrow + uint256 withdrawalAmount = 3 ether; + _setGnoWithdrawals(poolEscrow, withdrawalAmount); + + // Record initial balances + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + + // Register a validator to trigger _pullWithdrawals + _startSnapshotGas("GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets"); + _registerGnoValidator(address(vault), 1 ether, false); + _stopSnapshotGas(); + + // Verify results + uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); + uint256 escrowFinalBalance = contracts.gnoToken.balanceOf(poolEscrow); + + assertGt(vaultFinalBalance, vaultInitialBalance, "Vault balance should increase from claiming escrow assets"); + + assertLt(escrowFinalBalance, escrowAmount, "Escrow balance should decrease from withdrawal"); + } } diff --git a/test/gnosis/GnoOsTokenVaultEscrow.t.sol b/test/gnosis/GnoOsTokenVaultEscrow.t.sol index ff3e935d..6ac3b2ac 100644 --- a/test/gnosis/GnoOsTokenVaultEscrow.t.sol +++ b/test/gnosis/GnoOsTokenVaultEscrow.t.sol @@ -1,132 +1,121 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from '../../lib/forge-std/src/Test.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "../../lib/forge-std/src/Test.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {IOsTokenConfig} from "../../contracts/interfaces/IOsTokenConfig.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; interface IStrategiesRegistry { - function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; - function setStrategy(address strategy, bool enabled) external; + function addStrategyProxy(bytes32 strategyProxyId, address proxy) external; + function setStrategy(address strategy, bool enabled) external; - function owner() external view returns (address); + function owner() external view returns (address); } contract GnoOsTokenVaultEscrowTest is Test, GnoHelpers { - IStrategiesRegistry private constant _strategiesRegistry = - IStrategiesRegistry(0x4abB9BBb82922A6893A5d6890cd2eE94610BEc48); - - ForkContracts public contracts; - IGnoVault public vault; - - address public user; - address public admin; - - function setUp() public { - // Activate Gnosis fork and get contracts - contracts = _activateGnosisFork(); - - // Setup addresses - user = makeAddr('user'); - admin = makeAddr('admin'); - - // Fund accounts - vm.deal(user, 1 ether); - _mintGnoToken(user, 100 ether); - _mintGnoToken(admin, 100 ether); - - // Register user - vm.prank(_strategiesRegistry.owner()); - _strategiesRegistry.setStrategy(address(this), true); - _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(user)), user); - - // Create a vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); - vault = IGnoVault(_vault); - - // add escrow to vaults registry - vm.prank(contracts.vaultsRegistry.owner()); - contracts.vaultsRegistry.addVault(address(contracts.osTokenVaultEscrow)); - } - - function test_transferAssets() public { - _collateralizeGnoVault(address(vault)); - - uint256 depositAmount = 10 ether; - - _depositToVault(address(vault), depositAmount, user, user); - - // calculate osToken shares - IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); - uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; - uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); - - // mint osToken shares - vm.prank(user); - vault.mintOsToken(user, osTokenShares, address(0)); - - // Transfer osToken position to escrow - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(user); - _startSnapshotGas('GnoOsTokenVaultEscrowTest_test_transferAssets_transfer'); - uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); - _stopSnapshotGas(); - - uint256 afterTransferOsTokenPosition = vault.osTokenPositions(user); - assertEq(afterTransferOsTokenPosition, 0, 'osToken position was not transferred'); - - (address owner, uint256 exitedAssets, uint256 escrowOsTokenShares) = contracts - .osTokenVaultEscrow - .getPosition(address(vault), exitPositionTicket); - - assertEq(owner, user, 'Incorrect owner in escrow position'); - assertEq(exitedAssets, 0, 'Exited assets should be zero initially'); - assertEq(escrowOsTokenShares, osTokenShares, 'Incorrect osToken shares in escrow'); - - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - (uint128 queuedShares, , uint128 totalExitingAssets, ,) = vault.getExitQueueData(); - _mintGnoToken(address(vault), totalExitingAssets + vault.convertToAssets(queuedShares)); - vault.updateState(harvestParams); - - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - _startSnapshotGas('GnoOsTokenVaultEscrowTest_test_transferAssets_process'); - contracts.osTokenVaultEscrow.processExitedAssets( - address(vault), - exitPositionTicket, - timestamp, - uint256(vault.getExitQueueIndex(exitPositionTicket)) - ); - _stopSnapshotGas(); - - // User claims exited assets - uint256 userBalanceBefore = contracts.gnoToken.balanceOf(user); - - vm.prank(user); - _startSnapshotGas('GnoOsTokenVaultEscrowTest_test_transferAssets_claim'); - uint256 claimedAssets = contracts.osTokenVaultEscrow.claimExitedAssets( - address(vault), - exitPositionTicket, - osTokenShares - ); - _stopSnapshotGas(); - - uint256 userBalanceAfter = contracts.gnoToken.balanceOf(user); - - assertEq( - userBalanceAfter - userBalanceBefore, - claimedAssets, - 'Incorrect amount of assets transferred' - ); - assertGt(claimedAssets, 0, 'No assets were claimed'); - } + IStrategiesRegistry private constant _strategiesRegistry = + IStrategiesRegistry(0x4abB9BBb82922A6893A5d6890cd2eE94610BEc48); + + ForkContracts public contracts; + IGnoVault public vault; + + address public user; + address public admin; + + function setUp() public { + // Activate Gnosis fork and get contracts + contracts = _activateGnosisFork(); + + // Setup addresses + user = makeAddr("user"); + admin = makeAddr("admin"); + + // Fund accounts + vm.deal(user, 1 ether); + _mintGnoToken(user, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Register user + vm.prank(_strategiesRegistry.owner()); + _strategiesRegistry.setStrategy(address(this), true); + _strategiesRegistry.addStrategyProxy(keccak256(abi.encode(user)), user); + + // Create a vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + vault = IGnoVault(_vault); + + // add escrow to vaults registry + vm.prank(contracts.vaultsRegistry.owner()); + contracts.vaultsRegistry.addVault(address(contracts.osTokenVaultEscrow)); + } + + function test_transferAssets() public { + _collateralizeGnoVault(address(vault)); + + uint256 depositAmount = 10 ether; + + _depositToVault(address(vault), depositAmount, user, user); + + // calculate osToken shares + IOsTokenConfig.Config memory vaultConfig = contracts.osTokenConfig.getConfig(address(vault)); + uint256 osTokenAssets = (depositAmount * vaultConfig.ltvPercent) / 1e18; + uint256 osTokenShares = contracts.osTokenVaultController.convertToShares(osTokenAssets); + + // mint osToken shares + vm.prank(user); + vault.mintOsToken(user, osTokenShares, address(0)); + + // Transfer osToken position to escrow + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(user); + _startSnapshotGas("GnoOsTokenVaultEscrowTest_test_transferAssets_transfer"); + uint256 exitPositionTicket = vault.transferOsTokenPositionToEscrow(osTokenShares); + _stopSnapshotGas(); + + uint256 afterTransferOsTokenPosition = vault.osTokenPositions(user); + assertEq(afterTransferOsTokenPosition, 0, "osToken position was not transferred"); + + (address owner, uint256 exitedAssets, uint256 escrowOsTokenShares) = + contracts.osTokenVaultEscrow.getPosition(address(vault), exitPositionTicket); + + assertEq(owner, user, "Incorrect owner in escrow position"); + assertEq(exitedAssets, 0, "Exited assets should be zero initially"); + assertEq(escrowOsTokenShares, osTokenShares, "Incorrect osToken shares in escrow"); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + (uint128 queuedShares,, uint128 totalExitingAssets,,) = vault.getExitQueueData(); + _mintGnoToken(address(vault), totalExitingAssets + vault.convertToAssets(queuedShares)); + vault.updateState(harvestParams); + + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + _startSnapshotGas("GnoOsTokenVaultEscrowTest_test_transferAssets_process"); + contracts.osTokenVaultEscrow.processExitedAssets( + address(vault), exitPositionTicket, timestamp, uint256(vault.getExitQueueIndex(exitPositionTicket)) + ); + _stopSnapshotGas(); + + // User claims exited assets + uint256 userBalanceBefore = contracts.gnoToken.balanceOf(user); + + vm.prank(user); + _startSnapshotGas("GnoOsTokenVaultEscrowTest_test_transferAssets_claim"); + uint256 claimedAssets = + contracts.osTokenVaultEscrow.claimExitedAssets(address(vault), exitPositionTicket, osTokenShares); + _stopSnapshotGas(); + + uint256 userBalanceAfter = contracts.gnoToken.balanceOf(user); + + assertEq(userBalanceAfter - userBalanceBefore, claimedAssets, "Incorrect amount of assets transferred"); + assertGt(claimedAssets, 0, "No assets were claimed"); + } } diff --git a/test/gnosis/GnoOwnMevEscrow.t.sol b/test/gnosis/GnoOwnMevEscrow.t.sol index 2b82fa27..42e5ae3e 100644 --- a/test/gnosis/GnoOwnMevEscrow.t.sol +++ b/test/gnosis/GnoOwnMevEscrow.t.sol @@ -1,98 +1,98 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {IOwnMevEscrow} from '../../contracts/interfaces/IOwnMevEscrow.sol'; -import {GnoOwnMevEscrow} from '../../contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol'; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {IOwnMevEscrow} from "../../contracts/interfaces/IOwnMevEscrow.sol"; +import {GnoOwnMevEscrow} from "../../contracts/vaults/gnosis/mev/GnoOwnMevEscrow.sol"; contract GnoOwnMevEscrowTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoOwnMevEscrow public ownMevEscrow; - address public vault; - address public other; - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - vault = makeAddr('vault'); - other = makeAddr('other'); - vm.deal(other, 10 ether); // Give 'other' some xDAI - - // Deploy the contract - ownMevEscrow = new GnoOwnMevEscrow(vault); - } - - function test_ownMevEscrowDeploymentGas() public { - _startSnapshotGas('GnoOwnMevEscrowTest_test_ownMevEscrowDeploymentGas'); - new GnoOwnMevEscrow(vault); - _stopSnapshotGas(); - } - - function test_onlyVaultCanWithdrawAssets() public { - // Attempt to call harvest from a non-vault address should revert - vm.prank(other); - vm.expectRevert(Errors.HarvestFailed.selector); - ownMevEscrow.harvest(); - } - - function test_emitsEventOnTransfers() public { - uint256 value = 1 ether; - - // Expect the MevReceived event with the correct value - vm.expectEmit(true, false, false, true); - emit IOwnMevEscrow.MevReceived(value); - - // Send xDAI from the other account - vm.prank(other); - (bool success, ) = address(ownMevEscrow).call{value: value}(''); - vm.assertTrue(success, 'xDAI transfer failed'); - } - - function test_worksWithZeroBalance() public { - // Ensure contract has zero balance - assertEq(address(ownMevEscrow).balance, 0); - - // Call harvest as vault - vm.prank(vault); - uint256 harvestedAmount = ownMevEscrow.harvest(); - - // Should always return 0 - assertEq(harvestedAmount, 0); - - // Vault balance should remain unchanged - assertEq(vault.balance, 0); - } - - function test_worksWithNonZeroBalance() public { - uint256 mevAmount = 0.5 ether; - - // Send xDAI to the contract to simulate MEV rewards - vm.deal(address(ownMevEscrow), mevAmount); - assertEq(address(ownMevEscrow).balance, mevAmount); - - // Record vault's initial balance - uint256 initialVaultBalance = vault.balance; - - // Expect the Harvested event with the correct value - vm.expectEmit(true, false, false, true); - emit IOwnMevEscrow.Harvested(mevAmount); - - // Call harvest as vault - vm.prank(vault); - uint256 harvestedAmount = ownMevEscrow.harvest(); - - // Should always return 0 - assertEq(harvestedAmount, 0); - - // Vault balance should increase by the harvested amount - assertEq(vault.balance, initialVaultBalance + mevAmount); - - // Contract balance should now be 0 - assertEq(address(ownMevEscrow).balance, 0); - } + ForkContracts public contracts; + GnoOwnMevEscrow public ownMevEscrow; + address public vault; + address public other; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + vault = makeAddr("vault"); + other = makeAddr("other"); + vm.deal(other, 10 ether); // Give 'other' some xDAI + + // Deploy the contract + ownMevEscrow = new GnoOwnMevEscrow(vault); + } + + function test_ownMevEscrowDeploymentGas() public { + _startSnapshotGas("GnoOwnMevEscrowTest_test_ownMevEscrowDeploymentGas"); + new GnoOwnMevEscrow(vault); + _stopSnapshotGas(); + } + + function test_onlyVaultCanWithdrawAssets() public { + // Attempt to call harvest from a non-vault address should revert + vm.prank(other); + vm.expectRevert(Errors.HarvestFailed.selector); + ownMevEscrow.harvest(); + } + + function test_emitsEventOnTransfers() public { + uint256 value = 1 ether; + + // Expect the MevReceived event with the correct value + vm.expectEmit(true, false, false, true); + emit IOwnMevEscrow.MevReceived(value); + + // Send xDAI from the other account + vm.prank(other); + (bool success,) = address(ownMevEscrow).call{value: value}(""); + vm.assertTrue(success, "xDAI transfer failed"); + } + + function test_worksWithZeroBalance() public { + // Ensure contract has zero balance + assertEq(address(ownMevEscrow).balance, 0); + + // Call harvest as vault + vm.prank(vault); + uint256 harvestedAmount = ownMevEscrow.harvest(); + + // Should always return 0 + assertEq(harvestedAmount, 0); + + // Vault balance should remain unchanged + assertEq(vault.balance, 0); + } + + function test_worksWithNonZeroBalance() public { + uint256 mevAmount = 0.5 ether; + + // Send xDAI to the contract to simulate MEV rewards + vm.deal(address(ownMevEscrow), mevAmount); + assertEq(address(ownMevEscrow).balance, mevAmount); + + // Record vault's initial balance + uint256 initialVaultBalance = vault.balance; + + // Expect the Harvested event with the correct value + vm.expectEmit(true, false, false, true); + emit IOwnMevEscrow.Harvested(mevAmount); + + // Call harvest as vault + vm.prank(vault); + uint256 harvestedAmount = ownMevEscrow.harvest(); + + // Should always return 0 + assertEq(harvestedAmount, 0); + + // Vault balance should increase by the harvested amount + assertEq(vault.balance, initialVaultBalance + mevAmount); + + // Contract balance should now be 0 + assertEq(address(ownMevEscrow).balance, 0); + } } diff --git a/test/gnosis/GnoPrivErc20Vault.t.sol b/test/gnosis/GnoPrivErc20Vault.t.sol index 72b43262..d407657d 100644 --- a/test/gnosis/GnoPrivErc20Vault.t.sol +++ b/test/gnosis/GnoPrivErc20Vault.t.sol @@ -1,368 +1,365 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; -import {GnoPrivErc20Vault} from '../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol'; +import {Test} from "forge-std/Test.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {IGnoErc20Vault} from "../../contracts/interfaces/IGnoErc20Vault.sol"; +import {GnoPrivErc20Vault} from "../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoPrivErc20VaultTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoPrivErc20Vault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public whitelister; - address public referrer = address(0); - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - whitelister = makeAddr('whitelister'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(other, 100 ether); - _mintGnoToken(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.GnoPrivErc20Vault, admin, initParams, false); - vault = GnoPrivErc20Vault(payable(_vault)); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('GnoPrivErc20Vault'); - assertEq(vault.vaultId(), expectedId); - } - - function test_version() public view { - assertEq(vault.version(), 3); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_transfer() public { - uint256 amount = 1 ether; - uint256 shares = vault.convertToShares(amount); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(other, true); - vm.stopPrank(); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Transfer tokens - vm.prank(sender); - _startSnapshotGas('GnoPrivErc20VaultTest_test_transfer'); - vault.transfer(other, shares); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.balanceOf(sender), 0, 1); - assertEq(vault.balanceOf(other), shares); - } - - function test_cannotTransferToNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender but not other - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Try to transfer to non-whitelisted user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotTransferAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist other but not sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(other, true); - - // First whitelist sender temporarily to deposit - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Try to transfer from non-whitelisted user to whitelisted user - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.transfer(other, amount); - } - - function test_cannotDepositAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // Set whitelister but don't whitelist other - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Try to deposit as non-whitelisted user - vm.startPrank(other); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, receiver, referrer); - vm.stopPrank(); - } - - function test_cannotDepositToNotWhitelistedReceiver() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender but not receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Try to deposit to non-whitelisted receiver - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, receiver, referrer); - vm.stopPrank(); - } - - function test_canDepositAsWhitelistedUser() public { - uint256 amount = 1 ether; - uint256 expectedShares = vault.convertToShares(amount); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit as whitelisted user to whitelisted receiver - _startSnapshotGas('GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser'); - _depositGno(amount, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.balanceOf(receiver), expectedShares, 1); - } - - function test_cannotMintOsTokenAsNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Set whitelister and temporarily whitelist sender to deposit - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Try to mint osToken as non-whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Mint osToken as whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('GnoPrivErc20VaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.GnoPrivErc20Vault, admin, initParams, true); - _stopSnapshotGas(); - GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = privErc20Vault.getExitQueueData(); - assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); - assertEq(privErc20Vault.version(), 3); - assertEq(privErc20Vault.admin(), admin); - assertEq(privErc20Vault.whitelister(), admin); - assertEq(privErc20Vault.capacity(), 1000 ether); - assertEq(privErc20Vault.feePercent(), 1000); - assertEq(privErc20Vault.feeRecipient(), admin); - assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.totalShares(), _securityDeposit); - assertEq(privErc20Vault.totalAssets(), _securityDeposit); - assertEq(privErc20Vault.validatorsManagerNonce(), 0); - assertEq(privErc20Vault.totalSupply(), _securityDeposit); - assertEq(privErc20Vault.symbol(), 'SW-GNO-1'); - assertEq(privErc20Vault.name(), 'SW GNO Vault'); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - name: 'SW GNO Vault', - symbol: 'SW-GNO-1', - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.GnoPrivErc20Vault, admin, initParams, true); - GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); - - // whitelist sender and register validator - vm.prank(privErc20Vault.whitelister()); - privErc20Vault.updateWhitelist(sender, true); - - _depositToVault(address(privErc20Vault), 15 ether, sender, sender); - _registerGnoValidator(address(privErc20Vault), 1 ether, true); - - vm.prank(sender); - privErc20Vault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = privErc20Vault.totalShares(); - uint256 totalAssetsBefore = privErc20Vault.totalAssets(); - uint256 senderBalanceBefore = privErc20Vault.getShares(sender); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(privErc20Vault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV2(address(privErc20Vault)).queuedShares(); - - assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); - assertEq(privErc20Vault.version(), 2); - assertEq( - contracts.gnoToken.allowance(address(privErc20Vault), address(contracts.validatorsRegistry)), - 0 - ); - - _startSnapshotGas('GnoPrivErc20VaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoPrivErc20Vault, address(privErc20Vault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privErc20Vault.getExitQueueData(); - assertEq(privErc20Vault.vaultId(), keccak256('GnoPrivErc20Vault')); - assertEq(privErc20Vault.version(), 3); - assertEq(privErc20Vault.admin(), admin); - assertEq(privErc20Vault.whitelister(), admin); - assertEq(privErc20Vault.capacity(), 1000 ether); - assertEq(privErc20Vault.feePercent(), 1000); - assertEq(privErc20Vault.feeRecipient(), admin); - assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); - assertEq(privErc20Vault.totalShares(), totalSharesBefore); - assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); - assertEq(privErc20Vault.validatorsManagerNonce(), 0); - assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); - assertEq( - contracts.gnoToken.allowance(address(privErc20Vault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - assertEq(privErc20Vault.totalSupply(), totalSharesBefore); - assertEq(privErc20Vault.symbol(), 'SW-GNO-1'); - assertEq(privErc20Vault.name(), 'SW GNO Vault'); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - } - - // Helper function to deposit GNO to the vault - function _depositGno(uint256 amount, address from, address to) internal { - _depositToVault(address(vault), amount, from, to); - } + ForkContracts public contracts; + GnoPrivErc20Vault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + whitelister = makeAddr("whitelister"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoPrivErc20Vault, admin, initParams, false); + vault = GnoPrivErc20Vault(payable(_vault)); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("GnoPrivErc20Vault"); + assertEq(vault.vaultId(), expectedId); + } + + function test_version() public view { + assertEq(vault.version(), 3); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_transfer() public { + uint256 amount = 1 ether; + uint256 shares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(other, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Transfer tokens + vm.prank(sender); + _startSnapshotGas("GnoPrivErc20VaultTest_test_transfer"); + vault.transfer(other, shares); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(sender), 0, 1); + assertEq(vault.balanceOf(other), shares); + } + + function test_cannotTransferToNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not other + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Try to transfer to non-whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotTransferAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist other but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(other, true); + + // First whitelist sender temporarily to deposit + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to transfer from non-whitelisted user to whitelisted user + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.transfer(other, amount); + } + + function test_cannotDepositAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // Set whitelister but don't whitelist other + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Try to deposit as non-whitelisted user + vm.startPrank(other); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 amount = 1 ether; + uint256 expectedShares = vault.convertToShares(amount); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user to whitelisted receiver + _startSnapshotGas("GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser"); + _depositGno(amount, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.balanceOf(receiver), expectedShares, 1); + } + + function test_cannotMintOsTokenAsNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and temporarily whitelist sender to deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken as non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("GnoPrivErc20VaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.GnoPrivErc20Vault, admin, initParams, true); + _stopSnapshotGas(); + GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privErc20Vault.getExitQueueData(); + assertEq(privErc20Vault.vaultId(), keccak256("GnoPrivErc20Vault")); + assertEq(privErc20Vault.version(), 3); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.totalShares(), _securityDeposit); + assertEq(privErc20Vault.totalAssets(), _securityDeposit); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.totalSupply(), _securityDeposit); + assertEq(privErc20Vault.symbol(), "SW-GNO-1"); + assertEq(privErc20Vault.name(), "SW GNO Vault"); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + name: "SW GNO Vault", + symbol: "SW-GNO-1", + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoPrivErc20Vault, admin, initParams, true); + GnoPrivErc20Vault privErc20Vault = GnoPrivErc20Vault(payable(_vault)); + + // whitelist sender and register validator + vm.prank(privErc20Vault.whitelister()); + privErc20Vault.updateWhitelist(sender, true); + + _depositToVault(address(privErc20Vault), 15 ether, sender, sender); + _registerGnoValidator(address(privErc20Vault), 1 ether, true); + + vm.prank(sender); + privErc20Vault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privErc20Vault.totalShares(); + uint256 totalAssetsBefore = privErc20Vault.totalAssets(); + uint256 senderBalanceBefore = privErc20Vault.getShares(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(privErc20Vault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(privErc20Vault)).queuedShares(); + + assertEq(privErc20Vault.vaultId(), keccak256("GnoPrivErc20Vault")); + assertEq(privErc20Vault.version(), 2); + assertEq(contracts.gnoToken.allowance(address(privErc20Vault), address(contracts.validatorsRegistry)), 0); + + _startSnapshotGas("GnoPrivErc20VaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoPrivErc20Vault, address(privErc20Vault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = privErc20Vault.getExitQueueData(); + assertEq(privErc20Vault.vaultId(), keccak256("GnoPrivErc20Vault")); + assertEq(privErc20Vault.version(), 3); + assertEq(privErc20Vault.admin(), admin); + assertEq(privErc20Vault.whitelister(), admin); + assertEq(privErc20Vault.capacity(), 1000 ether); + assertEq(privErc20Vault.feePercent(), 1000); + assertEq(privErc20Vault.feeRecipient(), admin); + assertEq(privErc20Vault.validatorsManager(), _depositDataRegistry); + assertEq(privErc20Vault.totalShares(), totalSharesBefore); + assertEq(privErc20Vault.totalAssets(), totalAssetsBefore); + assertEq(privErc20Vault.validatorsManagerNonce(), 0); + assertEq(privErc20Vault.getShares(sender), senderBalanceBefore); + assertEq( + contracts.gnoToken.allowance(address(privErc20Vault), address(contracts.validatorsRegistry)), + type(uint256).max + ); + assertEq(privErc20Vault.totalSupply(), totalSharesBefore); + assertEq(privErc20Vault.symbol(), "SW-GNO-1"); + assertEq(privErc20Vault.name(), "SW GNO Vault"); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } } diff --git a/test/gnosis/GnoPrivVault.t.sol b/test/gnosis/GnoPrivVault.t.sol index 9f9333a7..6c8afc37 100644 --- a/test/gnosis/GnoPrivVault.t.sol +++ b/test/gnosis/GnoPrivVault.t.sol @@ -1,365 +1,357 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {GnoPrivVault} from '../../contracts/vaults/gnosis/GnoPrivVault.sol'; +import {Test} from "forge-std/Test.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {GnoPrivVault} from "../../contracts/vaults/gnosis/GnoPrivVault.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoPrivVaultTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoPrivVault public vault; - - address public sender; - address public receiver; - address public admin; - address public other; - address public whitelister; - address public referrer = address(0); - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - other = makeAddr('other'); - whitelister = makeAddr('whitelister'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(other, 100 ether); - _mintGnoToken(admin, 100 ether); - - // create vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _getOrCreateVault(VaultType.GnoPrivVault, admin, initParams, false); - vault = GnoPrivVault(payable(_vault)); - } - - function test_cannotInitializeTwice() public { - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_cannotDepositFromNotWhitelistedSender() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist receiver but not sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(receiver, true); - - // Try to deposit from non-whitelisted user - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, receiver, referrer); - vm.stopPrank(); - } - - function test_cannotDepositToNotWhitelistedReceiver() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender but not receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.prank(whitelister); - vault.updateWhitelist(sender, true); - - // Try to deposit to non-whitelisted receiver - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, receiver, referrer); - vm.stopPrank(); - } - - function test_canDepositAsWhitelistedUser() public { - uint256 assets = 1 ether; - uint256 shares = vault.convertToShares(assets); - - // Set whitelister and whitelist both sender and receiver - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit as whitelisted user - _startSnapshotGas('GnoPrivVaultTest_test_canDepositAsWhitelistedUser'); - _depositGno(assets, sender, receiver); - _stopSnapshotGas(); - - // Check balances - assertApproxEqAbs(vault.getShares(receiver), shares, 1); - } - - function test_cannotMintOsTokenFromNotWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Set whitelister and whitelist a user for initial deposit - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Try to mint osToken from non-whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - vm.expectRevert(Errors.AccessDenied.selector); - vault.mintOsToken(sender, osTokenShares, referrer); - } - - function test_canMintOsTokenAsWhitelistedUser() public { - uint256 amount = 1 ether; - - // First collateralize the vault - _collateralizeGnoVault(address(vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - - // Mint osToken as whitelisted user - uint256 osTokenShares = amount / 2; - vm.prank(sender); - _startSnapshotGas('GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser'); - vault.mintOsToken(sender, osTokenShares, referrer); - _stopSnapshotGas(); - - // Check osToken position - uint128 shares = vault.osTokenPositions(sender); - assertEq(shares, osTokenShares); - } - - function test_whitelistUpdateDoesNotAffectExistingFunds() public { - uint256 amount = 1 ether; - - // Set whitelister and whitelist sender - vm.prank(admin); - vault.setWhitelister(whitelister); - - vm.startPrank(whitelister); - vault.updateWhitelist(sender, true); - vault.updateWhitelist(receiver, true); - vm.stopPrank(); - - // Deposit GNO to get vault tokens - _depositGno(amount, sender, sender); - uint256 initialBalance = vault.getShares(sender); - assertApproxEqAbs(initialBalance, vault.convertToShares(amount), 1); - - // Remove sender from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - // Verify share balance remains the same - assertEq( - vault.getShares(sender), - initialBalance, - 'Balance should not change when whitelisting is removed' - ); - - // Verify cannot make new deposits but still has existing shares - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), amount); - vm.expectRevert(Errors.AccessDenied.selector); - vault.deposit(amount, sender, referrer); - vm.stopPrank(); - } - - function test_deploysCorrectly() public { - // create vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('GnoPrivVaultTest_test_deploysCorrectly'); - address _vault = _createVault(VaultType.GnoPrivVault, admin, initParams, false); - _stopSnapshotGas(); - GnoPrivVault privVault = GnoPrivVault(payable(_vault)); - - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = privVault.getExitQueueData(); - assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); - assertEq(privVault.version(), 3); - assertEq(privVault.admin(), admin); - assertEq(privVault.whitelister(), admin); - assertEq(privVault.capacity(), 1000 ether); - assertEq(privVault.feePercent(), 1000); - assertEq(privVault.feeRecipient(), admin); - assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.totalShares(), _securityDeposit); - assertEq(privVault.totalAssets(), _securityDeposit); - assertEq(privVault.validatorsManagerNonce(), 0); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // create prev version vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address _vault = _createPrevVersionVault(VaultType.GnoPrivVault, admin, initParams, false); - GnoPrivVault privVault = GnoPrivVault(payable(_vault)); - - // Set whitelister and whitelist sender - vm.prank(admin); - privVault.setWhitelister(whitelister); - - vm.prank(whitelister); - privVault.updateWhitelist(sender, true); - - // Make a deposit - _depositToVault(address(privVault), 15 ether, sender, sender); - _registerGnoValidator(address(privVault), 1 ether, true); - - vm.prank(sender); - privVault.enterExitQueue(10 ether, sender); - - uint256 totalSharesBefore = privVault.totalShares(); - uint256 totalAssetsBefore = privVault.totalAssets(); - uint256 senderBalanceBefore = privVault.getShares(sender); - bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(privVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV2(address(privVault)).queuedShares(); - - assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); - assertEq(privVault.version(), 2); - assertEq( - contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), - 0 - ); - - _startSnapshotGas('GnoPrivVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoPrivVault, address(privVault)); - _stopSnapshotGas(); - - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = privVault.getExitQueueData(); - assertEq(privVault.vaultId(), keccak256('GnoPrivVault')); - assertEq(privVault.version(), 3); - assertEq(privVault.admin(), admin); - assertEq(privVault.whitelister(), whitelister); - assertEq(privVault.capacity(), 1000 ether); - assertEq(privVault.feePercent(), 1000); - assertEq(privVault.feeRecipient(), admin); - assertEq(privVault.validatorsManager(), _depositDataRegistry); - assertEq(privVault.totalShares(), totalSharesBefore); - assertEq(privVault.totalAssets(), totalAssetsBefore); - assertEq(privVault.validatorsManagerNonce(), 0); - assertEq(privVault.getShares(sender), senderBalanceBefore); - assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); - assertEq( - contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - } - - function test_setWhitelister() public { - address newWhitelister = makeAddr('newWhitelister'); - - // Non-admin cannot set whitelister - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.setWhitelister(newWhitelister); - - // Admin can set whitelister - vm.prank(admin); - _startSnapshotGas('GnoPrivVaultTest_test_setWhitelister'); - vault.setWhitelister(newWhitelister); - _stopSnapshotGas(); - - assertEq(vault.whitelister(), newWhitelister, 'Whitelister not set correctly'); - } - - function test_updateWhitelist() public { - // Set whitelister - vm.prank(admin); - vault.setWhitelister(whitelister); - - // Non-whitelister cannot update whitelist - vm.prank(other); - vm.expectRevert(Errors.AccessDenied.selector); - vault.updateWhitelist(sender, true); - - // Whitelister can update whitelist - vm.prank(whitelister); - _startSnapshotGas('GnoPrivVaultTest_test_updateWhitelist'); - vault.updateWhitelist(sender, true); - _stopSnapshotGas(); - - assertTrue(vault.whitelistedAccounts(sender), 'Account not whitelisted correctly'); - - // Whitelister can remove from whitelist - vm.prank(whitelister); - vault.updateWhitelist(sender, false); - - assertFalse(vault.whitelistedAccounts(sender), 'Account not removed from whitelist correctly'); - } - - // Helper function to deposit GNO to the vault - function _depositGno(uint256 amount, address from, address to) internal { - _depositToVault(address(vault), amount, from, to); - } + ForkContracts public contracts; + GnoPrivVault public vault; + + address public sender; + address public receiver; + address public admin; + address public other; + address public whitelister; + address public referrer = address(0); + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + other = makeAddr("other"); + whitelister = makeAddr("whitelister"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(other, 100 ether); + _mintGnoToken(admin, 100 ether); + + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _getOrCreateVault(VaultType.GnoPrivVault, admin, initParams, false); + vault = GnoPrivVault(payable(_vault)); + } + + function test_cannotInitializeTwice() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_cannotDepositFromNotWhitelistedSender() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist receiver but not sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(receiver, true); + + // Try to deposit from non-whitelisted user + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_cannotDepositToNotWhitelistedReceiver() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender but not receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.prank(whitelister); + vault.updateWhitelist(sender, true); + + // Try to deposit to non-whitelisted receiver + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, receiver, referrer); + vm.stopPrank(); + } + + function test_canDepositAsWhitelistedUser() public { + uint256 assets = 1 ether; + uint256 shares = vault.convertToShares(assets); + + // Set whitelister and whitelist both sender and receiver + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit as whitelisted user + _startSnapshotGas("GnoPrivVaultTest_test_canDepositAsWhitelistedUser"); + _depositGno(assets, sender, receiver); + _stopSnapshotGas(); + + // Check balances + assertApproxEqAbs(vault.getShares(receiver), shares, 1); + } + + function test_cannotMintOsTokenFromNotWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and whitelist a user for initial deposit + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Try to mint osToken from non-whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + vm.expectRevert(Errors.AccessDenied.selector); + vault.mintOsToken(sender, osTokenShares, referrer); + } + + function test_canMintOsTokenAsWhitelistedUser() public { + uint256 amount = 1 ether; + + // First collateralize the vault + _collateralizeGnoVault(address(vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + + // Mint osToken as whitelisted user + uint256 osTokenShares = amount / 2; + vm.prank(sender); + _startSnapshotGas("GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser"); + vault.mintOsToken(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Check osToken position + uint128 shares = vault.osTokenPositions(sender); + assertEq(shares, osTokenShares); + } + + function test_whitelistUpdateDoesNotAffectExistingFunds() public { + uint256 amount = 1 ether; + + // Set whitelister and whitelist sender + vm.prank(admin); + vault.setWhitelister(whitelister); + + vm.startPrank(whitelister); + vault.updateWhitelist(sender, true); + vault.updateWhitelist(receiver, true); + vm.stopPrank(); + + // Deposit GNO to get vault tokens + _depositGno(amount, sender, sender); + uint256 initialBalance = vault.getShares(sender); + assertApproxEqAbs(initialBalance, vault.convertToShares(amount), 1); + + // Remove sender from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + // Verify share balance remains the same + assertEq(vault.getShares(sender), initialBalance, "Balance should not change when whitelisting is removed"); + + // Verify cannot make new deposits but still has existing shares + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), amount); + vm.expectRevert(Errors.AccessDenied.selector); + vault.deposit(amount, sender, referrer); + vm.stopPrank(); + } + + function test_deploysCorrectly() public { + // create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("GnoPrivVaultTest_test_deploysCorrectly"); + address _vault = _createVault(VaultType.GnoPrivVault, admin, initParams, false); + _stopSnapshotGas(); + GnoPrivVault privVault = GnoPrivVault(payable(_vault)); + + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = privVault.getExitQueueData(); + assertEq(privVault.vaultId(), keccak256("GnoPrivVault")); + assertEq(privVault.version(), 3); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), admin); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.totalShares(), _securityDeposit); + assertEq(privVault.totalAssets(), _securityDeposit); + assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // create prev version vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address _vault = _createPrevVersionVault(VaultType.GnoPrivVault, admin, initParams, false); + GnoPrivVault privVault = GnoPrivVault(payable(_vault)); + + // Set whitelister and whitelist sender + vm.prank(admin); + privVault.setWhitelister(whitelister); + + vm.prank(whitelister); + privVault.updateWhitelist(sender, true); + + // Make a deposit + _depositToVault(address(privVault), 15 ether, sender, sender); + _registerGnoValidator(address(privVault), 1 ether, true); + + vm.prank(sender); + privVault.enterExitQueue(10 ether, sender); + + uint256 totalSharesBefore = privVault.totalShares(); + uint256 totalAssetsBefore = privVault.totalAssets(); + uint256 senderBalanceBefore = privVault.getShares(sender); + bool senderWhitelistedBefore = privVault.whitelistedAccounts(sender); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(privVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(privVault)).queuedShares(); + + assertEq(privVault.vaultId(), keccak256("GnoPrivVault")); + assertEq(privVault.version(), 2); + assertEq(contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), 0); + + _startSnapshotGas("GnoPrivVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoPrivVault, address(privVault)); + _stopSnapshotGas(); + + (uint128 queuedShares,,, uint128 totalExitingAssets,) = privVault.getExitQueueData(); + assertEq(privVault.vaultId(), keccak256("GnoPrivVault")); + assertEq(privVault.version(), 3); + assertEq(privVault.admin(), admin); + assertEq(privVault.whitelister(), whitelister); + assertEq(privVault.capacity(), 1000 ether); + assertEq(privVault.feePercent(), 1000); + assertEq(privVault.feeRecipient(), admin); + assertEq(privVault.validatorsManager(), _depositDataRegistry); + assertEq(privVault.totalShares(), totalSharesBefore); + assertEq(privVault.totalAssets(), totalAssetsBefore); + assertEq(privVault.validatorsManagerNonce(), 0); + assertEq(privVault.getShares(sender), senderBalanceBefore); + assertEq(privVault.whitelistedAccounts(sender), senderWhitelistedBefore); + assertEq( + contracts.gnoToken.allowance(address(privVault), address(contracts.validatorsRegistry)), type(uint256).max + ); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + } + + function test_setWhitelister() public { + address newWhitelister = makeAddr("newWhitelister"); + + // Non-admin cannot set whitelister + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.setWhitelister(newWhitelister); + + // Admin can set whitelister + vm.prank(admin); + _startSnapshotGas("GnoPrivVaultTest_test_setWhitelister"); + vault.setWhitelister(newWhitelister); + _stopSnapshotGas(); + + assertEq(vault.whitelister(), newWhitelister, "Whitelister not set correctly"); + } + + function test_updateWhitelist() public { + // Set whitelister + vm.prank(admin); + vault.setWhitelister(whitelister); + + // Non-whitelister cannot update whitelist + vm.prank(other); + vm.expectRevert(Errors.AccessDenied.selector); + vault.updateWhitelist(sender, true); + + // Whitelister can update whitelist + vm.prank(whitelister); + _startSnapshotGas("GnoPrivVaultTest_test_updateWhitelist"); + vault.updateWhitelist(sender, true); + _stopSnapshotGas(); + + assertTrue(vault.whitelistedAccounts(sender), "Account not whitelisted correctly"); + + // Whitelister can remove from whitelist + vm.prank(whitelister); + vault.updateWhitelist(sender, false); + + assertFalse(vault.whitelistedAccounts(sender), "Account not removed from whitelist correctly"); + } + + // Helper function to deposit GNO to the vault + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } } diff --git a/test/gnosis/GnoRewardSplitter.t.sol b/test/gnosis/GnoRewardSplitter.t.sol index 493b5d0c..8eb9c5ca 100644 --- a/test/gnosis/GnoRewardSplitter.t.sol +++ b/test/gnosis/GnoRewardSplitter.t.sol @@ -1,550 +1,487 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IGnoErc20Vault} from '../../contracts/interfaces/IGnoErc20Vault.sol'; -import {IRewardSplitter} from '../../contracts/interfaces/IRewardSplitter.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IVaultGnoStaking} from '../../contracts/interfaces/IVaultGnoStaking.sol'; -import {IVaultEnterExit} from '../../contracts/interfaces/IVaultEnterExit.sol'; -import {IVaultFee} from '../../contracts/interfaces/IVaultFee.sol'; -import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {GnoRewardSplitter} from '../../contracts/misc/GnoRewardSplitter.sol'; -import {RewardSplitterFactory} from '../../contracts/misc/RewardSplitterFactory.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IGnoErc20Vault} from "../../contracts/interfaces/IGnoErc20Vault.sol"; +import {IRewardSplitter} from "../../contracts/interfaces/IRewardSplitter.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IVaultGnoStaking} from "../../contracts/interfaces/IVaultGnoStaking.sol"; +import {IVaultEnterExit} from "../../contracts/interfaces/IVaultEnterExit.sol"; +import {IVaultFee} from "../../contracts/interfaces/IVaultFee.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {GnoRewardSplitter} from "../../contracts/misc/GnoRewardSplitter.sol"; +import {RewardSplitterFactory} from "../../contracts/misc/RewardSplitterFactory.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; contract GnoRewardSplitterTest is Test, GnoHelpers { - ForkContracts public contracts; - address public vault; - GnoRewardSplitter public rewardSplitter; - RewardSplitterFactory public splitterFactory; - - address public admin; - address public shareholder1; - address public shareholder2; - address public depositor; - - uint128 public constant SHARE1 = 7000; // 70% - uint128 public constant SHARE2 = 3000; // 30% - uint256 public constant DEPOSIT_AMOUNT = 100 ether; // 100 GNO tokens - - function setUp() public { - // Get fork contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - admin = makeAddr('admin'); - shareholder1 = makeAddr('shareholder1'); - shareholder2 = makeAddr('shareholder2'); - depositor = makeAddr('depositor'); - - // Fund accounts - vm.deal(admin, 100 ether); - vm.deal(depositor, 100 ether); - - // Fund accounts with GNO for testing - _mintGnoToken(admin, 100 ether); - _mintGnoToken(depositor, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IGnoErc20Vault.GnoErc20VaultInitParams({ - name: 'Test GNO Vault', - symbol: 'TGNO', - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - vault = _getOrCreateVault(VaultType.GnoErc20Vault, admin, initParams, false); - - // Deploy GnoRewardSplitter implementation - GnoRewardSplitter impl = new GnoRewardSplitter(address(contracts.gnoToken)); - - // Deploy RewardSplitterFactory - splitterFactory = new RewardSplitterFactory(address(impl)); - - // Create GnoRewardSplitter for the vault - vm.prank(admin); - address splitterAddr = splitterFactory.createRewardSplitter(vault); - rewardSplitter = GnoRewardSplitter(payable(splitterAddr)); - - // Set RewardSplitter as fee recipient - vm.prank(admin); - IVaultFee(vault).setFeeRecipient(address(rewardSplitter)); - - // Configure shares in RewardSplitter - vm.startPrank(admin); - rewardSplitter.increaseShares(shareholder1, SHARE1); - rewardSplitter.increaseShares(shareholder2, SHARE2); - vm.stopPrank(); - - // Collateralize vault to enable rewards - _collateralizeGnoVault(vault); - } - - function test_initialization() public view { - assertEq(rewardSplitter.vault(), vault, 'Vault address not set correctly'); - assertEq(rewardSplitter.totalShares(), SHARE1 + SHARE2, 'Total shares not set correctly'); - assertEq( - rewardSplitter.sharesOf(shareholder1), - SHARE1, - 'Shareholder1 shares not set correctly' - ); - assertEq( - rewardSplitter.sharesOf(shareholder2), - SHARE2, - 'Shareholder2 shares not set correctly' - ); - } - - function test_generateAndDistributeRewards() public { - // Generate rewards by depositing and simulating profit - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - // Get initial vault shares of reward splitter - uint256 initialShares = IVaultState(vault).getShares(address(rewardSplitter)); - - // Simulate rewards/profit - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), // 1 GNO reward - 0 - ); - - // Update vault state to distribute rewards - IVaultState(vault).updateState(harvestParams); - - // Verify RewardSplitter has received vault shares as rewards - uint256 newShares = IVaultState(vault).getShares(address(rewardSplitter)); - assertGt(newShares, initialShares, 'RewardSplitter should have received vault shares'); - - // Sync rewards in the splitter - _startSnapshotGas('GnoRewardSplitter_syncRewards'); - rewardSplitter.syncRewards(); - _stopSnapshotGas(); - - // Check available rewards - uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); - uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); - assertGt(rewards1, 0, 'Shareholder1 should have rewards'); - assertGt(rewards2, 0, 'Shareholder2 should have rewards'); - - // Record initial GNO balances - uint256 shareholder1BalanceBefore = IERC20(contracts.gnoToken).balanceOf(shareholder1); - - // Shareholder1 enters exit queue with their vault shares - vm.prank(shareholder1); - uint256 timestamp = vm.getBlockTimestamp(); - _startSnapshotGas('GnoRewardSplitter_enterExitQueue'); - uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); - _stopSnapshotGas(); - - // Process the exit queue - harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); - IVaultState(vault).updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Shareholder1 claims exited assets - int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - vm.prank(shareholder1); - IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - - // Verify shareholder1 received GNO rewards - assertGt( - IERC20(contracts.gnoToken).balanceOf(shareholder1) - shareholder1BalanceBefore, - 0, - 'Shareholder1 should receive GNO rewards' - ); - - // Shareholder2 directly claims tokens without going through exit queue - vm.prank(shareholder2); - _startSnapshotGas('GnoRewardSplitter_claimVaultTokens'); - rewardSplitter.claimVaultTokens(rewards2, shareholder2); - _stopSnapshotGas(); - - // Verify shareholder2 received vault tokens - assertGt( - IVaultState(vault).getShares(shareholder2), - 0, - 'Shareholder2 should receive vault tokens directly' - ); - } - - function test_maxWithdrawal() public { - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - - IVaultState(vault).updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Get total rewards available - uint256 totalRewards = rewardSplitter.rewardsOf(shareholder1); - assertGt(totalRewards, 0, 'Should have rewards to withdraw'); - - // Withdraw using max value (should withdraw all available rewards) - vm.prank(shareholder1); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); - _startSnapshotGas('GnoRewardSplitter_enterExitQueueMaxWithdrawal'); - rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); - _stopSnapshotGas(); - - // Check rewards were fully claimed - assertEq(rewardSplitter.rewardsOf(shareholder1), 0, 'All rewards should be withdrawn'); - } - - function test_notHarvestedInSyncRewards() public { - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - // Force vault to need harvesting without actually harvesting - // First set a reward to make it need harvesting - _setGnoVaultReward(vault, int160(int256(1 ether)), 0); - - // Mock the isStateUpdateRequired to return true - vm.mockCall( - vault, - abi.encodeWithSelector(IVaultState.isStateUpdateRequired.selector), - abi.encode(true) - ); - - // Attempt to sync rewards when vault needs harvesting - vm.expectRevert(IRewardSplitter.NotHarvested.selector); - rewardSplitter.syncRewards(); - } - - function test_exitRequestNotProcessedInClaimOnBehalf() public { - // Enable claim on behalf - vm.prank(admin); - rewardSplitter.setClaimOnBehalf(true); - - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - - IVaultState(vault).updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Enter exit queue on behalf of shareholder1 - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(admin); - uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - - // Try to claim without waiting for the delay period - // (Exit request is not yet processed) - int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); - - vm.prank(admin); - vm.expectRevert(Errors.ExitRequestNotProcessed.selector); - rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); - } - - function test_accessDeniedInEnterExitQueueOnBehalf() public { - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - - IVaultState(vault).updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Claim on behalf is disabled by default - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - - // Should fail with AccessDenied since claim-on-behalf is disabled - vm.prank(admin); - vm.expectRevert(Errors.AccessDenied.selector); - rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - } - - function test_claimOnBehalf() public { - // Enable claim on behalf - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); - _startSnapshotGas('GnoRewardSplitter_setClaimOnBehalf'); - rewardSplitter.setClaimOnBehalf(true); - _stopSnapshotGas(); - - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - - IVaultState(vault).updateState(harvestParams); - - // Sync rewards - rewardSplitter.syncRewards(); - - // Check available rewards - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - assertGt(rewards, 0, 'Shareholder should have rewards'); - - // Someone else enters exit queue on behalf of shareholder1 - vm.prank(admin); - uint256 timestamp = vm.getBlockTimestamp(); - vm.expectEmit(true, false, false, false); - emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point - _startSnapshotGas('GnoRewardSplitter_enterExitQueueOnBehalf'); - uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); - _stopSnapshotGas(); - - // Verify position is tracked correctly - assertEq( - rewardSplitter.exitPositions(positionTicket), - shareholder1, - 'Exit position should be tracked' - ); - - // Process the exit queue - harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); - IVaultState(vault).updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Someone else claims on behalf of shareholder1 - uint256 shareholder1BalanceBefore = IERC20(contracts.gnoToken).balanceOf(shareholder1); - int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); - - // Expected reward amount to be claimed - (, , uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( - address(rewardSplitter), - positionTicket, - timestamp, - uint256(exitQueueIndex) - ); - - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); - _startSnapshotGas('GnoRewardSplitter_claimExitedAssetsOnBehalf'); - rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // Verify shareholder1 received GNO tokens - assertGt( - IERC20(contracts.gnoToken).balanceOf(shareholder1) - shareholder1BalanceBefore, - 0, - 'Shareholder should receive claimed GNO tokens' - ); - } - - function test_gnoTokenTransfer() public { - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - - IVaultState(vault).updateState(harvestParams); - rewardSplitter.syncRewards(); - - // Get shareholder1's rewards - uint256 rewards = rewardSplitter.rewardsOf(shareholder1); - assertGt(rewards, 0, 'Shareholder should have rewards'); - - // Set up for exit and claim - vm.prank(shareholder1); - uint256 timestamp = vm.getBlockTimestamp(); - uint256 positionTicket = rewardSplitter.enterExitQueue(rewards, shareholder1); - - // Process exit queue - harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); - IVaultState(vault).updateState(harvestParams); - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Check GNO token balance before claim - uint256 initialBalance = IERC20(contracts.gnoToken).balanceOf(shareholder1); - - // Claim exited assets (this should transfer GNO tokens) - int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); - - vm.prank(shareholder1); - _startSnapshotGas('GnoRewardSplitter_claimExitedAssets'); - IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // Verify GNO tokens were transferred to shareholder1 - uint256 finalBalance = IERC20(contracts.gnoToken).balanceOf(shareholder1); - assertGt(finalBalance, initialBalance, 'GNO tokens should be transferred to shareholder'); - } - - function test_manageShares() public { - // Initial shares amount - uint256 initialSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); - uint256 initialTotalShares = rewardSplitter.totalShares(); - - // Test increase shares - uint128 increaseAmount = 1000; - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.SharesIncreased(shareholder1, increaseAmount); - _startSnapshotGas('GnoRewardSplitter_increaseShares'); - rewardSplitter.increaseShares(shareholder1, increaseAmount); - _stopSnapshotGas(); - - uint256 newSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); - uint256 newTotalShares = rewardSplitter.totalShares(); - assertEq( - newSharesShareholder1, - initialSharesShareholder1 + increaseAmount, - 'Shares should be increased correctly' - ); - assertEq( - newTotalShares, - initialTotalShares + increaseAmount, - 'Total shares should be increased correctly' - ); - - // Test decrease shares - vm.prank(admin); - vm.expectEmit(true, false, false, true); - emit IRewardSplitter.SharesDecreased(shareholder1, increaseAmount); - _startSnapshotGas('GnoRewardSplitter_decreaseShares'); - rewardSplitter.decreaseShares(shareholder1, increaseAmount); - _stopSnapshotGas(); - - uint256 finalSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); - uint256 finalTotalShares = rewardSplitter.totalShares(); - assertEq( - finalSharesShareholder1, - initialSharesShareholder1, - 'Shares should be decreased back to original amount' - ); - assertEq( - finalTotalShares, - initialTotalShares, - 'Total shares should be decreased back to original amount' - ); - } - - function test_syncRewards() public { - // Generate rewards - vm.startPrank(depositor); - contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); - IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); - vm.stopPrank(); - - // Set reward and update vault state - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - IVaultState(vault).updateState(harvestParams); - - // Initial state before sync - uint256 initialTotalRewards = rewardSplitter.totalRewards(); - - // Should be able to sync rewards - assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards'); - - // Sync rewards - vm.expectEmit(false, false, false, false); // We don't check the parameters - emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values - _startSnapshotGas('GnoRewardSplitter_syncRewardsDetailed'); - rewardSplitter.syncRewards(); - _stopSnapshotGas(); - - // Verify rewards were synced - uint256 newTotalRewards = rewardSplitter.totalRewards(); - assertGt(newTotalRewards, initialTotalRewards, 'Total rewards should increase after sync'); - - // Verify proportional distribution - uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); - uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); - - assertGt(rewards1, 0, 'Shareholder1 should have rewards after sync'); - assertGt(rewards2, 0, 'Shareholder2 should have rewards after sync'); - - // Verify distribution is proportional to shares - uint256 expectedRewards1 = (newTotalRewards * SHARE1) / (SHARE1 + SHARE2); - uint256 expectedRewards2 = (newTotalRewards * SHARE2) / (SHARE1 + SHARE2); - - assertApproxEqRel( - rewards1, - expectedRewards1, - 0.0001e18, // 0.01% tolerance - 'Shareholder1 rewards should be proportional to shares' - ); - - assertApproxEqRel( - rewards2, - expectedRewards2, - 0.0001e18, // 0.01% tolerance - 'Shareholder2 rewards should be proportional to shares' - ); - } - - function test_updateVaultState() public { - // Generate rewards with a callback from reward splitter - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vault, - int160(int256(1 ether)), - 0 - ); - - // Update vault state through reward splitter - _startSnapshotGas('GnoRewardSplitter_updateVaultState'); - rewardSplitter.updateVaultState(harvestParams); - _stopSnapshotGas(); - - // Verify rewards can be synced - assertTrue(rewardSplitter.canSyncRewards(), 'Should be able to sync rewards after update'); - - // Sync and verify rewards - rewardSplitter.syncRewards(); - uint256 totalRewards = rewardSplitter.totalRewards(); - assertGt(totalRewards, 0, 'Total rewards should be greater than zero'); - } + ForkContracts public contracts; + address public vault; + GnoRewardSplitter public rewardSplitter; + RewardSplitterFactory public splitterFactory; + + address public admin; + address public shareholder1; + address public shareholder2; + address public depositor; + + uint128 public constant SHARE1 = 7000; // 70% + uint128 public constant SHARE2 = 3000; // 30% + uint256 public constant DEPOSIT_AMOUNT = 100 ether; // 100 GNO tokens + + function setUp() public { + // Get fork contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr("admin"); + shareholder1 = makeAddr("shareholder1"); + shareholder2 = makeAddr("shareholder2"); + depositor = makeAddr("depositor"); + + // Fund accounts + vm.deal(admin, 100 ether); + vm.deal(depositor, 100 ether); + + // Fund accounts with GNO for testing + _mintGnoToken(admin, 100 ether); + _mintGnoToken(depositor, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IGnoErc20Vault.GnoErc20VaultInitParams({ + name: "Test GNO Vault", + symbol: "TGNO", + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + vault = _getOrCreateVault(VaultType.GnoErc20Vault, admin, initParams, false); + + // Deploy GnoRewardSplitter implementation + GnoRewardSplitter impl = new GnoRewardSplitter(address(contracts.gnoToken)); + + // Deploy RewardSplitterFactory + splitterFactory = new RewardSplitterFactory(address(impl)); + + // Create GnoRewardSplitter for the vault + vm.prank(admin); + address splitterAddr = splitterFactory.createRewardSplitter(vault); + rewardSplitter = GnoRewardSplitter(payable(splitterAddr)); + + // Set RewardSplitter as fee recipient + vm.prank(admin); + IVaultFee(vault).setFeeRecipient(address(rewardSplitter)); + + // Configure shares in RewardSplitter + vm.startPrank(admin); + rewardSplitter.increaseShares(shareholder1, SHARE1); + rewardSplitter.increaseShares(shareholder2, SHARE2); + vm.stopPrank(); + + // Collateralize vault to enable rewards + _collateralizeGnoVault(vault); + } + + function test_initialization() public view { + assertEq(rewardSplitter.vault(), vault, "Vault address not set correctly"); + assertEq(rewardSplitter.totalShares(), SHARE1 + SHARE2, "Total shares not set correctly"); + assertEq(rewardSplitter.sharesOf(shareholder1), SHARE1, "Shareholder1 shares not set correctly"); + assertEq(rewardSplitter.sharesOf(shareholder2), SHARE2, "Shareholder2 shares not set correctly"); + } + + function test_generateAndDistributeRewards() public { + // Generate rewards by depositing and simulating profit + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + // Get initial vault shares of reward splitter + uint256 initialShares = IVaultState(vault).getShares(address(rewardSplitter)); + + // Simulate rewards/profit + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( + vault, + int160(int256(1 ether)), // 1 GNO reward + 0 + ); + + // Update vault state to distribute rewards + IVaultState(vault).updateState(harvestParams); + + // Verify RewardSplitter has received vault shares as rewards + uint256 newShares = IVaultState(vault).getShares(address(rewardSplitter)); + assertGt(newShares, initialShares, "RewardSplitter should have received vault shares"); + + // Sync rewards in the splitter + _startSnapshotGas("GnoRewardSplitter_syncRewards"); + rewardSplitter.syncRewards(); + _stopSnapshotGas(); + + // Check available rewards + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + assertGt(rewards1, 0, "Shareholder1 should have rewards"); + assertGt(rewards2, 0, "Shareholder2 should have rewards"); + + // Record initial GNO balances + uint256 shareholder1BalanceBefore = IERC20(contracts.gnoToken).balanceOf(shareholder1); + + // Shareholder1 enters exit queue with their vault shares + vm.prank(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + _startSnapshotGas("GnoRewardSplitter_enterExitQueue"); + uint256 positionTicket = rewardSplitter.enterExitQueue(rewards1, shareholder1); + _stopSnapshotGas(); + + // Process the exit queue + harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Shareholder1 claims exited assets + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + vm.prank(shareholder1); + IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify shareholder1 received GNO rewards + assertGt( + IERC20(contracts.gnoToken).balanceOf(shareholder1) - shareholder1BalanceBefore, + 0, + "Shareholder1 should receive GNO rewards" + ); + + // Shareholder2 directly claims tokens without going through exit queue + vm.prank(shareholder2); + _startSnapshotGas("GnoRewardSplitter_claimVaultTokens"); + rewardSplitter.claimVaultTokens(rewards2, shareholder2); + _stopSnapshotGas(); + + // Verify shareholder2 received vault tokens + assertGt(IVaultState(vault).getShares(shareholder2), 0, "Shareholder2 should receive vault tokens directly"); + } + + function test_maxWithdrawal() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Get total rewards available + uint256 totalRewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(totalRewards, 0, "Should have rewards to withdraw"); + + // Withdraw using max value (should withdraw all available rewards) + vm.prank(shareholder1); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.RewardsWithdrawn(shareholder1, totalRewards); + _startSnapshotGas("GnoRewardSplitter_enterExitQueueMaxWithdrawal"); + rewardSplitter.enterExitQueue(type(uint256).max, shareholder1); + _stopSnapshotGas(); + + // Check rewards were fully claimed + assertEq(rewardSplitter.rewardsOf(shareholder1), 0, "All rewards should be withdrawn"); + } + + function test_notHarvestedInSyncRewards() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + // Force vault to need harvesting without actually harvesting + // First set a reward to make it need harvesting + _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + // Mock the isStateUpdateRequired to return true + vm.mockCall(vault, abi.encodeWithSelector(IVaultState.isStateUpdateRequired.selector), abi.encode(true)); + + // Attempt to sync rewards when vault needs harvesting + vm.expectRevert(IRewardSplitter.NotHarvested.selector); + rewardSplitter.syncRewards(); + } + + function test_exitRequestNotProcessedInClaimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + rewardSplitter.setClaimOnBehalf(true); + + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Enter exit queue on behalf of shareholder1 + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(admin); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + + // Try to claim without waiting for the delay period + // (Exit request is not yet processed) + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + + vm.prank(admin); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + } + + function test_accessDeniedInEnterExitQueueOnBehalf() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Claim on behalf is disabled by default + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + + // Should fail with AccessDenied since claim-on-behalf is disabled + vm.prank(admin); + vm.expectRevert(Errors.AccessDenied.selector); + rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + } + + function test_claimOnBehalf() public { + // Enable claim on behalf + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ClaimOnBehalfUpdated(admin, true); + _startSnapshotGas("GnoRewardSplitter_setClaimOnBehalf"); + rewardSplitter.setClaimOnBehalf(true); + _stopSnapshotGas(); + + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + IVaultState(vault).updateState(harvestParams); + + // Sync rewards + rewardSplitter.syncRewards(); + + // Check available rewards + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(rewards, 0, "Shareholder should have rewards"); + + // Someone else enters exit queue on behalf of shareholder1 + vm.prank(admin); + uint256 timestamp = vm.getBlockTimestamp(); + vm.expectEmit(true, false, false, false); + emit IRewardSplitter.ExitQueueEnteredOnBehalf(shareholder1, 0, rewards); // Position ticket is unknown at this point + _startSnapshotGas("GnoRewardSplitter_enterExitQueueOnBehalf"); + uint256 positionTicket = rewardSplitter.enterExitQueueOnBehalf(rewards, shareholder1); + _stopSnapshotGas(); + + // Verify position is tracked correctly + assertEq(rewardSplitter.exitPositions(positionTicket), shareholder1, "Exit position should be tracked"); + + // Process the exit queue + harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Someone else claims on behalf of shareholder1 + uint256 shareholder1BalanceBefore = IERC20(contracts.gnoToken).balanceOf(shareholder1); + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + + // Expected reward amount to be claimed + (,, uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets( + address(rewardSplitter), positionTicket, timestamp, uint256(exitQueueIndex) + ); + + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.ExitedAssetsClaimedOnBehalf(shareholder1, positionTicket, exitedAssets); + _startSnapshotGas("GnoRewardSplitter_claimExitedAssetsOnBehalf"); + rewardSplitter.claimExitedAssetsOnBehalf(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify shareholder1 received GNO tokens + assertGt( + IERC20(contracts.gnoToken).balanceOf(shareholder1) - shareholder1BalanceBefore, + 0, + "Shareholder should receive claimed GNO tokens" + ); + } + + function test_gnoTokenTransfer() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + IVaultState(vault).updateState(harvestParams); + rewardSplitter.syncRewards(); + + // Get shareholder1's rewards + uint256 rewards = rewardSplitter.rewardsOf(shareholder1); + assertGt(rewards, 0, "Shareholder should have rewards"); + + // Set up for exit and claim + vm.prank(shareholder1); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = rewardSplitter.enterExitQueue(rewards, shareholder1); + + // Process exit queue + harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Check GNO token balance before claim + uint256 initialBalance = IERC20(contracts.gnoToken).balanceOf(shareholder1); + + // Claim exited assets (this should transfer GNO tokens) + int256 exitQueueIndex = IVaultEnterExit(vault).getExitQueueIndex(positionTicket); + + vm.prank(shareholder1); + _startSnapshotGas("GnoRewardSplitter_claimExitedAssets"); + IVaultEnterExit(vault).claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify GNO tokens were transferred to shareholder1 + uint256 finalBalance = IERC20(contracts.gnoToken).balanceOf(shareholder1); + assertGt(finalBalance, initialBalance, "GNO tokens should be transferred to shareholder"); + } + + function test_manageShares() public { + // Initial shares amount + uint256 initialSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); + uint256 initialTotalShares = rewardSplitter.totalShares(); + + // Test increase shares + uint128 increaseAmount = 1000; + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesIncreased(shareholder1, increaseAmount); + _startSnapshotGas("GnoRewardSplitter_increaseShares"); + rewardSplitter.increaseShares(shareholder1, increaseAmount); + _stopSnapshotGas(); + + uint256 newSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); + uint256 newTotalShares = rewardSplitter.totalShares(); + assertEq( + newSharesShareholder1, initialSharesShareholder1 + increaseAmount, "Shares should be increased correctly" + ); + assertEq(newTotalShares, initialTotalShares + increaseAmount, "Total shares should be increased correctly"); + + // Test decrease shares + vm.prank(admin); + vm.expectEmit(true, false, false, true); + emit IRewardSplitter.SharesDecreased(shareholder1, increaseAmount); + _startSnapshotGas("GnoRewardSplitter_decreaseShares"); + rewardSplitter.decreaseShares(shareholder1, increaseAmount); + _stopSnapshotGas(); + + uint256 finalSharesShareholder1 = rewardSplitter.sharesOf(shareholder1); + uint256 finalTotalShares = rewardSplitter.totalShares(); + assertEq( + finalSharesShareholder1, initialSharesShareholder1, "Shares should be decreased back to original amount" + ); + assertEq(finalTotalShares, initialTotalShares, "Total shares should be decreased back to original amount"); + } + + function test_syncRewards() public { + // Generate rewards + vm.startPrank(depositor); + contracts.gnoToken.approve(vault, DEPOSIT_AMOUNT); + IVaultGnoStaking(vault).deposit(DEPOSIT_AMOUNT, depositor, address(0)); + vm.stopPrank(); + + // Set reward and update vault state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + IVaultState(vault).updateState(harvestParams); + + // Initial state before sync + uint256 initialTotalRewards = rewardSplitter.totalRewards(); + + // Should be able to sync rewards + assertTrue(rewardSplitter.canSyncRewards(), "Should be able to sync rewards"); + + // Sync rewards + vm.expectEmit(false, false, false, false); // We don't check the parameters + emit IRewardSplitter.RewardsSynced(0, 0); // Placeholder values + _startSnapshotGas("GnoRewardSplitter_syncRewardsDetailed"); + rewardSplitter.syncRewards(); + _stopSnapshotGas(); + + // Verify rewards were synced + uint256 newTotalRewards = rewardSplitter.totalRewards(); + assertGt(newTotalRewards, initialTotalRewards, "Total rewards should increase after sync"); + + // Verify proportional distribution + uint256 rewards1 = rewardSplitter.rewardsOf(shareholder1); + uint256 rewards2 = rewardSplitter.rewardsOf(shareholder2); + + assertGt(rewards1, 0, "Shareholder1 should have rewards after sync"); + assertGt(rewards2, 0, "Shareholder2 should have rewards after sync"); + + // Verify distribution is proportional to shares + uint256 expectedRewards1 = (newTotalRewards * SHARE1) / (SHARE1 + SHARE2); + uint256 expectedRewards2 = (newTotalRewards * SHARE2) / (SHARE1 + SHARE2); + + assertApproxEqRel( + rewards1, + expectedRewards1, + 0.0001e18, // 0.01% tolerance + "Shareholder1 rewards should be proportional to shares" + ); + + assertApproxEqRel( + rewards2, + expectedRewards2, + 0.0001e18, // 0.01% tolerance + "Shareholder2 rewards should be proportional to shares" + ); + } + + function test_updateVaultState() public { + // Generate rewards with a callback from reward splitter + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, int160(int256(1 ether)), 0); + + // Update vault state through reward splitter + _startSnapshotGas("GnoRewardSplitter_updateVaultState"); + rewardSplitter.updateVaultState(harvestParams); + _stopSnapshotGas(); + + // Verify rewards can be synced + assertTrue(rewardSplitter.canSyncRewards(), "Should be able to sync rewards after update"); + + // Sync and verify rewards + rewardSplitter.syncRewards(); + uint256 totalRewards = rewardSplitter.totalRewards(); + assertGt(totalRewards, 0, "Total rewards should be greater than zero"); + } } diff --git a/test/gnosis/GnoSharedMevEscrow.t.sol b/test/gnosis/GnoSharedMevEscrow.t.sol index ad2aeee3..dd3ba35f 100644 --- a/test/gnosis/GnoSharedMevEscrow.t.sol +++ b/test/gnosis/GnoSharedMevEscrow.t.sol @@ -1,121 +1,117 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; -import {GnoSharedMevEscrow} from '../../contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol'; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {ISharedMevEscrow} from "../../contracts/interfaces/ISharedMevEscrow.sol"; +import {GnoSharedMevEscrow} from "../../contracts/vaults/gnosis/mev/GnoSharedMevEscrow.sol"; contract GnoSharedMevEscrowTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoSharedMevEscrow public sharedMevEscrow; - address public other; - address public mockVault; - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Deploy a new GnoSharedMevEscrow - sharedMevEscrow = new GnoSharedMevEscrow(address(contracts.vaultsRegistry)); - - // Set up test account - other = makeAddr('other'); - vm.deal(other, 10 ether); - - // Register a mock vault in the registry - mockVault = makeAddr('mockVault'); - vm.prank(contracts.vaultsRegistry.owner()); - contracts.vaultsRegistry.addVault(mockVault); - } - - function test_sharedEscrowDeploymentGas() public { - _startSnapshotGas('GnoSharedMevEscrowTest_test_sharedEscrowDeploymentGas'); - new GnoSharedMevEscrow(address(contracts.vaultsRegistry)); - _stopSnapshotGas(); - } - - function test_onlyVaultCanWithdrawAssets() public { - // Attempt to call harvest from a non-vault address should revert - vm.prank(other); - vm.expectRevert(Errors.HarvestFailed.selector); - sharedMevEscrow.harvest(1 ether); - } - - function test_emitsEventOnTransfers() public { - uint256 value = 1 ether; - - // Expect the MevReceived event with the correct value - vm.expectEmit(true, false, false, true); - emit ISharedMevEscrow.MevReceived(value); - - // Send xDAI from the other account - vm.prank(other); - (bool success, ) = address(sharedMevEscrow).call{value: value}(''); - vm.assertTrue(success, 'xDAI transfer failed'); - } - - function test_worksWithZeroBalance() public { - // Simulate a call from the vault with zero balance in the escrow - vm.prank(mockVault); - uint256 balanceBefore = address(mockVault).balance; - - // Harvest should succeed even with 0 balance - sharedMevEscrow.harvest(0); - - // Verify the balance didn't change - assertEq(address(mockVault).balance, balanceBefore, "Vault balance shouldn't change"); - } - - function test_worksWithNonZeroBalance() public { - // Fund the escrow contract - uint256 fundAmount = 3 ether; - vm.deal(address(sharedMevEscrow), fundAmount); - - // Record the initial balances - uint256 escrowBalanceBefore = address(sharedMevEscrow).balance; - uint256 vaultBalanceBefore = address(mockVault).balance; - - // Harvest a portion of the balance - uint256 harvestAmount = 1 ether; - - // The Harvested event should be emitted with the correct amount - vm.expectEmit(true, false, false, true); - emit ISharedMevEscrow.Harvested(mockVault, harvestAmount); - - // Perform the harvest - vm.prank(mockVault); - sharedMevEscrow.harvest(harvestAmount); - - // Verify the balances changed correctly - assertEq( - address(sharedMevEscrow).balance, - escrowBalanceBefore - harvestAmount, - 'Escrow balance should decrease by harvestAmount' - ); - assertEq( - address(mockVault).balance, - vaultBalanceBefore + harvestAmount, - 'Vault balance should increase by harvestAmount' - ); - - // Harvest the remaining balance - uint256 remainingBalance = address(sharedMevEscrow).balance; - - vm.expectEmit(true, false, false, true); - emit ISharedMevEscrow.Harvested(mockVault, remainingBalance); - - vm.prank(mockVault); - sharedMevEscrow.harvest(remainingBalance); - - // Verify escrow is now empty and vault received all funds - assertEq(address(sharedMevEscrow).balance, 0, 'Escrow should be empty'); - assertEq( - address(mockVault).balance, - vaultBalanceBefore + fundAmount, - 'Vault should have received all funds' - ); - } + ForkContracts public contracts; + GnoSharedMevEscrow public sharedMevEscrow; + address public other; + address public mockVault; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Deploy a new GnoSharedMevEscrow + sharedMevEscrow = new GnoSharedMevEscrow(address(contracts.vaultsRegistry)); + + // Set up test account + other = makeAddr("other"); + vm.deal(other, 10 ether); + + // Register a mock vault in the registry + mockVault = makeAddr("mockVault"); + vm.prank(contracts.vaultsRegistry.owner()); + contracts.vaultsRegistry.addVault(mockVault); + } + + function test_sharedEscrowDeploymentGas() public { + _startSnapshotGas("GnoSharedMevEscrowTest_test_sharedEscrowDeploymentGas"); + new GnoSharedMevEscrow(address(contracts.vaultsRegistry)); + _stopSnapshotGas(); + } + + function test_onlyVaultCanWithdrawAssets() public { + // Attempt to call harvest from a non-vault address should revert + vm.prank(other); + vm.expectRevert(Errors.HarvestFailed.selector); + sharedMevEscrow.harvest(1 ether); + } + + function test_emitsEventOnTransfers() public { + uint256 value = 1 ether; + + // Expect the MevReceived event with the correct value + vm.expectEmit(true, false, false, true); + emit ISharedMevEscrow.MevReceived(value); + + // Send xDAI from the other account + vm.prank(other); + (bool success,) = address(sharedMevEscrow).call{value: value}(""); + vm.assertTrue(success, "xDAI transfer failed"); + } + + function test_worksWithZeroBalance() public { + // Simulate a call from the vault with zero balance in the escrow + vm.prank(mockVault); + uint256 balanceBefore = address(mockVault).balance; + + // Harvest should succeed even with 0 balance + sharedMevEscrow.harvest(0); + + // Verify the balance didn't change + assertEq(address(mockVault).balance, balanceBefore, "Vault balance shouldn't change"); + } + + function test_worksWithNonZeroBalance() public { + // Fund the escrow contract + uint256 fundAmount = 3 ether; + vm.deal(address(sharedMevEscrow), fundAmount); + + // Record the initial balances + uint256 escrowBalanceBefore = address(sharedMevEscrow).balance; + uint256 vaultBalanceBefore = address(mockVault).balance; + + // Harvest a portion of the balance + uint256 harvestAmount = 1 ether; + + // The Harvested event should be emitted with the correct amount + vm.expectEmit(true, false, false, true); + emit ISharedMevEscrow.Harvested(mockVault, harvestAmount); + + // Perform the harvest + vm.prank(mockVault); + sharedMevEscrow.harvest(harvestAmount); + + // Verify the balances changed correctly + assertEq( + address(sharedMevEscrow).balance, + escrowBalanceBefore - harvestAmount, + "Escrow balance should decrease by harvestAmount" + ); + assertEq( + address(mockVault).balance, + vaultBalanceBefore + harvestAmount, + "Vault balance should increase by harvestAmount" + ); + + // Harvest the remaining balance + uint256 remainingBalance = address(sharedMevEscrow).balance; + + vm.expectEmit(true, false, false, true); + emit ISharedMevEscrow.Harvested(mockVault, remainingBalance); + + vm.prank(mockVault); + sharedMevEscrow.harvest(remainingBalance); + + // Verify escrow is now empty and vault received all funds + assertEq(address(sharedMevEscrow).balance, 0, "Escrow should be empty"); + assertEq(address(mockVault).balance, vaultBalanceBefore + fundAmount, "Vault should have received all funds"); + } } diff --git a/test/gnosis/GnoValidatorsChecker.t.sol b/test/gnosis/GnoValidatorsChecker.t.sol index b958004f..7d42e227 100644 --- a/test/gnosis/GnoValidatorsChecker.t.sol +++ b/test/gnosis/GnoValidatorsChecker.t.sol @@ -1,133 +1,125 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {GnoValidatorsChecker} from '../../contracts/validators/GnoValidatorsChecker.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {IVaultEnterExit} from '../../contracts/interfaces/IVaultEnterExit.sol'; -import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {GnoValidatorsChecker} from "../../contracts/validators/GnoValidatorsChecker.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {IVaultEnterExit} from "../../contracts/interfaces/IVaultEnterExit.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; contract GnoValidatorsCheckerTest is Test, GnoHelpers { - // Test contracts - ForkContracts public contracts; - GnoValidatorsChecker public validatorsChecker; - address public vault; - address public prevVersionVault; - address public emptyVault; - address public admin; - address public user; - bytes32 public validRegistryRoot; - - function setUp() public { - // Setup fork and contracts - contracts = _activateGnosisFork(); - - // Deploy a fresh GnoValidatorsChecker - validatorsChecker = new GnoValidatorsChecker( - address(contracts.validatorsRegistry), - address(contracts.keeper), - address(contracts.vaultsRegistry), - address(_depositDataRegistry), - address(contracts.gnoToken) - ); - - // Setup accounts - admin = makeAddr('admin'); - user = makeAddr('user'); - _mintGnoToken(user, 100 ether); - _mintGnoToken(admin, 100 ether); - - // Create and prepare a vault with sufficient funds - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - vault = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); - _depositToVault(vault, 33 ether, user, user); // Deposit enough for 1 validator - _collateralizeGnoVault(address(vault)); - - // Create a previous version vault for testing totalExitingAssets - prevVersionVault = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); - _depositToVault(prevVersionVault, 33 ether, user, user); - _collateralizeGnoVault(address(prevVersionVault)); - - // Create another vault without sufficient funds - emptyVault = _createVault(VaultType.GnoVault, admin, initParams, false); - - // Get valid registry root - validRegistryRoot = contracts.validatorsRegistry.get_deposit_root(); - } - - // Test getExitQueueCumulativeTickets and getExitQueueMissingAssets with an empty exit queue - function testGetExitQueueFunctions_EmptyQueue() public view { - // Get cumulative tickets for empty queue - uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(emptyVault); - - // Get missing assets with zero pending assets - uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( - emptyVault, - 0, // withdrawingAssets - cumulativeTickets // targetCumulativeTickets (same as current since queue is empty) - ); - - // Verify expected values for empty queue - assertEq(cumulativeTickets, 0, 'Cumulative tickets should be 0 for empty vault'); - assertEq(missingAssets, 0, 'Missing assets should be 0 for empty vault'); - } - - // Test getExitQueueCumulativeTickets and getExitQueueMissingAssets after updating state - function testGetExitQueueFunctions_AfterStateUpdate() public { - // Enter exit queue - uint256 sharesToExit = IVaultState(prevVersionVault).convertToShares(2 ether); - vm.prank(user); - IVaultEnterExit(prevVersionVault).enterExitQueue(sharesToExit, user); - - _upgradeVault(VaultType.GnoVault, address(prevVersionVault)); - - // Get initial exit queue state - uint256 initialCumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets( - prevVersionVault - ); - uint256 initialMissingAssets = validatorsChecker.getExitQueueMissingAssets( - prevVersionVault, - 0, // withdrawingAssets - initialCumulativeTickets // targetCumulativeTickets - ); - - // Update vault state - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - prevVersionVault, - int160(int256(0)), - uint160(0) - ); - validatorsChecker.updateVaultState(prevVersionVault, harvestParams); - - // Get exit queue state after update - uint256 updatedCumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets( - prevVersionVault - ); - uint256 updatedMissingAssets = validatorsChecker.getExitQueueMissingAssets( - prevVersionVault, - 0, // withdrawingAssets - initialCumulativeTickets // use same target as before for fair comparison - ); - - // After state update, the queue data may change depending on implementation - // At minimum, verify the function doesn't revert and returns reasonable values - assertTrue( - updatedCumulativeTickets >= initialCumulativeTickets, - 'Cumulative tickets should not decrease after state update' - ); - - // Missing assets should not increase after a state update - assertTrue( - updatedMissingAssets <= initialMissingAssets, - 'Missing assets should not increase after state update' - ); - } + // Test contracts + ForkContracts public contracts; + GnoValidatorsChecker public validatorsChecker; + address public vault; + address public prevVersionVault; + address public emptyVault; + address public admin; + address public user; + bytes32 public validRegistryRoot; + + function setUp() public { + // Setup fork and contracts + contracts = _activateGnosisFork(); + + // Deploy a fresh GnoValidatorsChecker + validatorsChecker = new GnoValidatorsChecker( + address(contracts.validatorsRegistry), + address(contracts.keeper), + address(contracts.vaultsRegistry), + address(_depositDataRegistry), + address(contracts.gnoToken) + ); + + // Setup accounts + admin = makeAddr("admin"); + user = makeAddr("user"); + _mintGnoToken(user, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Create and prepare a vault with sufficient funds + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + vault = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + _depositToVault(vault, 33 ether, user, user); // Deposit enough for 1 validator + _collateralizeGnoVault(address(vault)); + + // Create a previous version vault for testing totalExitingAssets + prevVersionVault = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); + _depositToVault(prevVersionVault, 33 ether, user, user); + _collateralizeGnoVault(address(prevVersionVault)); + + // Create another vault without sufficient funds + emptyVault = _createVault(VaultType.GnoVault, admin, initParams, false); + + // Get valid registry root + validRegistryRoot = contracts.validatorsRegistry.get_deposit_root(); + } + + // Test getExitQueueCumulativeTickets and getExitQueueMissingAssets with an empty exit queue + function testGetExitQueueFunctions_EmptyQueue() public view { + // Get cumulative tickets for empty queue + uint256 cumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(emptyVault); + + // Get missing assets with zero pending assets + uint256 missingAssets = validatorsChecker.getExitQueueMissingAssets( + emptyVault, + 0, // withdrawingAssets + cumulativeTickets // targetCumulativeTickets (same as current since queue is empty) + ); + + // Verify expected values for empty queue + assertEq(cumulativeTickets, 0, "Cumulative tickets should be 0 for empty vault"); + assertEq(missingAssets, 0, "Missing assets should be 0 for empty vault"); + } + + // Test getExitQueueCumulativeTickets and getExitQueueMissingAssets after updating state + function testGetExitQueueFunctions_AfterStateUpdate() public { + // Enter exit queue + uint256 sharesToExit = IVaultState(prevVersionVault).convertToShares(2 ether); + vm.prank(user); + IVaultEnterExit(prevVersionVault).enterExitQueue(sharesToExit, user); + + _upgradeVault(VaultType.GnoVault, address(prevVersionVault)); + + // Get initial exit queue state + uint256 initialCumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(prevVersionVault); + uint256 initialMissingAssets = validatorsChecker.getExitQueueMissingAssets( + prevVersionVault, + 0, // withdrawingAssets + initialCumulativeTickets // targetCumulativeTickets + ); + + // Update vault state + IKeeperRewards.HarvestParams memory harvestParams = + _setGnoVaultReward(prevVersionVault, int160(int256(0)), uint160(0)); + validatorsChecker.updateVaultState(prevVersionVault, harvestParams); + + // Get exit queue state after update + uint256 updatedCumulativeTickets = validatorsChecker.getExitQueueCumulativeTickets(prevVersionVault); + uint256 updatedMissingAssets = validatorsChecker.getExitQueueMissingAssets( + prevVersionVault, + 0, // withdrawingAssets + initialCumulativeTickets // use same target as before for fair comparison + ); + + // After state update, the queue data may change depending on implementation + // At minimum, verify the function doesn't revert and returns reasonable values + assertTrue( + updatedCumulativeTickets >= initialCumulativeTickets, + "Cumulative tickets should not decrease after state update" + ); + + // Missing assets should not increase after a state update + assertTrue( + updatedMissingAssets <= initialMissingAssets, "Missing assets should not increase after state update" + ); + } } diff --git a/test/gnosis/GnoVault.t.sol b/test/gnosis/GnoVault.t.sol index 22c8a7b8..85b36376 100644 --- a/test/gnosis/GnoVault.t.sol +++ b/test/gnosis/GnoVault.t.sol @@ -1,366 +1,341 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {GnoVault} from "../../contracts/vaults/gnosis/GnoVault.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoVaultTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoVault public vault; - - address public sender; - address public receiver; - address public admin; - address public referrer; - address public validatorsManager; - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - referrer = makeAddr('referrer'); - validatorsManager = makeAddr('validatorsManager'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(admin, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); - vault = GnoVault(payable(vaultAddr)); - - // Set validatorsManager for the vault - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - vm.deal(validatorsManager, 1 ether); - } - - function test_cannotInitializeTwice() public { - // Try to initialize the vault again, which should fail - vm.expectRevert(Initializable.InvalidInitialization.selector); - vault.initialize('0x'); - } - - function test_deploysCorrectly() public { - // Create a new vault to test deployment - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - _startSnapshotGas('GnoVaultTest_test_deploysCorrectly'); - address vaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); - _stopSnapshotGas(); - - GnoVault newVault = GnoVault(payable(vaultAddr)); - - // Verify the vault was deployed correctly - ( - uint128 queuedShares, - uint128 unclaimedAssets, - uint128 totalExitingTickets, - uint128 totalExitingAssets, - uint256 totalTickets - ) = newVault.getExitQueueData(); - assertEq(newVault.vaultId(), keccak256('GnoVault')); - assertEq(newVault.version(), 3); - assertEq(newVault.admin(), admin); - assertEq(newVault.capacity(), 1000 ether); - assertEq(newVault.feePercent(), 1000); - assertEq(newVault.feeRecipient(), admin); - assertEq(newVault.validatorsManager(), _depositDataRegistry); - assertEq(newVault.totalShares(), _securityDeposit); - assertEq(newVault.totalAssets(), _securityDeposit); - assertEq(newVault.validatorsManagerNonce(), 0); - assertEq(queuedShares, 0); - assertEq(unclaimedAssets, 0); - assertEq(totalExitingAssets, 0); - assertEq(totalExitingTickets, 0); - assertEq(totalTickets, 0); - } - - function test_upgradesCorrectly() public { - // Create a v2 vault (previous version) - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); - GnoVault prevVault = GnoVault(payable(vaultAddr)); - - // Deposit some GNO - _depositToVault(address(prevVault), 15 ether, sender, sender); - - // Register a validator - _registerGnoValidator(address(prevVault), 1 ether, true); - - // Enter exit queue with some shares - vm.prank(sender); - prevVault.enterExitQueue(10 ether, sender); - - // Record state before upgrade - uint256 totalSharesBefore = prevVault.totalShares(); - uint256 totalAssetsBefore = prevVault.totalAssets(); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(prevVault)).totalExitingAssets(); - uint256 queuedSharesBefore = IVaultStateV2(address(prevVault)).queuedShares(); - uint256 senderBalanceBefore = prevVault.getShares(sender); - - // Verify current version - assertEq(prevVault.vaultId(), keccak256('GnoVault')); - assertEq(prevVault.version(), 2); - - // Check validator registry allowance - assertEq( - contracts.gnoToken.allowance(address(prevVault), address(contracts.validatorsRegistry)), - 0 - ); - - // Upgrade the vault - _startSnapshotGas('GnoVaultTest_test_upgradesCorrectly'); - _upgradeVault(VaultType.GnoVault, address(prevVault)); - _stopSnapshotGas(); - - // Check that the vault was upgraded correctly - (uint128 queuedShares, , , uint128 totalExitingAssets, ) = prevVault.getExitQueueData(); - assertEq(prevVault.vaultId(), keccak256('GnoVault')); - assertEq(prevVault.version(), 3); - assertEq(prevVault.admin(), admin); - assertEq(prevVault.capacity(), 1000 ether); - assertEq(prevVault.feePercent(), 1000); - assertEq(prevVault.feeRecipient(), admin); - assertEq(prevVault.validatorsManager(), _depositDataRegistry); - - // State should be preserved - assertEq(prevVault.totalShares(), totalSharesBefore); - assertEq(prevVault.totalAssets(), totalAssetsBefore); - assertEq(prevVault.validatorsManagerNonce(), 0); - assertEq(prevVault.getShares(sender), senderBalanceBefore); - assertEq(queuedShares, queuedSharesBefore); - assertEq(totalExitingAssets, totalExitingAssetsBefore); - - // Allowance should be set after upgrade - assertEq( - contracts.gnoToken.allowance(address(prevVault), address(contracts.validatorsRegistry)), - type(uint256).max - ); - } - - function test_exitQueue_works() public { - // Collateralize the vault first - _collateralizeGnoVault(address(vault)); - - // Deposit GNO into the vault - uint256 depositAmount = 10 ether; - _depositToVault(address(vault), depositAmount, sender, sender); - - // Get initial state - uint256 senderSharesBefore = vault.getShares(sender); - ( - uint128 queuedSharesBefore, - uint128 unclaimedAssetsBefore, - , - uint128 totalExitingAssetsBefore, - uint256 totalTicketsBefore - ) = vault.getExitQueueData(); - - // Amount to exit with - uint256 exitAmount = senderSharesBefore / 2; - - // Enter exit queue - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(sender); - _startSnapshotGas('GnoVaultTest_test_exitQueue_works'); - uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); - _stopSnapshotGas(); - - ( - uint128 queuedSharesAfter, - uint128 unclaimedAssetsAfter, - , - uint128 totalExitingAssetsAfter, - uint256 totalTicketsAfter - ) = vault.getExitQueueData(); - - // Check state after entering exit queue - assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, 'Sender shares not reduced'); - assertEq(queuedSharesAfter, queuedSharesBefore + exitAmount, 'Queued shares not increased'); - assertEq(unclaimedAssetsAfter, unclaimedAssetsBefore, 'Unclaimed assets should not change'); - assertEq( - totalExitingAssetsAfter, - totalExitingAssetsBefore, - 'Total exiting assets should not change' - ); - assertEq(totalTicketsAfter, totalTicketsBefore, 'Total tickets should not change'); - - queuedSharesBefore = queuedSharesAfter; - unclaimedAssetsBefore = unclaimedAssetsAfter; - totalExitingAssetsBefore = totalExitingAssetsAfter; - totalTicketsBefore = totalTicketsAfter; - - _mintGnoToken( - address(vault), - totalExitingAssetsAfter + vault.convertToAssets(queuedSharesAfter) - ); - - // Process exit queue by updating state - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - (queuedSharesAfter, unclaimedAssetsAfter, , totalExitingAssetsAfter, totalTicketsAfter) = vault - .getExitQueueData(); - assertLt( - queuedSharesAfter, - queuedSharesBefore, - 'Queued shares should be reduced after processing exit queue' - ); - assertGt( - unclaimedAssetsAfter, - unclaimedAssetsBefore, - 'Unclaimed assets should increase after processing exit queue' - ); - assertLe( - totalExitingAssetsAfter, - totalExitingAssetsBefore, - 'Total exiting assets should not change after processing exit queue' - ); - assertGt( - totalTicketsAfter, - totalTicketsBefore, - 'Total tickets should increase after processing exit queue' - ); - - // Check that position can be found in exit queue - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Wait for the claiming delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Verify exited assets can be calculated - (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = vault - .calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); - - // Assets should be exited and claimable - assertApproxEqAbs(leftTickets, 0, 1, 'All tickets should be processed'); - assertGt(exitedTickets, 0, 'No tickets exited'); - assertGt(exitedAssets, 0, 'No assets exited'); - - // Claim exited assets - uint256 receiverBalanceBefore = contracts.gnoToken.balanceOf(receiver); - - vm.prank(receiver); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - - // Verify receiver got their GNO - uint256 receiverBalanceAfter = contracts.gnoToken.balanceOf(receiver); - assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver didn't get GNO tokens"); - assertEq( - receiverBalanceAfter, - receiverBalanceBefore + exitedAssets, - 'Incorrect amount received' - ); - } - - function test_vaultId() public view { - bytes32 expectedId = keccak256('GnoVault'); - assertEq(vault.vaultId(), expectedId, 'Invalid vault ID'); - } - - function test_vaultVersion() public view { - assertEq(vault.version(), 3, 'Invalid vault version'); - } - - function test_withdrawValidator_validatorsManager() public { - // First deposit and register a validator - _depositToVault(address(vault), 10 ether, sender, sender); - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // Execute withdrawal as validatorsManager - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - - vm.prank(validatorsManager); - _startSnapshotGas('GnoVaultTest_test_withdrawValidator_validatorsManager'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - - // Verify no error - test passes if the transaction completes successfully - } - - function test_withdrawValidator_osTokenRedeemer() public { - // Set osToken redeemer - address osTokenRedeemer = makeAddr('osTokenRedeemer'); - vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); - contracts.osTokenConfig.setRedeemer(osTokenRedeemer); - - // Fund the redeemer account - uint256 withdrawFee = 0.1 ether; - vm.deal(osTokenRedeemer, withdrawFee); - - // First deposit and register a validator - _depositToVault(address(vault), 10 ether, sender, sender); - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // Execute withdrawal as osTokenRedeemer - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - - vm.prank(osTokenRedeemer); - _startSnapshotGas('GnoVaultTest_test_withdrawValidator_osTokenRedeemer'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - - // Verify no error - test passes if the transaction completes successfully - } - - function test_withdrawValidator_unknown() public { - // Create an unknown address - address unknown = makeAddr('unknown'); - - // Fund the unknown account - uint256 withdrawFee = 0.1 ether; - vm.deal(unknown, withdrawFee); - - // First deposit and register a validator - _depositToVault(address(vault), 10 ether, sender, sender); - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // Execute withdrawal as an unknown address - should fail - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - - vm.prank(unknown); - _startSnapshotGas('GnoVaultTest_test_withdrawValidator_unknown'); - vm.expectRevert(Errors.AccessDenied.selector); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } + ForkContracts public contracts; + GnoVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + referrer = makeAddr("referrer"); + validatorsManager = makeAddr("validatorsManager"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + vault = GnoVault(payable(vaultAddr)); + + // Set validatorsManager for the vault + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + vm.deal(validatorsManager, 1 ether); + } + + function test_cannotInitializeTwice() public { + // Try to initialize the vault again, which should fail + vm.expectRevert(Initializable.InvalidInitialization.selector); + vault.initialize("0x"); + } + + function test_deploysCorrectly() public { + // Create a new vault to test deployment + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + _startSnapshotGas("GnoVaultTest_test_deploysCorrectly"); + address vaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); + _stopSnapshotGas(); + + GnoVault newVault = GnoVault(payable(vaultAddr)); + + // Verify the vault was deployed correctly + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = newVault.getExitQueueData(); + assertEq(newVault.vaultId(), keccak256("GnoVault")); + assertEq(newVault.version(), 3); + assertEq(newVault.admin(), admin); + assertEq(newVault.capacity(), 1000 ether); + assertEq(newVault.feePercent(), 1000); + assertEq(newVault.feeRecipient(), admin); + assertEq(newVault.validatorsManager(), _depositDataRegistry); + assertEq(newVault.totalShares(), _securityDeposit); + assertEq(newVault.totalAssets(), _securityDeposit); + assertEq(newVault.validatorsManagerNonce(), 0); + assertEq(queuedShares, 0); + assertEq(unclaimedAssets, 0); + assertEq(totalExitingAssets, 0); + assertEq(totalExitingTickets, 0); + assertEq(totalTickets, 0); + } + + function test_upgradesCorrectly() public { + // Create a v2 vault (previous version) + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); + GnoVault prevVault = GnoVault(payable(vaultAddr)); + + // Deposit some GNO + _depositToVault(address(prevVault), 15 ether, sender, sender); + + // Register a validator + _registerGnoValidator(address(prevVault), 1 ether, true); + + // Enter exit queue with some shares + vm.prank(sender); + prevVault.enterExitQueue(10 ether, sender); + + // Record state before upgrade + uint256 totalSharesBefore = prevVault.totalShares(); + uint256 totalAssetsBefore = prevVault.totalAssets(); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(prevVault)).totalExitingAssets(); + uint256 queuedSharesBefore = IVaultStateV2(address(prevVault)).queuedShares(); + uint256 senderBalanceBefore = prevVault.getShares(sender); + + // Verify current version + assertEq(prevVault.vaultId(), keccak256("GnoVault")); + assertEq(prevVault.version(), 2); + + // Check validator registry allowance + assertEq(contracts.gnoToken.allowance(address(prevVault), address(contracts.validatorsRegistry)), 0); + + // Upgrade the vault + _startSnapshotGas("GnoVaultTest_test_upgradesCorrectly"); + _upgradeVault(VaultType.GnoVault, address(prevVault)); + _stopSnapshotGas(); + + // Check that the vault was upgraded correctly + (uint128 queuedShares,,, uint128 totalExitingAssets,) = prevVault.getExitQueueData(); + assertEq(prevVault.vaultId(), keccak256("GnoVault")); + assertEq(prevVault.version(), 3); + assertEq(prevVault.admin(), admin); + assertEq(prevVault.capacity(), 1000 ether); + assertEq(prevVault.feePercent(), 1000); + assertEq(prevVault.feeRecipient(), admin); + assertEq(prevVault.validatorsManager(), _depositDataRegistry); + + // State should be preserved + assertEq(prevVault.totalShares(), totalSharesBefore); + assertEq(prevVault.totalAssets(), totalAssetsBefore); + assertEq(prevVault.validatorsManagerNonce(), 0); + assertEq(prevVault.getShares(sender), senderBalanceBefore); + assertEq(queuedShares, queuedSharesBefore); + assertEq(totalExitingAssets, totalExitingAssetsBefore); + + // Allowance should be set after upgrade + assertEq( + contracts.gnoToken.allowance(address(prevVault), address(contracts.validatorsRegistry)), type(uint256).max + ); + } + + function test_exitQueue_works() public { + // Collateralize the vault first + _collateralizeGnoVault(address(vault)); + + // Deposit GNO into the vault + uint256 depositAmount = 10 ether; + _depositToVault(address(vault), depositAmount, sender, sender); + + // Get initial state + uint256 senderSharesBefore = vault.getShares(sender); + ( + uint128 queuedSharesBefore, + uint128 unclaimedAssetsBefore, + , + uint128 totalExitingAssetsBefore, + uint256 totalTicketsBefore + ) = vault.getExitQueueData(); + + // Amount to exit with + uint256 exitAmount = senderSharesBefore / 2; + + // Enter exit queue + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(sender); + _startSnapshotGas("GnoVaultTest_test_exitQueue_works"); + uint256 positionTicket = vault.enterExitQueue(exitAmount, receiver); + _stopSnapshotGas(); + + ( + uint128 queuedSharesAfter, + uint128 unclaimedAssetsAfter, + , + uint128 totalExitingAssetsAfter, + uint256 totalTicketsAfter + ) = vault.getExitQueueData(); + + // Check state after entering exit queue + assertEq(vault.getShares(sender), senderSharesBefore - exitAmount, "Sender shares not reduced"); + assertEq(queuedSharesAfter, queuedSharesBefore + exitAmount, "Queued shares not increased"); + assertEq(unclaimedAssetsAfter, unclaimedAssetsBefore, "Unclaimed assets should not change"); + assertEq(totalExitingAssetsAfter, totalExitingAssetsBefore, "Total exiting assets should not change"); + assertEq(totalTicketsAfter, totalTicketsBefore, "Total tickets should not change"); + + queuedSharesBefore = queuedSharesAfter; + unclaimedAssetsBefore = unclaimedAssetsAfter; + totalExitingAssetsBefore = totalExitingAssetsAfter; + totalTicketsBefore = totalTicketsAfter; + + _mintGnoToken(address(vault), totalExitingAssetsAfter + vault.convertToAssets(queuedSharesAfter)); + + // Process exit queue by updating state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + (queuedSharesAfter, unclaimedAssetsAfter,, totalExitingAssetsAfter, totalTicketsAfter) = + vault.getExitQueueData(); + assertLt(queuedSharesAfter, queuedSharesBefore, "Queued shares should be reduced after processing exit queue"); + assertGt( + unclaimedAssetsAfter, unclaimedAssetsBefore, "Unclaimed assets should increase after processing exit queue" + ); + assertLe( + totalExitingAssetsAfter, + totalExitingAssetsBefore, + "Total exiting assets should not change after processing exit queue" + ); + assertGt(totalTicketsAfter, totalTicketsBefore, "Total tickets should increase after processing exit queue"); + + // Check that position can be found in exit queue + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Wait for the claiming delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Verify exited assets can be calculated + (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets) = + vault.calculateExitedAssets(receiver, positionTicket, timestamp, uint256(exitQueueIndex)); + + // Assets should be exited and claimable + assertApproxEqAbs(leftTickets, 0, 1, "All tickets should be processed"); + assertGt(exitedTickets, 0, "No tickets exited"); + assertGt(exitedAssets, 0, "No assets exited"); + + // Claim exited assets + uint256 receiverBalanceBefore = contracts.gnoToken.balanceOf(receiver); + + vm.prank(receiver); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + + // Verify receiver got their GNO + uint256 receiverBalanceAfter = contracts.gnoToken.balanceOf(receiver); + assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver didn't get GNO tokens"); + assertEq(receiverBalanceAfter, receiverBalanceBefore + exitedAssets, "Incorrect amount received"); + } + + function test_vaultId() public view { + bytes32 expectedId = keccak256("GnoVault"); + assertEq(vault.vaultId(), expectedId, "Invalid vault ID"); + } + + function test_vaultVersion() public view { + assertEq(vault.version(), 3, "Invalid vault version"); + } + + function test_withdrawValidator_validatorsManager() public { + // First deposit and register a validator + _depositToVault(address(vault), 10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // Execute withdrawal as validatorsManager + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(validatorsManager); + _startSnapshotGas("GnoVaultTest_test_withdrawValidator_validatorsManager"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_osTokenRedeemer() public { + // Set osToken redeemer + address osTokenRedeemer = makeAddr("osTokenRedeemer"); + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(osTokenRedeemer); + + // Fund the redeemer account + uint256 withdrawFee = 0.1 ether; + vm.deal(osTokenRedeemer, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // Execute withdrawal as osTokenRedeemer + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(osTokenRedeemer); + _startSnapshotGas("GnoVaultTest_test_withdrawValidator_osTokenRedeemer"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + + // Verify no error - test passes if the transaction completes successfully + } + + function test_withdrawValidator_unknown() public { + // Create an unknown address + address unknown = makeAddr("unknown"); + + // Fund the unknown account + uint256 withdrawFee = 0.1 ether; + vm.deal(unknown, withdrawFee); + + // First deposit and register a validator + _depositToVault(address(vault), 10 ether, sender, sender); + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // Execute withdrawal as an unknown address - should fail + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + + vm.prank(unknown); + _startSnapshotGas("GnoVaultTest_test_withdrawValidator_unknown"); + vm.expectRevert(Errors.AccessDenied.selector); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } } diff --git a/test/gnosis/GnoVaultExitQueue.t.sol b/test/gnosis/GnoVaultExitQueue.t.sol index 07cbc864..8d3af120 100644 --- a/test/gnosis/GnoVaultExitQueue.t.sol +++ b/test/gnosis/GnoVaultExitQueue.t.sol @@ -1,329 +1,291 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test, console} from '../../lib/forge-std/src/Test.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; -import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; +import {Test, console} from "../../lib/forge-std/src/Test.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; +import {GnoVault} from "../../contracts/vaults/gnosis/GnoVault.sol"; interface IVaultStateV2 { - function totalExitingAssets() external view returns (uint128); - function queuedShares() external view returns (uint128); + function totalExitingAssets() external view returns (uint128); + function queuedShares() external view returns (uint128); } contract GnoVaultExitQueueTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoVault public vault; - - address public vaultAddr; - address public admin; - address public user1; - address public user2; - address public user3; - - uint256 public depositAmount = 10 ether; - uint256 public exitAmount = 5 ether; - - uint256 public user1InitialGno; - uint256 public user2InitialGno; - uint256 public user3InitialGno; - - uint256 public timestamp1; - uint256 public timestamp2; - uint256 public timestamp3; - uint256 public timestamp4; - - uint256 public positionTicket1; - uint256 public positionTicket2; - uint256 public positionTicket3; - uint256 public positionTicket4; - - function setUp() public { - contracts = _activateGnosisFork(); - - // Set up test accounts - admin = makeAddr('admin'); - user1 = makeAddr('user1'); - user2 = makeAddr('user2'); - user3 = makeAddr('user3'); - - // Fund accounts - _mintGnoToken(admin, 100 ether); - _mintGnoToken(user1, 100 ether); - _mintGnoToken(user2, 100 ether); - _mintGnoToken(user3, 100 ether); - - // Step 1: Create a v2 GNO vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - vaultAddr = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); - vault = GnoVault(payable(vaultAddr)); - } - - function testVaultV2ToV3ExitQueue() public { - // Verify initial vault version - assertEq(vault.version(), 2, 'Vault should be version 2'); - - // Collateralize the vault - _collateralizeGnoVault(vaultAddr); - - // Make deposits for users - uint256 depositShares = vault.convertToShares(depositAmount); - _depositToVault(vaultAddr, depositAmount, user1, user1); - _depositToVault(vaultAddr, depositAmount, user2, user2); - _depositToVault(vaultAddr, depositAmount, user3, user3); - - // remove deposited GNO token from the vault - uint256 withdrawableAssets = vault.withdrawableAssets(); - vm.prank(vaultAddr); - contracts.gnoToken.transfer(address(1), withdrawableAssets); - - // Verify initial shares - assertEq(vault.getShares(user1), depositShares, 'User1 initial shares incorrect'); - assertEq(vault.getShares(user2), depositShares, 'User2 initial shares incorrect'); - assertEq(vault.getShares(user3), depositShares, 'User3 initial shares incorrect'); - - // Record initial GNO balances - user1InitialGno = contracts.gnoToken.balanceOf(user1); - user2InitialGno = contracts.gnoToken.balanceOf(user2); - user3InitialGno = contracts.gnoToken.balanceOf(user3); - - // Step 2: Add 3 exit requests to the vault - uint256 exitShares = vault.convertToShares(exitAmount); - uint256 totalExitingAssetsBefore = IVaultStateV2(address(vault)).totalExitingAssets(); - - timestamp1 = vm.getBlockTimestamp(); - vm.prank(user1); - positionTicket1 = vault.enterExitQueue(exitShares, user1); - - timestamp2 = vm.getBlockTimestamp(); - vm.prank(user2); - positionTicket2 = vault.enterExitQueue(exitShares, user2); - - timestamp3 = vm.getBlockTimestamp(); - vm.prank(user3); - positionTicket3 = vault.enterExitQueue(exitShares, user3); - - // Verify exit requests are in the queue - assertEq( - IVaultStateV2(address(vault)).totalExitingAssets(), - totalExitingAssetsBefore + exitAmount * 3, - 'Exit requests not added to queue' - ); - - // Step 3: Make 1st and 2nd exit requests claimable - _mintGnoToken( - vaultAddr, - vault.convertToAssets(exitAmount * 2) // Just enough for 2 requests - ); - - // Update state to process exit requests (should process the first 2) - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vaultAddr, 0, 0); - vault.updateState(harvestParams); - - // Advance time to make exit requests claimable - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - - // Verify first and second exit positions are claimable - int256 exitQueueIndex1 = vault.getExitQueueIndex(positionTicket1); - assertGt(exitQueueIndex1, -1, 'Exit queue index not found for position 1'); - (uint256 leftTickets1, , uint256 exitedAssets1) = vault.calculateExitedAssets( - user1, - positionTicket1, - timestamp1, - uint256(exitQueueIndex1) - ); - assertEq(leftTickets1, 0, 'Position 1 should be fully processed'); - assertGt(exitedAssets1, 0, 'Position 1 should have exited assets'); - - int256 exitQueueIndex2 = vault.getExitQueueIndex(positionTicket2); - assertGt(exitQueueIndex2, -1, 'Exit queue index not found for position 2'); - (uint256 leftTickets2, , uint256 exitedAssets2) = vault.calculateExitedAssets( - user2, - positionTicket2, - timestamp2, - uint256(exitQueueIndex2) - ); - assertEq(leftTickets2, 0, 'Position 2 should be fully processed'); - assertGt(exitedAssets2, 0, 'Position 2 should have exited assets'); - - // Verify third exit position is not yet claimable - int256 exitQueueIndex3 = vault.getExitQueueIndex(positionTicket3); - assertEq(exitQueueIndex3, -1, 'Exit queue index found for position 3'); - - // Step 4: Claim 2nd exit request - uint256 exitedAssets2Claimed = exitedAssets2; - vm.prank(user2); - _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position2_before_upgrade'); - vault.claimExitedAssets(positionTicket2, timestamp2, uint256(exitQueueIndex2)); - _stopSnapshotGas(); - - // Verify user2 received their GNO - uint256 user2GnoAfterClaim = contracts.gnoToken.balanceOf(user2); - assertEq( - user2GnoAfterClaim, - user2InitialGno + exitedAssets2Claimed, - 'User2 received incorrect amount of GNO tokens' - ); - - // Step 5: Upgrade vault to v3 - _upgradeVault(VaultType.GnoVault, vaultAddr); - - // Verify upgrade was successful - assertEq(vault.version(), 3, 'Vault not upgraded to v3'); - - // Step 6: Create another exit request - uint256 remainingShares = vault.getShares(user2); - uint256 remainingAssets = vault.convertToAssets(vault.getShares(user2)); - vm.prank(user2); - positionTicket4 = vault.enterExitQueue(remainingShares, user2); - timestamp4 = vm.getBlockTimestamp(); - - // Advance time to make exit requests claimable - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - - // Step 7: Make all exit requests claimable - _mintGnoToken( - vaultAddr, - vault.convertToAssets(exitAmount * 2 + remainingAssets) // Enough for the rest - ); - - // Update state again to process all exit requests - harvestParams = _setGnoVaultReward(vaultAddr, 0, 0); - vault.updateState(harvestParams); - - // Step 8: Claim all exit requests - - // Claim 1st exit request (user1) - vm.prank(user1); - _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position1_after_upgrade'); - vault.claimExitedAssets(positionTicket1, timestamp1, uint256(exitQueueIndex1)); - _stopSnapshotGas(); - - // Verify user1 received their GNO - uint256 user1GnoAfterClaim = contracts.gnoToken.balanceOf(user1); - assertApproxEqAbs( - user1GnoAfterClaim, - user1InitialGno + exitedAssets1, - 1, - 'User1 received incorrect amount of GNO tokens' - ); - - // Claim 3rd exit request (user3) - // Re-get the index as it may have changed after upgrade - exitQueueIndex3 = vault.getExitQueueIndex(positionTicket3); - assertGt(exitQueueIndex3, -1, 'Exit queue index not found for position 3 after upgrade'); - - // Calculate exited assets for position 3 - (, , uint256 exitedAssets3) = vault.calculateExitedAssets( - user3, - positionTicket3, - timestamp3, - uint256(exitQueueIndex3) - ); - assertGt(exitedAssets3, 0, 'Position 3 should have exited assets after upgrade'); - - vm.prank(user3); - _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position3_after_upgrade'); - vault.claimExitedAssets(positionTicket3, timestamp3, uint256(exitQueueIndex3)); - _stopSnapshotGas(); - - // Verify user3 received their GNO - uint256 user3GnoAfterClaim = contracts.gnoToken.balanceOf(user3); - assertApproxEqAbs( - user3GnoAfterClaim, - user3InitialGno + exitedAssets3, - 1, - 'User3 received incorrect amount of GNO tokens' - ); - - // Claim 4th exit request (user2's second request) - int256 exitQueueIndex4 = vault.getExitQueueIndex(positionTicket4); - assertGt(exitQueueIndex4, -1, 'Exit queue index not found for position 4 after upgrade'); - - // Calculate exited assets for position 4 - (, , uint256 exitedAssets4) = vault.calculateExitedAssets( - user2, - positionTicket4, - timestamp4, - uint256(exitQueueIndex4) - ); - assertGt(exitedAssets4, 0, 'Position 4 should have exited assets'); - - vm.prank(user2); - _startSnapshotGas('GnoVaultExitQueueTest_test_claim_position4_after_upgrade'); - vault.claimExitedAssets(positionTicket4, timestamp4, uint256(exitQueueIndex4)); - _stopSnapshotGas(); - - // Verify user2 received the rest of their GNO - uint256 user2GnoFinalClaim = contracts.gnoToken.balanceOf(user2); - assertApproxEqAbs( - user2GnoFinalClaim, - user2GnoAfterClaim + exitedAssets4, - 1, - 'User2 received incorrect amount of GNO tokens on final claim' - ); - - // Verify final share balances - assertEq( - vault.convertToAssets(vault.getShares(user1)), - depositAmount - exitAmount, - 'User1 assets incorrect' - ); - assertEq(vault.getShares(user2), 0, 'User2 should have 0 shares'); - assertEq( - vault.convertToAssets(vault.getShares(user3)), - depositAmount - exitAmount, - 'User3 assets incorrect' - ); - } - - function test_exitingAssetsPenalized() public { - _depositToVault(vaultAddr, depositAmount, user1, user1); - - // Enter half of the deposit into the exit queue - vm.prank(user1); - vault.enterExitQueue(exitAmount, user1); - - uint256 totalExitingAssetsBefore = IVaultStateV2(address(vault)).totalExitingAssets(); - - // Upgrade the vault to v3 - _upgradeVault(VaultType.GnoVault, vaultAddr); - - // Calculate what the penalty should be - (, , , uint128 totalExitingAssets, ) = vault.getExitQueueData(); - int256 penalty = -1 ether; // 1 GNO worth of penalty - uint256 expectedPenalty = (uint256(-penalty) * uint256(totalExitingAssets)) / - (uint256(totalExitingAssets) + uint256(vault.totalAssets())); - - // Set a negative reward (penalty) and update the vault state - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - vaultAddr, - int160(penalty), - 0 - ); - - // Expect the ExitingAssetsPenalized event with the correct penalty amount - vm.expectEmit(true, true, true, true); - emit IVaultState.ExitingAssetsPenalized(expectedPenalty); - - _startSnapshotGas('GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify the exiting assets were penalized - (, , , totalExitingAssets, ) = vault.getExitQueueData(); - assertLt( - totalExitingAssets, - totalExitingAssetsBefore + exitAmount, - 'Exiting assets should be reduced by the penalty' - ); - } + ForkContracts public contracts; + GnoVault public vault; + + address public vaultAddr; + address public admin; + address public user1; + address public user2; + address public user3; + + uint256 public depositAmount = 10 ether; + uint256 public exitAmount = 5 ether; + + uint256 public user1InitialGno; + uint256 public user2InitialGno; + uint256 public user3InitialGno; + + uint256 public timestamp1; + uint256 public timestamp2; + uint256 public timestamp3; + uint256 public timestamp4; + + uint256 public positionTicket1; + uint256 public positionTicket2; + uint256 public positionTicket3; + uint256 public positionTicket4; + + function setUp() public { + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr("admin"); + user1 = makeAddr("user1"); + user2 = makeAddr("user2"); + user3 = makeAddr("user3"); + + // Fund accounts + _mintGnoToken(admin, 100 ether); + _mintGnoToken(user1, 100 ether); + _mintGnoToken(user2, 100 ether); + _mintGnoToken(user3, 100 ether); + + // Step 1: Create a v2 GNO vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + vaultAddr = _createPrevVersionVault(VaultType.GnoVault, admin, initParams, false); + vault = GnoVault(payable(vaultAddr)); + } + + function testVaultV2ToV3ExitQueue() public { + // Verify initial vault version + assertEq(vault.version(), 2, "Vault should be version 2"); + + // Collateralize the vault + _collateralizeGnoVault(vaultAddr); + + // Make deposits for users + uint256 depositShares = vault.convertToShares(depositAmount); + _depositToVault(vaultAddr, depositAmount, user1, user1); + _depositToVault(vaultAddr, depositAmount, user2, user2); + _depositToVault(vaultAddr, depositAmount, user3, user3); + + // remove deposited GNO token from the vault + uint256 withdrawableAssets = vault.withdrawableAssets(); + vm.prank(vaultAddr); + contracts.gnoToken.transfer(address(1), withdrawableAssets); + + // Verify initial shares + assertEq(vault.getShares(user1), depositShares, "User1 initial shares incorrect"); + assertEq(vault.getShares(user2), depositShares, "User2 initial shares incorrect"); + assertEq(vault.getShares(user3), depositShares, "User3 initial shares incorrect"); + + // Record initial GNO balances + user1InitialGno = contracts.gnoToken.balanceOf(user1); + user2InitialGno = contracts.gnoToken.balanceOf(user2); + user3InitialGno = contracts.gnoToken.balanceOf(user3); + + // Step 2: Add 3 exit requests to the vault + uint256 exitShares = vault.convertToShares(exitAmount); + uint256 totalExitingAssetsBefore = IVaultStateV2(address(vault)).totalExitingAssets(); + + timestamp1 = vm.getBlockTimestamp(); + vm.prank(user1); + positionTicket1 = vault.enterExitQueue(exitShares, user1); + + timestamp2 = vm.getBlockTimestamp(); + vm.prank(user2); + positionTicket2 = vault.enterExitQueue(exitShares, user2); + + timestamp3 = vm.getBlockTimestamp(); + vm.prank(user3); + positionTicket3 = vault.enterExitQueue(exitShares, user3); + + // Verify exit requests are in the queue + assertEq( + IVaultStateV2(address(vault)).totalExitingAssets(), + totalExitingAssetsBefore + exitAmount * 3, + "Exit requests not added to queue" + ); + + // Step 3: Make 1st and 2nd exit requests claimable + _mintGnoToken( + vaultAddr, + vault.convertToAssets(exitAmount * 2) // Just enough for 2 requests + ); + + // Update state to process exit requests (should process the first 2) + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vaultAddr, 0, 0); + vault.updateState(harvestParams); + + // Advance time to make exit requests claimable + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Verify first and second exit positions are claimable + int256 exitQueueIndex1 = vault.getExitQueueIndex(positionTicket1); + assertGt(exitQueueIndex1, -1, "Exit queue index not found for position 1"); + (uint256 leftTickets1,, uint256 exitedAssets1) = + vault.calculateExitedAssets(user1, positionTicket1, timestamp1, uint256(exitQueueIndex1)); + assertEq(leftTickets1, 0, "Position 1 should be fully processed"); + assertGt(exitedAssets1, 0, "Position 1 should have exited assets"); + + int256 exitQueueIndex2 = vault.getExitQueueIndex(positionTicket2); + assertGt(exitQueueIndex2, -1, "Exit queue index not found for position 2"); + (uint256 leftTickets2,, uint256 exitedAssets2) = + vault.calculateExitedAssets(user2, positionTicket2, timestamp2, uint256(exitQueueIndex2)); + assertEq(leftTickets2, 0, "Position 2 should be fully processed"); + assertGt(exitedAssets2, 0, "Position 2 should have exited assets"); + + // Verify third exit position is not yet claimable + int256 exitQueueIndex3 = vault.getExitQueueIndex(positionTicket3); + assertEq(exitQueueIndex3, -1, "Exit queue index found for position 3"); + + // Step 4: Claim 2nd exit request + uint256 exitedAssets2Claimed = exitedAssets2; + vm.prank(user2); + _startSnapshotGas("GnoVaultExitQueueTest_test_claim_position2_before_upgrade"); + vault.claimExitedAssets(positionTicket2, timestamp2, uint256(exitQueueIndex2)); + _stopSnapshotGas(); + + // Verify user2 received their GNO + uint256 user2GnoAfterClaim = contracts.gnoToken.balanceOf(user2); + assertEq( + user2GnoAfterClaim, user2InitialGno + exitedAssets2Claimed, "User2 received incorrect amount of GNO tokens" + ); + + // Step 5: Upgrade vault to v3 + _upgradeVault(VaultType.GnoVault, vaultAddr); + + // Verify upgrade was successful + assertEq(vault.version(), 3, "Vault not upgraded to v3"); + + // Step 6: Create another exit request + uint256 remainingShares = vault.getShares(user2); + uint256 remainingAssets = vault.convertToAssets(vault.getShares(user2)); + vm.prank(user2); + positionTicket4 = vault.enterExitQueue(remainingShares, user2); + timestamp4 = vm.getBlockTimestamp(); + + // Advance time to make exit requests claimable + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Step 7: Make all exit requests claimable + _mintGnoToken( + vaultAddr, + vault.convertToAssets(exitAmount * 2 + remainingAssets) // Enough for the rest + ); + + // Update state again to process all exit requests + harvestParams = _setGnoVaultReward(vaultAddr, 0, 0); + vault.updateState(harvestParams); + + // Step 8: Claim all exit requests + + // Claim 1st exit request (user1) + vm.prank(user1); + _startSnapshotGas("GnoVaultExitQueueTest_test_claim_position1_after_upgrade"); + vault.claimExitedAssets(positionTicket1, timestamp1, uint256(exitQueueIndex1)); + _stopSnapshotGas(); + + // Verify user1 received their GNO + uint256 user1GnoAfterClaim = contracts.gnoToken.balanceOf(user1); + assertApproxEqAbs( + user1GnoAfterClaim, user1InitialGno + exitedAssets1, 1, "User1 received incorrect amount of GNO tokens" + ); + + // Claim 3rd exit request (user3) + // Re-get the index as it may have changed after upgrade + exitQueueIndex3 = vault.getExitQueueIndex(positionTicket3); + assertGt(exitQueueIndex3, -1, "Exit queue index not found for position 3 after upgrade"); + + // Calculate exited assets for position 3 + (,, uint256 exitedAssets3) = + vault.calculateExitedAssets(user3, positionTicket3, timestamp3, uint256(exitQueueIndex3)); + assertGt(exitedAssets3, 0, "Position 3 should have exited assets after upgrade"); + + vm.prank(user3); + _startSnapshotGas("GnoVaultExitQueueTest_test_claim_position3_after_upgrade"); + vault.claimExitedAssets(positionTicket3, timestamp3, uint256(exitQueueIndex3)); + _stopSnapshotGas(); + + // Verify user3 received their GNO + uint256 user3GnoAfterClaim = contracts.gnoToken.balanceOf(user3); + assertApproxEqAbs( + user3GnoAfterClaim, user3InitialGno + exitedAssets3, 1, "User3 received incorrect amount of GNO tokens" + ); + + // Claim 4th exit request (user2's second request) + int256 exitQueueIndex4 = vault.getExitQueueIndex(positionTicket4); + assertGt(exitQueueIndex4, -1, "Exit queue index not found for position 4 after upgrade"); + + // Calculate exited assets for position 4 + (,, uint256 exitedAssets4) = + vault.calculateExitedAssets(user2, positionTicket4, timestamp4, uint256(exitQueueIndex4)); + assertGt(exitedAssets4, 0, "Position 4 should have exited assets"); + + vm.prank(user2); + _startSnapshotGas("GnoVaultExitQueueTest_test_claim_position4_after_upgrade"); + vault.claimExitedAssets(positionTicket4, timestamp4, uint256(exitQueueIndex4)); + _stopSnapshotGas(); + + // Verify user2 received the rest of their GNO + uint256 user2GnoFinalClaim = contracts.gnoToken.balanceOf(user2); + assertApproxEqAbs( + user2GnoFinalClaim, + user2GnoAfterClaim + exitedAssets4, + 1, + "User2 received incorrect amount of GNO tokens on final claim" + ); + + // Verify final share balances + assertEq(vault.convertToAssets(vault.getShares(user1)), depositAmount - exitAmount, "User1 assets incorrect"); + assertEq(vault.getShares(user2), 0, "User2 should have 0 shares"); + assertEq(vault.convertToAssets(vault.getShares(user3)), depositAmount - exitAmount, "User3 assets incorrect"); + } + + function test_exitingAssetsPenalized() public { + _depositToVault(vaultAddr, depositAmount, user1, user1); + + // Enter half of the deposit into the exit queue + vm.prank(user1); + vault.enterExitQueue(exitAmount, user1); + + uint256 totalExitingAssetsBefore = IVaultStateV2(address(vault)).totalExitingAssets(); + + // Upgrade the vault to v3 + _upgradeVault(VaultType.GnoVault, vaultAddr); + + // Calculate what the penalty should be + (,,, uint128 totalExitingAssets,) = vault.getExitQueueData(); + int256 penalty = -1 ether; // 1 GNO worth of penalty + uint256 expectedPenalty = (uint256(-penalty) * uint256(totalExitingAssets)) + / (uint256(totalExitingAssets) + uint256(vault.totalAssets())); + + // Set a negative reward (penalty) and update the vault state + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vaultAddr, int160(penalty), 0); + + // Expect the ExitingAssetsPenalized event with the correct penalty amount + vm.expectEmit(true, true, true, true); + emit IVaultState.ExitingAssetsPenalized(expectedPenalty); + + _startSnapshotGas("GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify the exiting assets were penalized + (,,, totalExitingAssets,) = vault.getExitQueueData(); + assertLt( + totalExitingAssets, totalExitingAssetsBefore + exitAmount, "Exiting assets should be reduced by the penalty" + ); + } } diff --git a/test/gnosis/VaultGnoStaking.t.sol b/test/gnosis/VaultGnoStaking.t.sol index 674a53aa..2a8cfe7a 100644 --- a/test/gnosis/VaultGnoStaking.t.sol +++ b/test/gnosis/VaultGnoStaking.t.sol @@ -1,574 +1,493 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; -import {IVaultValidators} from '../../contracts/interfaces/IVaultValidators.sol'; -import {IGnoVault} from '../../contracts/interfaces/IGnoVault.sol'; -import {GnoHelpers} from '../helpers/GnoHelpers.sol'; -import {Errors} from '../../contracts/libraries/Errors.sol'; -import {GnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; +import {IVaultValidators} from "../../contracts/interfaces/IVaultValidators.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {GnoVault} from "../../contracts/vaults/gnosis/GnoVault.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; contract VaultGnoStakingTest is Test, GnoHelpers { - ForkContracts public contracts; - GnoVault public vault; - - address public sender; - address public receiver; - address public admin; - address public referrer; - address public validatorsManager; - - uint256 public depositAmount = 1 ether; - - function setUp() public { - // Activate Gnosis fork and get the contracts - contracts = _activateGnosisFork(); - - // Set up test accounts - sender = makeAddr('sender'); - receiver = makeAddr('receiver'); - admin = makeAddr('admin'); - referrer = makeAddr('referrer'); - validatorsManager = makeAddr('validatorsManager'); - - // Fund accounts with GNO for testing - _mintGnoToken(sender, 100 ether); - _mintGnoToken(admin, 100 ether); - - // Create vault - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, // 10% - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - address vaultAddr = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); - vault = GnoVault(payable(vaultAddr)); - - // set validators manager - vm.prank(admin); - vault.setValidatorsManager(validatorsManager); - vm.deal(validatorsManager, 1 ether); - } - - function test_deposit() public { - // Initial balances - uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); - uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); - uint256 vaultTotalSharesBefore = vault.totalShares(); - uint256 vaultTotalAssetsBefore = vault.totalAssets(); - - // Approve and deposit - vm.startPrank(sender); - contracts.gnoToken.approve(address(vault), depositAmount); - - _startSnapshotGas('VaultGnoStakingTest_test_deposit'); - uint256 shares = vault.deposit(depositAmount, receiver, referrer); - _stopSnapshotGas(); - - vm.stopPrank(); - - // Verify balances changed correctly - assertEq( - contracts.gnoToken.balanceOf(sender), - senderInitialBalance - depositAmount, - 'Sender balance should decrease' - ); - assertEq( - contracts.gnoToken.balanceOf(address(vault)), - vaultInitialBalance + depositAmount, - 'Vault balance should increase' - ); - - // Verify shares minted correctly - assertEq(vault.getShares(receiver), shares, 'Receiver should get correct shares'); - - uint256 expectedShares = vault.convertToShares(depositAmount); - assertApproxEqAbs( - shares, - expectedShares, - 1, - 'Shares should match the expected conversion rate' - ); - - // Verify totalAssets and totalShares updated - assertEq( - vault.totalAssets(), - vaultTotalAssetsBefore + depositAmount, - 'Total assets should increase' - ); - assertEq(vault.totalShares(), vaultTotalSharesBefore + shares, 'Total shares should increase'); - } - - function test_withdrawableAssets() public { - uint256 withdrawableBefore = vault.withdrawableAssets(); - - // Deposit some GNO - _depositGno(depositAmount, sender, receiver); - - // Check withdrawable assets - uint256 withdrawable = vault.withdrawableAssets(); - assertGe( - withdrawable, - withdrawableBefore + depositAmount, - 'Withdrawable assets should include deposited amount' - ); - } - - function test_processTotalAssetsDelta() public { - // Deposit GNO - _depositGno(depositAmount, sender, receiver); - - // Now simulate some xDAI balance that would trigger distribution - vm.deal(vault.mevEscrow(), 1 ether); - - // use the same conversion function as for GnoVault - uint256 vaultBalanceBefore = address(vault).balance; - uint256 expectedAddedSDai = IGnoVault(address(contracts.sdaiToken)).convertToShares( - vaultBalanceBefore + 1 ether - ); - - _collateralizeGnoVault(address(vault)); - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - address(vault), - 0, - 1 ether - ); - - uint256 distributorBalanceBefore = contracts.sdaiToken.balanceOf( - address(contracts.merkleDistributor) - ); - - // Update state which will trigger _processTotalAssetsDelta - _startSnapshotGas('VaultGnoStakingTest_test_processTotalAssetsDelta'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify sDAI was sent to the distributor - assertEq(address(vault).balance, 0, 'Vault should have no xDAI left'); - assertEq( - contracts.sdaiToken.balanceOf(address(contracts.merkleDistributor)), - distributorBalanceBefore + expectedAddedSDai, - 'Distributor should get sDAI' - ); - } - - function test_processTotalAssetsDelta_smallXdaiBalance() public { - // Deposit GNO - _depositGno(depositAmount, sender, sender); - - // Small xDAI amount (below 0.1 ETH threshold) - vm.deal(vault.mevEscrow(), 0.09 ether); - - // Process rewards - _collateralizeGnoVault(address(vault)); - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward( - address(vault), - 1 ether, - 0 - ); - - uint256 mevBalanceBefore = address(vault.mevEscrow()).balance; - - // Update state - _startSnapshotGas('VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance'); - vault.updateState(harvestParams); - _stopSnapshotGas(); - - // Verify small xDAI balance wasn't processed (below 0.1 ETH threshold) - assertEq( - address(vault.mevEscrow()).balance, - mevBalanceBefore, - 'xDAI balance should remain unchanged' - ); - } - - function test_vaultAssets() public { - // Initial check - uint256 initialAssets = vault.totalAssets(); - (uint128 queuedShares, uint128 unclaimedAssets, , uint128 totalExitingAssets, ) = vault - .getExitQueueData(); - uint256 senderDeposit = vault.convertToAssets(queuedShares) + - totalExitingAssets + - unclaimedAssets + - 1 ether; - - // Deposit GNO - _mintGnoToken(sender, senderDeposit); - _depositGno(senderDeposit, sender, receiver); - - // Check assets increased - assertEq( - vault.totalAssets(), - initialAssets + senderDeposit, - 'Total assets should increase by deposit amount' - ); - - // Simulate GNO in validator registry that's withdrawable - _setGnoWithdrawals(address(vault), 1 ether); - - // Since _vaultAssets is internal, we need to check a public function that uses it - uint256 withdrawableAfter = vault.withdrawableAssets(); - assertGe(withdrawableAfter, 1 ether, 'Withdrawable assets should include all assets'); - } - - function test_pullWithdrawals() public { - // 1. Deposit GNO - _depositGno(depositAmount, sender, sender); - - // 2. Register a validator - _registerGnoValidator(address(vault), 1 ether, true); - - // 3. Set up withdrawable GNO in the registry (simulate validator withdrawal) - uint256 withdrawalAmount = 2 ether; - _setGnoWithdrawals(address(vault), withdrawalAmount); - - // Verify the registry shows the correct withdrawable amount - assertEq( - contracts.validatorsRegistry.withdrawableAmount(address(vault)), - withdrawalAmount, - 'Withdrawal amount not set correctly' - ); - - // Record initial balances - uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); - uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); - - // 4. Enter the exit queue with shares - uint256 shares = vault.getShares(sender); - uint256 timestamp = vm.getBlockTimestamp(); - vm.prank(sender); - uint256 positionTicket = vault.enterExitQueue(shares, sender); - - // 5. Process the exit queue - // Update vault state to process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // 6. Claim exited assets - vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - _startSnapshotGas('VaultGnoStakingTest_test_pullWithdrawals'); - vm.prank(sender); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // 7. Verify results - // Sender should have received their GNO - uint256 senderFinalBalance = contracts.gnoToken.balanceOf(sender); - assertGt(senderFinalBalance, senderInitialBalance, 'Sender did not receive exited assets'); - - // Registry should have 0 withdrawable amount - uint256 registryFinalWithdrawable = contracts.validatorsRegistry.withdrawableAmount( - address(vault) - ); - assertEq( - registryFinalWithdrawable, - 0, - 'Registry withdrawable amount should be completely claimed' - ); - - // Vault's GNO balance should have changed due to _pullWithdrawals - uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); - // The vault should have transferred out GNO (either directly or via _pullWithdrawals) - assertLt( - vaultFinalBalance, - vaultInitialBalance + withdrawalAmount, - 'Vault balance should reflect withdrawals' - ); - } - - function test_registerValidators_pullsWithdrawals() public { - // Setup: Set GNO withdrawals in the validators registry - uint256 withdrawalAmount = 2 ether; - _setGnoWithdrawals(address(vault), withdrawalAmount); - uint256 withdrawableBefore = contracts.validatorsRegistry.withdrawableAmount(address(vault)); - - // Get vault's GNO balance before registration - uint256 vaultGnoBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); - - // setup oracle - _startOracleImpersonate(address(contracts.keeper)); - - // Register a validator - this should trigger a withdrawal claim - IKeeperValidators.ApprovalParams memory approvalParams = _getGnoValidatorApproval( - address(vault), - 1 ether, - 'ipfsHash', - false - ); - - vm.prank(validatorsManager); - vault.registerValidators(approvalParams, ''); - - // Verify that withdrawals were pulled by checking the vault's GNO balance increased - uint256 vaultGnoBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); - assertGe( - vaultGnoBalanceAfter, - vaultGnoBalanceBefore + withdrawableBefore - 1 ether, - 'Vault should have received withdrawals' - ); - - // Verify the withdrawable amount is now 0 - uint256 withdrawableAfter = contracts.validatorsRegistry.withdrawableAmount(address(vault)); - assertEq(withdrawableAfter, 0, 'Withdrawable amount should be cleared after claiming'); - - // revert previous state - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidators_succeeds() public { - // Setup oracle - _startOracleImpersonate(address(contracts.keeper)); - - // Test successful registration with 0x01 prefix - _depositGno(1 ether, sender, sender); - IKeeperValidators.ApprovalParams memory approvalParams = _getGnoValidatorApproval( - address(vault), - 1 ether, - 'ipfsHash', - true - ); - - vm.prank(validatorsManager); - _startSnapshotGas('test_registerValidators_succeeds_0x01'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // Test successful registration with 0x02 prefix and valid amount - _depositGno(64 ether, sender, sender); - approvalParams = _getGnoValidatorApproval(address(vault), 64 ether, 'ipfsHash', false); - - vm.prank(validatorsManager); - _startSnapshotGas('test_registerValidators_succeeds_0x02'); - vault.registerValidators(approvalParams, ''); - _stopSnapshotGas(); - - // revert previous state - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_receive_xDai() public { - // Send xDAI directly to the vault - uint256 sendAmount = 0.5 ether; - vm.deal(sender, sendAmount); - - uint256 balanceBefore = address(vault).balance; - - vm.prank(sender); - _startSnapshotGas('VaultGnoStakingTest_test_receive_xDai'); - (bool success, ) = address(vault).call{value: sendAmount}(''); - _stopSnapshotGas(); - - assertTrue(success, 'Failed to send xDAI to vault'); - assertEq( - address(vault).balance, - balanceBefore + sendAmount, - "Vault balance didn't increase correctly" - ); - } - - function test_validatorRegistration_minMaxEffectiveBalance() public { - // 1. Test registration with amount less than min effective balance (should fail) - uint256 tooSmallAmount = 0.5 ether; // Less than the min 1 GNO requirement - _depositGno(tooSmallAmount, sender, sender); - - // Setup oracle - _startOracleImpersonate(address(contracts.keeper)); - - // Prepare registration with too small amount - IKeeperValidators.ApprovalParams memory approvalParams = _getGnoValidatorApproval( - address(vault), - tooSmallAmount, - 'ipfsHash', - false - ); - - // Should fail because amount is too small - vm.prank(validatorsManager); - vm.expectRevert(Errors.InvalidAssets.selector); - vault.registerValidators(approvalParams, ''); - - // 2. Test registration with amount greater than max effective balance (should fail) - uint256 tooLargeAmount = 65 ether; // More than the max 64 GNO requirement - _depositGno(tooLargeAmount, sender, sender); - - // Prepare registration with too large amount - approvalParams = _getGnoValidatorApproval(address(vault), tooLargeAmount, 'ipfsHash', false); - - // Should fail because amount is too large - vm.prank(validatorsManager); - vm.expectRevert(Errors.InvalidAssets.selector); - vault.registerValidators(approvalParams, ''); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_registerValidator_topUp() public { - // Deposit enough GNO for multiple validator registrations - _depositGno(10 ether, sender, sender); - - // Setup oracle for validator registration and top-up - _startOracleImpersonate(address(contracts.keeper)); - - // Step 1: Register a validator first to make it tracked - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // Step 2: Try to top up a non-existing validator (should fail) - bytes memory nonExistingPublicKey = vm.randomBytes(48); - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); - uint256 topUpAmount = (1 ether * 32) / 1 gwei; - bytes32 depositDataRoot = _getDepositDataRoot( - nonExistingPublicKey, - signature, - withdrawalCredentials, - topUpAmount - ); - - // Create top-up data for non-existing validator - bytes memory invalidTopUpData = bytes.concat( - nonExistingPublicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - vm.prank(validatorsManager); - _startSnapshotGas('VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid'); - vm.expectRevert(Errors.InvalidValidators.selector); - vault.fundValidators(invalidTopUpData, ''); - _stopSnapshotGas(); - - // Step 3: Successfully top up the registered validator - // Create valid top-up data using the same public key as the registered validator - depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); - bytes memory validTopUpData = bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(uint64(topUpAmount)) - ); - - // Check for ValidatorFunded event - vm.expectEmit(true, true, true, true); - emit IVaultValidators.ValidatorFunded(publicKey, 32 ether); - - vm.prank(validatorsManager); - _startSnapshotGas('VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid'); - vault.fundValidators(validTopUpData, ''); - _stopSnapshotGas(); - - // Clean up - _stopOracleImpersonate(address(contracts.keeper)); - } - - function test_withdrawValidator_fullFlow() public { - // 1. First deposit and register a validator - _depositGno(10 ether, sender, sender); - _registerGnoValidator(address(vault), 1 ether, false); - - // 2. Ensure validator is tracked - bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); - - // 3. Fund the validators manager - uint256 withdrawFee = 0.1 ether; - vm.deal(validatorsManager, withdrawFee); - - // 4. Execute withdrawal - bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); - vm.prank(validatorsManager); - _startSnapshotGas('VaultGnoStakingTest_test_withdrawValidator_fullFlow'); - vault.withdrawValidators{value: withdrawFee}(withdrawalData, ''); - _stopSnapshotGas(); - } - - function test_transferVaultAssets() public { - _collateralizeGnoVault(address(vault)); - - // Deposit GNO to the vault - (uint128 queuedShares, uint128 unclaimedAssets, , uint128 totalExitingAssets, ) = vault - .getExitQueueData(); - uint256 senderDeposit = vault.convertToAssets(queuedShares) + - totalExitingAssets + - unclaimedAssets + - depositAmount; - _mintGnoToken(sender, senderDeposit); - _depositGno(senderDeposit, sender, sender); - - // Add some funds to test withdrawal - uint256 vaultBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); - uint256 receiverBalanceBefore = contracts.gnoToken.balanceOf(receiver); - - // Enter exit queue - uint256 withdrawalAmount = vault.convertToShares(depositAmount); - vm.prank(sender); - uint256 timestamp = vm.getBlockTimestamp(); - uint256 positionTicket = vault.enterExitQueue(withdrawalAmount, receiver); - - // Process the exit queue (update state) - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); - - // Wait for claim delay to pass - vm.warp(timestamp + _exitingAssetsClaimDelay + 1); - - // Get exit queue index - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); - assertGt(exitQueueIndex, -1, 'Exit queue index not found'); - - // Claim exited assets which will trigger _transferVaultAssets - vm.prank(receiver); - _startSnapshotGas('VaultGnoStakingTest_test_transferVaultAssets'); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); - _stopSnapshotGas(); - - // Verify the transfer occurred - uint256 vaultBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); - uint256 receiverBalanceAfter = contracts.gnoToken.balanceOf(receiver); - - assertLt(vaultBalanceAfter, vaultBalanceBefore, 'Vault balance should decrease'); - assertGt(receiverBalanceAfter, receiverBalanceBefore, 'Receiver balance should increase'); - } - - function test_vaultGnoStaking_init() public { - // Create a vault that calls __VaultGnoStaking_init - bytes memory initParams = abi.encode( - IGnoVault.GnoVaultInitParams({ - capacity: 1000 ether, - feePercent: 1000, - metadataIpfsHash: 'bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u' - }) - ); - - // To test creation and initialization - _startSnapshotGas('VaultGnoStakingTest_test_vaultGnoStaking_init'); - address newVaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); - _stopSnapshotGas(); - - GnoVault newVault = GnoVault(payable(newVaultAddr)); - - // Verify that initialization properly set up the vault - assertGt(newVault.totalShares(), 0, 'Vault should have initial shares for security deposit'); - assertGt(newVault.totalAssets(), 0, 'Vault should have initial assets for security deposit'); - - // Check initial GNO balance matches security deposit - uint256 securityDeposit = 1e9; // Same as defined in VaultGnoStaking - assertEq( - contracts.gnoToken.balanceOf(address(newVault)), - securityDeposit, - 'Incorrect security deposit' - ); - } - - // Helper functions - function _depositGno(uint256 amount, address from, address to) internal { - _depositToVault(address(vault), amount, from, to); - } + ForkContracts public contracts; + GnoVault public vault; + + address public sender; + address public receiver; + address public admin; + address public referrer; + address public validatorsManager; + + uint256 public depositAmount = 1 ether; + + function setUp() public { + // Activate Gnosis fork and get the contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + admin = makeAddr("admin"); + referrer = makeAddr("referrer"); + validatorsManager = makeAddr("validatorsManager"); + + // Fund accounts with GNO for testing + _mintGnoToken(sender, 100 ether); + _mintGnoToken(admin, 100 ether); + + // Create vault + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.GnoVault, admin, initParams, false); + vault = GnoVault(payable(vaultAddr)); + + // set validators manager + vm.prank(admin); + vault.setValidatorsManager(validatorsManager); + vm.deal(validatorsManager, 1 ether); + } + + function test_deposit() public { + // Initial balances + uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + uint256 vaultTotalSharesBefore = vault.totalShares(); + uint256 vaultTotalAssetsBefore = vault.totalAssets(); + + // Approve and deposit + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), depositAmount); + + _startSnapshotGas("VaultGnoStakingTest_test_deposit"); + uint256 shares = vault.deposit(depositAmount, receiver, referrer); + _stopSnapshotGas(); + + vm.stopPrank(); + + // Verify balances changed correctly + assertEq( + contracts.gnoToken.balanceOf(sender), senderInitialBalance - depositAmount, "Sender balance should decrease" + ); + assertEq( + contracts.gnoToken.balanceOf(address(vault)), + vaultInitialBalance + depositAmount, + "Vault balance should increase" + ); + + // Verify shares minted correctly + assertEq(vault.getShares(receiver), shares, "Receiver should get correct shares"); + + uint256 expectedShares = vault.convertToShares(depositAmount); + assertApproxEqAbs(shares, expectedShares, 1, "Shares should match the expected conversion rate"); + + // Verify totalAssets and totalShares updated + assertEq(vault.totalAssets(), vaultTotalAssetsBefore + depositAmount, "Total assets should increase"); + assertEq(vault.totalShares(), vaultTotalSharesBefore + shares, "Total shares should increase"); + } + + function test_withdrawableAssets() public { + uint256 withdrawableBefore = vault.withdrawableAssets(); + + // Deposit some GNO + _depositGno(depositAmount, sender, receiver); + + // Check withdrawable assets + uint256 withdrawable = vault.withdrawableAssets(); + assertGe( + withdrawable, withdrawableBefore + depositAmount, "Withdrawable assets should include deposited amount" + ); + } + + function test_processTotalAssetsDelta() public { + // Deposit GNO + _depositGno(depositAmount, sender, receiver); + + // Now simulate some xDAI balance that would trigger distribution + vm.deal(vault.mevEscrow(), 1 ether); + + // use the same conversion function as for GnoVault + uint256 vaultBalanceBefore = address(vault).balance; + uint256 expectedAddedSDai = + IGnoVault(address(contracts.sdaiToken)).convertToShares(vaultBalanceBefore + 1 ether); + + _collateralizeGnoVault(address(vault)); + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 1 ether); + + uint256 distributorBalanceBefore = contracts.sdaiToken.balanceOf(address(contracts.merkleDistributor)); + + // Update state which will trigger _processTotalAssetsDelta + _startSnapshotGas("VaultGnoStakingTest_test_processTotalAssetsDelta"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify sDAI was sent to the distributor + assertEq(address(vault).balance, 0, "Vault should have no xDAI left"); + assertEq( + contracts.sdaiToken.balanceOf(address(contracts.merkleDistributor)), + distributorBalanceBefore + expectedAddedSDai, + "Distributor should get sDAI" + ); + } + + function test_processTotalAssetsDelta_smallXdaiBalance() public { + // Deposit GNO + _depositGno(depositAmount, sender, sender); + + // Small xDAI amount (below 0.1 ETH threshold) + vm.deal(vault.mevEscrow(), 0.09 ether); + + // Process rewards + _collateralizeGnoVault(address(vault)); + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 1 ether, 0); + + uint256 mevBalanceBefore = address(vault.mevEscrow()).balance; + + // Update state + _startSnapshotGas("VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance"); + vault.updateState(harvestParams); + _stopSnapshotGas(); + + // Verify small xDAI balance wasn't processed (below 0.1 ETH threshold) + assertEq(address(vault.mevEscrow()).balance, mevBalanceBefore, "xDAI balance should remain unchanged"); + } + + function test_vaultAssets() public { + // Initial check + uint256 initialAssets = vault.totalAssets(); + (uint128 queuedShares, uint128 unclaimedAssets,, uint128 totalExitingAssets,) = vault.getExitQueueData(); + uint256 senderDeposit = vault.convertToAssets(queuedShares) + totalExitingAssets + unclaimedAssets + 1 ether; + + // Deposit GNO + _mintGnoToken(sender, senderDeposit); + _depositGno(senderDeposit, sender, receiver); + + // Check assets increased + assertEq(vault.totalAssets(), initialAssets + senderDeposit, "Total assets should increase by deposit amount"); + + // Simulate GNO in validator registry that's withdrawable + _setGnoWithdrawals(address(vault), 1 ether); + + // Since _vaultAssets is internal, we need to check a public function that uses it + uint256 withdrawableAfter = vault.withdrawableAssets(); + assertGe(withdrawableAfter, 1 ether, "Withdrawable assets should include all assets"); + } + + function test_pullWithdrawals() public { + // 1. Deposit GNO + _depositGno(depositAmount, sender, sender); + + // 2. Register a validator + _registerGnoValidator(address(vault), 1 ether, true); + + // 3. Set up withdrawable GNO in the registry (simulate validator withdrawal) + uint256 withdrawalAmount = 2 ether; + _setGnoWithdrawals(address(vault), withdrawalAmount); + + // Verify the registry shows the correct withdrawable amount + assertEq( + contracts.validatorsRegistry.withdrawableAmount(address(vault)), + withdrawalAmount, + "Withdrawal amount not set correctly" + ); + + // Record initial balances + uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + + // 4. Enter the exit queue with shares + uint256 shares = vault.getShares(sender); + uint256 timestamp = vm.getBlockTimestamp(); + vm.prank(sender); + uint256 positionTicket = vault.enterExitQueue(shares, sender); + + // 5. Process the exit queue + // Update vault state to process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // 6. Claim exited assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + _startSnapshotGas("VaultGnoStakingTest_test_pullWithdrawals"); + vm.prank(sender); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // 7. Verify results + // Sender should have received their GNO + uint256 senderFinalBalance = contracts.gnoToken.balanceOf(sender); + assertGt(senderFinalBalance, senderInitialBalance, "Sender did not receive exited assets"); + + // Registry should have 0 withdrawable amount + uint256 registryFinalWithdrawable = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + assertEq(registryFinalWithdrawable, 0, "Registry withdrawable amount should be completely claimed"); + + // Vault's GNO balance should have changed due to _pullWithdrawals + uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); + // The vault should have transferred out GNO (either directly or via _pullWithdrawals) + assertLt(vaultFinalBalance, vaultInitialBalance + withdrawalAmount, "Vault balance should reflect withdrawals"); + } + + function test_registerValidators_pullsWithdrawals() public { + // Setup: Set GNO withdrawals in the validators registry + uint256 withdrawalAmount = 2 ether; + _setGnoWithdrawals(address(vault), withdrawalAmount); + uint256 withdrawableBefore = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + + // Get vault's GNO balance before registration + uint256 vaultGnoBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); + + // setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Register a validator - this should trigger a withdrawal claim + IKeeperValidators.ApprovalParams memory approvalParams = + _getGnoValidatorApproval(address(vault), 1 ether, "ipfsHash", false); + + vm.prank(validatorsManager); + vault.registerValidators(approvalParams, ""); + + // Verify that withdrawals were pulled by checking the vault's GNO balance increased + uint256 vaultGnoBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); + assertGe( + vaultGnoBalanceAfter, + vaultGnoBalanceBefore + withdrawableBefore - 1 ether, + "Vault should have received withdrawals" + ); + + // Verify the withdrawable amount is now 0 + uint256 withdrawableAfter = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + assertEq(withdrawableAfter, 0, "Withdrawable amount should be cleared after claiming"); + + // revert previous state + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidators_succeeds() public { + // Setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Test successful registration with 0x01 prefix + _depositGno(1 ether, sender, sender); + IKeeperValidators.ApprovalParams memory approvalParams = + _getGnoValidatorApproval(address(vault), 1 ether, "ipfsHash", true); + + vm.prank(validatorsManager); + _startSnapshotGas("test_registerValidators_succeeds_0x01"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // Test successful registration with 0x02 prefix and valid amount + _depositGno(64 ether, sender, sender); + approvalParams = _getGnoValidatorApproval(address(vault), 64 ether, "ipfsHash", false); + + vm.prank(validatorsManager); + _startSnapshotGas("test_registerValidators_succeeds_0x02"); + vault.registerValidators(approvalParams, ""); + _stopSnapshotGas(); + + // revert previous state + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_receive_xDai() public { + // Send xDAI directly to the vault + uint256 sendAmount = 0.5 ether; + vm.deal(sender, sendAmount); + + uint256 balanceBefore = address(vault).balance; + + vm.prank(sender); + _startSnapshotGas("VaultGnoStakingTest_test_receive_xDai"); + (bool success,) = address(vault).call{value: sendAmount}(""); + _stopSnapshotGas(); + + assertTrue(success, "Failed to send xDAI to vault"); + assertEq(address(vault).balance, balanceBefore + sendAmount, "Vault balance didn't increase correctly"); + } + + function test_validatorRegistration_minMaxEffectiveBalance() public { + // 1. Test registration with amount less than min effective balance (should fail) + uint256 tooSmallAmount = 0.5 ether; // Less than the min 1 GNO requirement + _depositGno(tooSmallAmount, sender, sender); + + // Setup oracle + _startOracleImpersonate(address(contracts.keeper)); + + // Prepare registration with too small amount + IKeeperValidators.ApprovalParams memory approvalParams = + _getGnoValidatorApproval(address(vault), tooSmallAmount, "ipfsHash", false); + + // Should fail because amount is too small + vm.prank(validatorsManager); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.registerValidators(approvalParams, ""); + + // 2. Test registration with amount greater than max effective balance (should fail) + uint256 tooLargeAmount = 65 ether; // More than the max 64 GNO requirement + _depositGno(tooLargeAmount, sender, sender); + + // Prepare registration with too large amount + approvalParams = _getGnoValidatorApproval(address(vault), tooLargeAmount, "ipfsHash", false); + + // Should fail because amount is too large + vm.prank(validatorsManager); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.registerValidators(approvalParams, ""); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_registerValidator_topUp() public { + // Deposit enough GNO for multiple validator registrations + _depositGno(10 ether, sender, sender); + + // Setup oracle for validator registration and top-up + _startOracleImpersonate(address(contracts.keeper)); + + // Step 1: Register a validator first to make it tracked + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // Step 2: Try to top up a non-existing validator (should fail) + bytes32 nonce = contracts.validatorsRegistry.get_deposit_root(); + bytes memory nonExistingPublicKey = _getDeterministicBytes(nonce, 48); + bytes memory signature = _getDeterministicBytes(nonce, 96); + bytes memory withdrawalCredentials = abi.encodePacked(bytes1(0x02), bytes11(0x0), vault); + uint256 topUpAmount = (1 ether * 32) / 1 gwei; + bytes32 depositDataRoot = + _getDepositDataRoot(nonExistingPublicKey, signature, withdrawalCredentials, topUpAmount); + + // Create top-up data for non-existing validator + bytes memory invalidTopUpData = + bytes.concat(nonExistingPublicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + vm.prank(validatorsManager); + _startSnapshotGas("VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid"); + vm.expectRevert(Errors.InvalidValidators.selector); + vault.fundValidators(invalidTopUpData, ""); + _stopSnapshotGas(); + + // Step 3: Successfully top up the registered validator + // Create valid top-up data using the same public key as the registered validator + depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, topUpAmount); + bytes memory validTopUpData = bytes.concat(publicKey, signature, depositDataRoot, bytes8(uint64(topUpAmount))); + + // Check for ValidatorFunded event + vm.expectEmit(true, true, true, true); + emit IVaultValidators.ValidatorFunded(publicKey, 32 ether); + + vm.prank(validatorsManager); + _startSnapshotGas("VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid"); + vault.fundValidators(validTopUpData, ""); + _stopSnapshotGas(); + + // Clean up + _stopOracleImpersonate(address(contracts.keeper)); + } + + function test_withdrawValidator_fullFlow() public { + // 1. First deposit and register a validator + _depositGno(10 ether, sender, sender); + _registerGnoValidator(address(vault), 1 ether, false); + + // 2. Ensure validator is tracked + bytes memory publicKey = _registerGnoValidator(address(vault), 1 ether, false); + + // 3. Fund the validators manager + uint256 withdrawFee = 0.1 ether; + vm.deal(validatorsManager, withdrawFee); + + // 4. Execute withdrawal + bytes memory withdrawalData = abi.encodePacked(publicKey, bytes8(uint64(32 ether / 1 gwei))); + vm.prank(validatorsManager); + _startSnapshotGas("VaultGnoStakingTest_test_withdrawValidator_fullFlow"); + vault.withdrawValidators{value: withdrawFee}(withdrawalData, ""); + _stopSnapshotGas(); + } + + function test_transferVaultAssets() public { + _collateralizeGnoVault(address(vault)); + + // Deposit GNO to the vault + (uint128 queuedShares, uint128 unclaimedAssets,, uint128 totalExitingAssets,) = vault.getExitQueueData(); + uint256 senderDeposit = + vault.convertToAssets(queuedShares) + totalExitingAssets + unclaimedAssets + depositAmount; + _mintGnoToken(sender, senderDeposit); + _depositGno(senderDeposit, sender, sender); + + // Add some funds to test withdrawal + uint256 vaultBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); + uint256 receiverBalanceBefore = contracts.gnoToken.balanceOf(receiver); + + // Enter exit queue + uint256 withdrawalAmount = vault.convertToShares(depositAmount); + vm.prank(sender); + uint256 timestamp = vm.getBlockTimestamp(); + uint256 positionTicket = vault.enterExitQueue(withdrawalAmount, receiver); + + // Process the exit queue (update state) + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Wait for claim delay to pass + vm.warp(timestamp + _exitingAssetsClaimDelay + 1); + + // Get exit queue index + int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + assertGt(exitQueueIndex, -1, "Exit queue index not found"); + + // Claim exited assets which will trigger _transferVaultAssets + vm.prank(receiver); + _startSnapshotGas("VaultGnoStakingTest_test_transferVaultAssets"); + vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Verify the transfer occurred + uint256 vaultBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); + uint256 receiverBalanceAfter = contracts.gnoToken.balanceOf(receiver); + + assertLt(vaultBalanceAfter, vaultBalanceBefore, "Vault balance should decrease"); + assertGt(receiverBalanceAfter, receiverBalanceBefore, "Receiver balance should increase"); + } + + function test_vaultGnoStaking_init() public { + // Create a vault that calls __VaultGnoStaking_init + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + // To test creation and initialization + _startSnapshotGas("VaultGnoStakingTest_test_vaultGnoStaking_init"); + address newVaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); + _stopSnapshotGas(); + + GnoVault newVault = GnoVault(payable(newVaultAddr)); + + // Verify that initialization properly set up the vault + assertGt(newVault.totalShares(), 0, "Vault should have initial shares for security deposit"); + assertGt(newVault.totalAssets(), 0, "Vault should have initial assets for security deposit"); + + // Check initial GNO balance matches security deposit + uint256 securityDeposit = 1e9; // Same as defined in VaultGnoStaking + assertEq(contracts.gnoToken.balanceOf(address(newVault)), securityDeposit, "Incorrect security deposit"); + } + + // Helper functions + function _depositGno(uint256 amount, address from, address to) internal { + _depositToVault(address(vault), amount, from, to); + } } diff --git a/test/helpers/EthHelpers.sol b/test/helpers/EthHelpers.sol index 9699a447..e231e6f5 100644 --- a/test/helpers/EthHelpers.sol +++ b/test/helpers/EthHelpers.sol @@ -2,429 +2,410 @@ pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; -import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; -import {IOsTokenVaultController} from '../../contracts/interfaces/IOsTokenVaultController.sol'; -import {IOsTokenVaultEscrow} from '../../contracts/interfaces/IOsTokenVaultEscrow.sol'; -import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; -import {IEthValidatorsRegistry} from '../../contracts/interfaces/IEthValidatorsRegistry.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; -import {IConsolidationsChecker} from '../../contracts/interfaces/IConsolidationsChecker.sol'; -import {ConsolidationsChecker} from '../../contracts/validators/ConsolidationsChecker.sol'; -import {EthBlocklistErc20Vault} from '../../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol'; -import {EthBlocklistVault} from '../../contracts/vaults/ethereum/EthBlocklistVault.sol'; -import {EthErc20Vault, IEthErc20Vault} from '../../contracts/vaults/ethereum/EthErc20Vault.sol'; -import {EthGenesisVault} from '../../contracts/vaults/ethereum/EthGenesisVault.sol'; -import {EthPrivErc20Vault} from '../../contracts/vaults/ethereum/EthPrivErc20Vault.sol'; -import {EthPrivVault} from '../../contracts/vaults/ethereum/EthPrivVault.sol'; -import {EthVault, IEthVault} from '../../contracts/vaults/ethereum/EthVault.sol'; -import {EthVaultFactory} from '../../contracts/vaults/ethereum/EthVaultFactory.sol'; -import {EthFoxVault} from '../../contracts/vaults/ethereum/custom/EthFoxVault.sol'; -import {Keeper} from '../../contracts/keeper/Keeper.sol'; -import {ValidatorsConsolidationsMock} from '../../contracts/mocks/ValidatorsConsolidationsMock.sol'; -import {ValidatorsHelpers} from './ValidatorsHelpers.sol'; -import {ValidatorsWithdrawalsMock} from '../../contracts/mocks/ValidatorsWithdrawalsMock.sol'; -import {VaultsRegistry, IVaultsRegistry} from '../../contracts/vaults/VaultsRegistry.sol'; +import {Test} from "forge-std/Test.sol"; +import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; +import {IOsTokenConfig} from "../../contracts/interfaces/IOsTokenConfig.sol"; +import {IOsTokenVaultController} from "../../contracts/interfaces/IOsTokenVaultController.sol"; +import {IOsTokenVaultEscrow} from "../../contracts/interfaces/IOsTokenVaultEscrow.sol"; +import {ISharedMevEscrow} from "../../contracts/interfaces/ISharedMevEscrow.sol"; +import {IEthValidatorsRegistry} from "../../contracts/interfaces/IEthValidatorsRegistry.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; +import {IConsolidationsChecker} from "../../contracts/interfaces/IConsolidationsChecker.sol"; +import {ConsolidationsChecker} from "../../contracts/validators/ConsolidationsChecker.sol"; +import {EthBlocklistErc20Vault} from "../../contracts/vaults/ethereum/EthBlocklistErc20Vault.sol"; +import {EthBlocklistVault} from "../../contracts/vaults/ethereum/EthBlocklistVault.sol"; +import {EthErc20Vault, IEthErc20Vault} from "../../contracts/vaults/ethereum/EthErc20Vault.sol"; +import {EthGenesisVault} from "../../contracts/vaults/ethereum/EthGenesisVault.sol"; +import {EthPrivErc20Vault} from "../../contracts/vaults/ethereum/EthPrivErc20Vault.sol"; +import {EthPrivVault} from "../../contracts/vaults/ethereum/EthPrivVault.sol"; +import {EthVault, IEthVault} from "../../contracts/vaults/ethereum/EthVault.sol"; +import {EthVaultFactory} from "../../contracts/vaults/ethereum/EthVaultFactory.sol"; +import {EthFoxVault} from "../../contracts/vaults/ethereum/custom/EthFoxVault.sol"; +import {Keeper} from "../../contracts/keeper/Keeper.sol"; +import {ValidatorsConsolidationsMock} from "../../contracts/mocks/ValidatorsConsolidationsMock.sol"; +import {ValidatorsHelpers} from "./ValidatorsHelpers.sol"; +import {ValidatorsWithdrawalsMock} from "../../contracts/mocks/ValidatorsWithdrawalsMock.sol"; +import {VaultsRegistry, IVaultsRegistry} from "../../contracts/vaults/VaultsRegistry.sol"; abstract contract EthHelpers is Test, ValidatorsHelpers { - uint256 internal constant forkBlockNumber = 22100000; - uint256 internal constant _securityDeposit = 1e9; - address private constant _keeper = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; - address private constant _validatorsRegistry = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address private constant _vaultsRegistry = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; - address internal constant _osToken = 0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38; - address internal constant _osTokenFlashLoans = 0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2; - address private constant _osTokenVaultController = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; - address private constant _osTokenConfig = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; - address private constant _osTokenVaultEscrow = 0x09e84205DF7c68907e619D07aFD90143c5763605; - address private constant _sharedMevEscrow = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; - address internal constant _depositDataRegistry = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; - address internal constant _poolEscrow = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; - address internal constant _rewardEthToken = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; - uint256 internal constant _exitingAssetsClaimDelay = 1 days; - - enum VaultType { - EthVault, - EthBlocklistVault, - EthPrivVault, - EthGenesisVault, - EthErc20Vault, - EthBlocklistErc20Vault, - EthPrivErc20Vault, - EthFoxVault - } - - struct ForkContracts { - Keeper keeper; - IEthValidatorsRegistry validatorsRegistry; - VaultsRegistry vaultsRegistry; - IOsTokenVaultController osTokenVaultController; - IOsTokenConfig osTokenConfig; - IOsTokenVaultEscrow osTokenVaultEscrow; - ISharedMevEscrow sharedMevEscrow; - IConsolidationsChecker consolidationsChecker; - } - - mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; - mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; - mapping(VaultType vaultType => address vaultFactory) private _vaultPrevFactories; - - address internal _consolidationsChecker; - address internal _validatorsWithdrawals; - address internal _validatorsConsolidations; - - function _activateEthereumFork() internal returns (ForkContracts memory) { - vm.createSelectFork(vm.envString('MAINNET_RPC_URL'), forkBlockNumber); - - _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); - _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); - _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); - - return - ForkContracts({ - keeper: Keeper(_keeper), - validatorsRegistry: IEthValidatorsRegistry(_validatorsRegistry), - vaultsRegistry: VaultsRegistry(_vaultsRegistry), - osTokenVaultController: IOsTokenVaultController(_osTokenVaultController), - osTokenConfig: IOsTokenConfig(_osTokenConfig), - osTokenVaultEscrow: IOsTokenVaultEscrow(_osTokenVaultEscrow), - sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), - consolidationsChecker: IConsolidationsChecker(_consolidationsChecker) - }); - } - - function _getOrCreateVault( - VaultType vaultType, - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address vault) { - vault = _getForkVault(vaultType); - if (vault != address(0)) { - _upgradeVault(vaultType, vault); - if (Keeper(_keeper).isHarvestRequired(vault)) { - IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(vault, 0, 0); - IVaultState(vault).updateState(harvestParams); - } - } else { - vault = _createVault(vaultType, admin, initParams, isOwnMevEscrow); + uint256 internal constant forkBlockNumber = 22100000; + uint256 internal constant _securityDeposit = 1e9; + address private constant _keeper = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; + address private constant _validatorsRegistry = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + address private constant _vaultsRegistry = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; + address internal constant _osToken = 0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38; + address internal constant _osTokenFlashLoans = 0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2; + address private constant _osTokenVaultController = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; + address private constant _osTokenConfig = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; + address private constant _osTokenVaultEscrow = 0x09e84205DF7c68907e619D07aFD90143c5763605; + address private constant _sharedMevEscrow = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; + address internal constant _depositDataRegistry = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; + address internal constant _poolEscrow = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; + address internal constant _rewardEthToken = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; + uint256 internal constant _exitingAssetsClaimDelay = 1 days; + + enum VaultType { + EthVault, + EthBlocklistVault, + EthPrivVault, + EthGenesisVault, + EthErc20Vault, + EthBlocklistErc20Vault, + EthPrivErc20Vault, + EthFoxVault } - address currentAdmin = IEthVault(vault).admin(); - if (currentAdmin != admin) { - vm.prank(currentAdmin); - IEthVault(vault).setAdmin(admin); + struct ForkContracts { + Keeper keeper; + IEthValidatorsRegistry validatorsRegistry; + VaultsRegistry vaultsRegistry; + IOsTokenVaultController osTokenVaultController; + IOsTokenConfig osTokenConfig; + IOsTokenVaultEscrow osTokenVaultEscrow; + ISharedMevEscrow sharedMevEscrow; + IConsolidationsChecker consolidationsChecker; } - } - function _getOrCreateFactory(VaultType _vaultType) internal returns (EthVaultFactory) { - if (_vaultFactories[_vaultType] != address(0)) { - return EthVaultFactory(_vaultFactories[_vaultType]); + mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; + mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; + mapping(VaultType vaultType => address vaultFactory) private _vaultPrevFactories; + + address internal _consolidationsChecker; + address internal _validatorsWithdrawals; + address internal _validatorsConsolidations; + + function _activateEthereumFork() internal returns (ForkContracts memory) { + vm.createSelectFork(vm.envString("MAINNET_RPC_URL"), forkBlockNumber); + + _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); + _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); + _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); + + return ForkContracts({ + keeper: Keeper(_keeper), + validatorsRegistry: IEthValidatorsRegistry(_validatorsRegistry), + vaultsRegistry: VaultsRegistry(_vaultsRegistry), + osTokenVaultController: IOsTokenVaultController(_osTokenVaultController), + osTokenConfig: IOsTokenConfig(_osTokenConfig), + osTokenVaultEscrow: IOsTokenVaultEscrow(_osTokenVaultEscrow), + sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), + consolidationsChecker: IConsolidationsChecker(_consolidationsChecker) + }); } - address impl = _getOrCreateVaultImpl(_vaultType); - EthVaultFactory factory = new EthVaultFactory(impl, IVaultsRegistry(_vaultsRegistry)); + function _getOrCreateVault(VaultType vaultType, address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address vault) + { + vault = _getForkVault(vaultType); + if (vault != address(0)) { + _upgradeVault(vaultType, vault); + if (Keeper(_keeper).isHarvestRequired(vault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(vault, 0, 0); + IVaultState(vault).updateState(harvestParams); + } + } else { + vault = _createVault(vaultType, admin, initParams, isOwnMevEscrow); + } + + address currentAdmin = IEthVault(vault).admin(); + if (currentAdmin != admin) { + vm.prank(currentAdmin); + IEthVault(vault).setAdmin(admin); + } + } + + function _getOrCreateFactory(VaultType _vaultType) internal returns (EthVaultFactory) { + if (_vaultFactories[_vaultType] != address(0)) { + return EthVaultFactory(_vaultFactories[_vaultType]); + } + + address impl = _getOrCreateVaultImpl(_vaultType); + EthVaultFactory factory = new EthVaultFactory(impl, IVaultsRegistry(_vaultsRegistry)); - _vaultFactories[_vaultType] = address(factory); + _vaultFactories[_vaultType] = address(factory); - vm.prank(VaultsRegistry(_vaultsRegistry).owner()); - VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); - return factory; - } + return factory; + } - function _getPrevVersionVaultFactory(VaultType _vaultType) internal returns (EthVaultFactory) { - if (_vaultPrevFactories[_vaultType] != address(0)) { - return EthVaultFactory(_vaultPrevFactories[_vaultType]); + function _getPrevVersionVaultFactory(VaultType _vaultType) internal returns (EthVaultFactory) { + if (_vaultPrevFactories[_vaultType] != address(0)) { + return EthVaultFactory(_vaultPrevFactories[_vaultType]); + } + + // Return actual contract addresses of previous factory versions if needed + address impl; + if (_vaultType == VaultType.EthVault) { + impl = 0xDecb606ee9140f229Df78F9E40041EAD61610F8f; + } else if (_vaultType == VaultType.EthPrivVault) { + impl = 0x135f45e0179dd928E73422B40Bdc6C5d7047a035; + } else if (_vaultType == VaultType.EthBlocklistVault) { + impl = 0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478; + } else if (_vaultType == VaultType.EthErc20Vault) { + impl = 0x7E5198DF09fED891e7AecD623cD2231443cEb5d5; + } else if (_vaultType == VaultType.EthPrivErc20Vault) { + impl = 0x9488A7dd178F0D927707eEc61A7D8C0ae9558c88; + } else if (_vaultType == VaultType.EthBlocklistErc20Vault) { + impl = 0x84d44A696539B3eF4162184fb8ab97596A311e9E; + } else { + return EthVaultFactory(address(0)); + } + + EthVaultFactory factory = new EthVaultFactory(impl, IVaultsRegistry(_vaultsRegistry)); + _vaultPrevFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; } - // Return actual contract addresses of previous factory versions if needed - address impl; - if (_vaultType == VaultType.EthVault) { - impl = 0xDecb606ee9140f229Df78F9E40041EAD61610F8f; - } else if (_vaultType == VaultType.EthPrivVault) { - impl = 0x135f45e0179dd928E73422B40Bdc6C5d7047a035; - } else if (_vaultType == VaultType.EthBlocklistVault) { - impl = 0xd19E4B1d680a6aA672b08ebf483381bc0C9c8478; - } else if (_vaultType == VaultType.EthErc20Vault) { - impl = 0x7E5198DF09fED891e7AecD623cD2231443cEb5d5; - } else if (_vaultType == VaultType.EthPrivErc20Vault) { - impl = 0x9488A7dd178F0D927707eEc61A7D8C0ae9558c88; - } else if (_vaultType == VaultType.EthBlocklistErc20Vault) { - impl = 0x84d44A696539B3eF4162184fb8ab97596A311e9E; - } else { - return EthVaultFactory(address(0)); + function _depositToVault(address vault, uint256 amount, address from, address to) internal { + vm.prank(from); + IEthVault(vault).deposit{value: amount}(to, address(0)); } - EthVaultFactory factory = new EthVaultFactory(impl, IVaultsRegistry(_vaultsRegistry)); - _vaultPrevFactories[_vaultType] = address(factory); - - vm.prank(VaultsRegistry(_vaultsRegistry).owner()); - VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); - - return factory; - } - - function _depositToVault(address vault, uint256 amount, address from, address to) internal { - vm.prank(from); - IEthVault(vault).deposit{value: amount}(to, address(0)); - } - - function _collateralizeEthVault(address vault) internal { - _collateralizeVault(_keeper, _validatorsRegistry, vault); - } - - function _mintOsToken(address user, uint256 amount) internal { - vm.prank(_getForkVault(VaultType.EthGenesisVault)); - IOsTokenVaultController(_osTokenVaultController).mintShares(user, amount); - } - - function _setEthVaultReward( - address vault, - int160 totalReward, - uint160 unlockedMevReward - ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { - (totalReward, unlockedMevReward) = _getVaultRewards(vault, totalReward, unlockedMevReward); - SetVaultRewardParams memory params = SetVaultRewardParams({ - keeper: _keeper, - osTokenCtrl: _osTokenVaultController, - vault: vault, - totalReward: totalReward, - unlockedMevReward: unlockedMevReward - }); - return _setVaultReward(params); - } - - function _registerEthValidator( - address vault, - uint256 depositAmount, - bool isV1Validator - ) internal returns (bytes memory publicKey) { - return _registerValidator(_keeper, _validatorsRegistry, vault, depositAmount, isV1Validator); - } - - function _getEthValidatorApproval( - address vault, - uint256 depositAmount, - string memory ipfsHash, - bool isV1Validator - ) internal view returns (IKeeperValidators.ApprovalParams memory harvestParams) { - uint256[] memory deposits = new uint256[](1); - deposits[0] = depositAmount / 1 gwei; - - harvestParams = _getValidatorsApproval( - _keeper, - _validatorsRegistry, - vault, - ipfsHash, - deposits, - isV1Validator - ); - } - - function _startSnapshotGas(string memory label) internal { - if (vm.envBool('USE_FORK_VAULTS')) return; - return vm.startSnapshotGas(label); - } - - function _stopSnapshotGas() internal { - if (vm.envBool('USE_FORK_VAULTS')) return; - vm.stopSnapshotGas(); - } - - function _getForkVault(VaultType vaultType) internal view returns (address) { - if (vaultType == VaultType.EthGenesisVault) { - return 0xAC0F906E433d58FA868F936E8A43230473652885; - } else if (vaultType == VaultType.EthFoxVault) { - return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; + function _collateralizeEthVault(address vault) internal { + _collateralizeVault(_keeper, _validatorsRegistry, vault); } - if (!vm.envBool('USE_FORK_VAULTS')) return address(0); - - // Update with actual deployed vault addresses for each type - if (vaultType == VaultType.EthVault) { - return 0x8A93A876912c9F03F88Bc9114847cf5b63c89f56; - } else if (vaultType == VaultType.EthPrivVault) { - return 0xD66A71A68392767F26b7EE47e9a0293191A23072; - } else if (vaultType == VaultType.EthErc20Vault) { - return 0x7106FA765d45dF6d5340972C58742fC54f0d1Ef9; - } else if (vaultType == VaultType.EthPrivErc20Vault) { - return 0xFB22Ded2bd69aff0907e195F23E448aB44E3cA97; - } else if (vaultType == VaultType.EthFoxVault) { - return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; + function _mintOsToken(address user, uint256 amount) internal { + vm.prank(_getForkVault(VaultType.EthGenesisVault)); + IOsTokenVaultController(_osTokenVaultController).mintShares(user, amount); } - return address(0); - } - - function _getVaultRewards( - address vault, - int160 newTotalReward, - uint160 newUnlockedMevReward - ) private view returns (int160, uint160) { - // Update with actual values if needed for specific vaults - if (vault == 0xAC0F906E433d58FA868F936E8A43230473652885) { - // Genesis Vault - newTotalReward += 11492988394536925432019; - newUnlockedMevReward += 588134256533622872486; - } else if (vault == 0x4FEF9D741011476750A243aC70b9789a63dd47Df) { - newTotalReward += 242948554351000000000; + + function _setEthVaultReward(address vault, int160 totalReward, uint160 unlockedMevReward) + internal + returns (IKeeperRewards.HarvestParams memory harvestParams) + { + (totalReward, unlockedMevReward) = _getVaultRewards(vault, totalReward, unlockedMevReward); + SetVaultRewardParams memory params = SetVaultRewardParams({ + keeper: _keeper, + osTokenCtrl: _osTokenVaultController, + vault: vault, + totalReward: totalReward, + unlockedMevReward: unlockedMevReward + }); + return _setVaultReward(params); } - if (!vm.envBool('USE_FORK_VAULTS')) { - return (newTotalReward, newUnlockedMevReward); + function _registerEthValidator(address vault, uint256 depositAmount, bool isV1Validator) + internal + returns (bytes memory publicKey) + { + return _registerValidator(_keeper, _validatorsRegistry, vault, depositAmount, isV1Validator); } - // Add specific rewards for each vault type - if (vault == 0x8A93A876912c9F03F88Bc9114847cf5b63c89f56) { - newTotalReward += 39158842473943927643; - newUnlockedMevReward += 6210915181493109989; - } else if (vault == 0xD66A71A68392767F26b7EE47e9a0293191A23072) { - newTotalReward += 17651468000000000; + function _getEthValidatorApproval(address vault, uint256 depositAmount, string memory ipfsHash, bool isV1Validator) + internal + view + returns (IKeeperValidators.ApprovalParams memory harvestParams) + { + uint256[] memory deposits = new uint256[](1); + deposits[0] = depositAmount / 1 gwei; + + harvestParams = _getValidatorsApproval(_keeper, _validatorsRegistry, vault, ipfsHash, deposits, isV1Validator); } - return (newTotalReward, newUnlockedMevReward); - } - - function _createVault( - VaultType vaultType, - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address) { - EthVaultFactory factory = _getOrCreateFactory(vaultType); - - vm.deal(admin, admin.balance + _securityDeposit); - vm.prank(admin); - address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); - - return vaultAddress; - } - - function _createPrevVersionVault( - VaultType vaultType, - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address) { - EthVaultFactory factory = _getPrevVersionVaultFactory(vaultType); - - vm.deal(admin, admin.balance + _securityDeposit); - vm.prank(admin); - address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); - - return vaultAddress; - } - - function _createV1EthVault( - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address) { - EthVaultFactory factory = EthVaultFactory(0xDada5a8E3703B1e3EA2bAe5Ab704627eb2659fCC); - - vm.prank(VaultsRegistry(_vaultsRegistry).owner()); - VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); - - vm.deal(admin, admin.balance + _securityDeposit); - vm.prank(admin); - address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); - - return vaultAddress; - } - - function _upgradeVault(VaultType vaultType, address vault) internal { - EthVault vaultContract = EthVault(payable(vault)); - uint256 currentVersion = vaultContract.version(); - - if (vaultType == VaultType.EthFoxVault) { - if (currentVersion == 2) return; - require(currentVersion == 1, 'Invalid vault version'); - } else { - if (currentVersion == 5) return; - require(currentVersion == 4, 'Invalid vault version'); + function _startSnapshotGas(string memory label) internal { + if (vm.envBool("SKIP_SNAPSHOTS")) return; + return vm.startSnapshotGas(label); } - address newImpl = _getOrCreateVaultImpl(vaultType); - address admin = vaultContract.admin(); + function _stopSnapshotGas() internal { + if (vm.envBool("SKIP_SNAPSHOTS")) return; + vm.stopSnapshotGas(); + } - vm.deal(admin, admin.balance + 1 ether); - vm.prank(admin); - vaultContract.upgradeToAndCall(newImpl, '0x'); - } + function _getForkVault(VaultType vaultType) internal view returns (address) { + if (vaultType == VaultType.EthGenesisVault) { + return 0xAC0F906E433d58FA868F936E8A43230473652885; + } else if (vaultType == VaultType.EthFoxVault) { + return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; + } + + if (!vm.envBool("USE_FORK_VAULTS")) return address(0); + + // Update with actual deployed vault addresses for each type + if (vaultType == VaultType.EthVault) { + return 0x8A93A876912c9F03F88Bc9114847cf5b63c89f56; + } else if (vaultType == VaultType.EthPrivVault) { + return 0xD66A71A68392767F26b7EE47e9a0293191A23072; + } else if (vaultType == VaultType.EthErc20Vault) { + return 0x7106FA765d45dF6d5340972C58742fC54f0d1Ef9; + } else if (vaultType == VaultType.EthPrivErc20Vault) { + return 0xFB22Ded2bd69aff0907e195F23E448aB44E3cA97; + } else if (vaultType == VaultType.EthFoxVault) { + return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; + } + return address(0); + } - function _getOrCreateVaultImpl(VaultType _vaultType) internal returns (address impl) { - if (_vaultImplementations[_vaultType] != address(0)) { - return _vaultImplementations[_vaultType]; + function _getVaultRewards(address vault, int160 newTotalReward, uint160 newUnlockedMevReward) + private + view + returns (int160, uint160) + { + // Update with actual values if needed for specific vaults + if (vault == 0xAC0F906E433d58FA868F936E8A43230473652885) { + // Genesis Vault + newTotalReward += 11492988394536925432019; + newUnlockedMevReward += 588134256533622872486; + } else if (vault == 0x4FEF9D741011476750A243aC70b9789a63dd47Df) { + newTotalReward += 242948554351000000000; + } + + if (!vm.envBool("USE_FORK_VAULTS")) { + return (newTotalReward, newUnlockedMevReward); + } + + // Add specific rewards for each vault type + if (vault == 0x8A93A876912c9F03F88Bc9114847cf5b63c89f56) { + newTotalReward += 39158842473943927643; + newUnlockedMevReward += 6210915181493109989; + } else if (vault == 0xD66A71A68392767F26b7EE47e9a0293191A23072) { + newTotalReward += 17651468000000000; + } + + return (newTotalReward, newUnlockedMevReward); } - IEthVault.EthVaultConstructorArgs memory ethArgs = IEthVault.EthVaultConstructorArgs( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - _validatorsWithdrawals, - _validatorsConsolidations, - _consolidationsChecker, - _osTokenVaultController, - _osTokenConfig, - _osTokenVaultEscrow, - _sharedMevEscrow, - _depositDataRegistry, - uint64(_exitingAssetsClaimDelay) - ); - - IEthErc20Vault.EthErc20VaultConstructorArgs memory ethErc20Args = IEthErc20Vault - .EthErc20VaultConstructorArgs( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - _validatorsWithdrawals, - _validatorsConsolidations, - _consolidationsChecker, - _osTokenVaultController, - _osTokenConfig, - _osTokenVaultEscrow, - _sharedMevEscrow, - _depositDataRegistry, - uint64(_exitingAssetsClaimDelay) - ); - - if (_vaultType == VaultType.EthVault) { - impl = address(new EthVault(ethArgs)); - } else if (_vaultType == VaultType.EthBlocklistVault) { - impl = address(new EthBlocklistVault(ethArgs)); - } else if (_vaultType == VaultType.EthPrivVault) { - impl = address(new EthPrivVault(ethArgs)); - } else if (_vaultType == VaultType.EthGenesisVault) { - impl = address(new EthGenesisVault(ethArgs, _poolEscrow, _rewardEthToken)); - } else if (_vaultType == VaultType.EthErc20Vault) { - impl = address(new EthErc20Vault(ethErc20Args)); - } else if (_vaultType == VaultType.EthBlocklistErc20Vault) { - impl = address(new EthBlocklistErc20Vault(ethErc20Args)); - } else if (_vaultType == VaultType.EthPrivErc20Vault) { - impl = address(new EthPrivErc20Vault(ethErc20Args)); - } else if (_vaultType == VaultType.EthFoxVault) { - impl = address( - new EthFoxVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - _validatorsWithdrawals, - _validatorsConsolidations, - _consolidationsChecker, - _sharedMevEscrow, - _depositDataRegistry, - _exitingAssetsClaimDelay - ) - ); + function _createVault(VaultType vaultType, address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address) + { + EthVaultFactory factory = _getOrCreateFactory(vaultType); + + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + + return vaultAddress; } - _vaultImplementations[_vaultType] = impl; + function _createPrevVersionVault(VaultType vaultType, address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address) + { + EthVaultFactory factory = _getPrevVersionVaultFactory(vaultType); + + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); - vm.prank(VaultsRegistry(_vaultsRegistry).owner()); - VaultsRegistry(_vaultsRegistry).addVaultImpl(impl); + return vaultAddress; + } - return impl; - } + function _createV1EthVault(address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address) + { + EthVaultFactory factory = EthVaultFactory(0xDada5a8E3703B1e3EA2bAe5Ab704627eb2659fCC); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + + return vaultAddress; + } + + function _upgradeVault(VaultType vaultType, address vault) internal { + EthVault vaultContract = EthVault(payable(vault)); + uint256 currentVersion = vaultContract.version(); + + if (vaultType == VaultType.EthFoxVault) { + if (currentVersion == 2) return; + require(currentVersion == 1, "Invalid vault version"); + } else { + if (currentVersion == 5) return; + require(currentVersion == 4, "Invalid vault version"); + } + + address newImpl = _getOrCreateVaultImpl(vaultType); + address admin = vaultContract.admin(); + + vm.deal(admin, admin.balance + 1 ether); + vm.prank(admin); + vaultContract.upgradeToAndCall(newImpl, "0x"); + } + + function _getOrCreateVaultImpl(VaultType _vaultType) internal returns (address impl) { + if (_vaultImplementations[_vaultType] != address(0)) { + return _vaultImplementations[_vaultType]; + } + + IEthVault.EthVaultConstructorArgs memory ethArgs = IEthVault.EthVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + IEthErc20Vault.EthErc20VaultConstructorArgs memory ethErc20Args = IEthErc20Vault.EthErc20VaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + + if (_vaultType == VaultType.EthVault) { + impl = address(new EthVault(ethArgs)); + } else if (_vaultType == VaultType.EthBlocklistVault) { + impl = address(new EthBlocklistVault(ethArgs)); + } else if (_vaultType == VaultType.EthPrivVault) { + impl = address(new EthPrivVault(ethArgs)); + } else if (_vaultType == VaultType.EthGenesisVault) { + impl = address(new EthGenesisVault(ethArgs, _poolEscrow, _rewardEthToken)); + } else if (_vaultType == VaultType.EthErc20Vault) { + impl = address(new EthErc20Vault(ethErc20Args)); + } else if (_vaultType == VaultType.EthBlocklistErc20Vault) { + impl = address(new EthBlocklistErc20Vault(ethErc20Args)); + } else if (_vaultType == VaultType.EthPrivErc20Vault) { + impl = address(new EthPrivErc20Vault(ethErc20Args)); + } else if (_vaultType == VaultType.EthFoxVault) { + impl = address( + new EthFoxVault( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _sharedMevEscrow, + _depositDataRegistry, + _exitingAssetsClaimDelay + ) + ); + } + + _vaultImplementations[_vaultType] = impl; + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addVaultImpl(impl); + + return impl; + } } diff --git a/test/helpers/GnoHelpers.sol b/test/helpers/GnoHelpers.sol index 2f66d87b..cbbd57ca 100644 --- a/test/helpers/GnoHelpers.sol +++ b/test/helpers/GnoHelpers.sol @@ -2,439 +2,413 @@ pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; -import {IOsTokenConfig} from '../../contracts/interfaces/IOsTokenConfig.sol'; -import {IOsTokenVaultController} from '../../contracts/interfaces/IOsTokenVaultController.sol'; -import {IOsTokenVaultEscrow} from '../../contracts/interfaces/IOsTokenVaultEscrow.sol'; -import {ISharedMevEscrow} from '../../contracts/interfaces/ISharedMevEscrow.sol'; -import {IGnoValidatorsRegistry} from '../../contracts/interfaces/IGnoValidatorsRegistry.sol'; -import {IMerkleDistributor} from '../../contracts/interfaces/IMerkleDistributor.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IVaultState} from '../../contracts/interfaces/IVaultState.sol'; -import {IConsolidationsChecker} from '../../contracts/interfaces/IConsolidationsChecker.sol'; -import {GnoDaiDistributor, IGnoDaiDistributor} from '../../contracts/misc/GnoDaiDistributor.sol'; -import {ConsolidationsChecker} from '../../contracts/validators/ConsolidationsChecker.sol'; -import {GnoBlocklistErc20Vault} from '../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol'; -import {GnoBlocklistVault} from '../../contracts/vaults/gnosis/GnoBlocklistVault.sol'; -import {GnoErc20Vault, IGnoErc20Vault} from '../../contracts/vaults/gnosis/GnoErc20Vault.sol'; -import {GnoGenesisVault} from '../../contracts/vaults/gnosis/GnoGenesisVault.sol'; -import {GnoPrivErc20Vault} from '../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol'; -import {GnoPrivVault} from '../../contracts/vaults/gnosis/GnoPrivVault.sol'; -import {GnoVault, IGnoVault} from '../../contracts/vaults/gnosis/GnoVault.sol'; -import {GnoVaultFactory} from '../../contracts/vaults/gnosis/GnoVaultFactory.sol'; -import {Keeper} from '../../contracts/keeper/Keeper.sol'; -import {ValidatorsConsolidationsMock} from '../../contracts/mocks/ValidatorsConsolidationsMock.sol'; -import {ValidatorsHelpers} from './ValidatorsHelpers.sol'; -import {ValidatorsWithdrawalsMock} from '../../contracts/mocks/ValidatorsWithdrawalsMock.sol'; -import {VaultsRegistry, IVaultsRegistry} from '../../contracts/vaults/VaultsRegistry.sol'; +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; +import {IOsTokenConfig} from "../../contracts/interfaces/IOsTokenConfig.sol"; +import {IOsTokenVaultController} from "../../contracts/interfaces/IOsTokenVaultController.sol"; +import {IOsTokenVaultEscrow} from "../../contracts/interfaces/IOsTokenVaultEscrow.sol"; +import {ISharedMevEscrow} from "../../contracts/interfaces/ISharedMevEscrow.sol"; +import {IGnoValidatorsRegistry} from "../../contracts/interfaces/IGnoValidatorsRegistry.sol"; +import {IMerkleDistributor} from "../../contracts/interfaces/IMerkleDistributor.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; +import {IConsolidationsChecker} from "../../contracts/interfaces/IConsolidationsChecker.sol"; +import {GnoDaiDistributor, IGnoDaiDistributor} from "../../contracts/misc/GnoDaiDistributor.sol"; +import {ConsolidationsChecker} from "../../contracts/validators/ConsolidationsChecker.sol"; +import {GnoBlocklistErc20Vault} from "../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol"; +import {GnoBlocklistVault} from "../../contracts/vaults/gnosis/GnoBlocklistVault.sol"; +import {GnoErc20Vault, IGnoErc20Vault} from "../../contracts/vaults/gnosis/GnoErc20Vault.sol"; +import {GnoGenesisVault} from "../../contracts/vaults/gnosis/GnoGenesisVault.sol"; +import {GnoPrivErc20Vault} from "../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol"; +import {GnoPrivVault} from "../../contracts/vaults/gnosis/GnoPrivVault.sol"; +import {GnoVault, IGnoVault} from "../../contracts/vaults/gnosis/GnoVault.sol"; +import {GnoVaultFactory} from "../../contracts/vaults/gnosis/GnoVaultFactory.sol"; +import {Keeper} from "../../contracts/keeper/Keeper.sol"; +import {ValidatorsConsolidationsMock} from "../../contracts/mocks/ValidatorsConsolidationsMock.sol"; +import {ValidatorsHelpers} from "./ValidatorsHelpers.sol"; +import {ValidatorsWithdrawalsMock} from "../../contracts/mocks/ValidatorsWithdrawalsMock.sol"; +import {VaultsRegistry, IVaultsRegistry} from "../../contracts/vaults/VaultsRegistry.sol"; interface IGnoToken { - function mint(address _to, uint256 _amount) external returns (bool); - function owner() external view returns (address); + function mint(address _to, uint256 _amount) external returns (bool); + function owner() external view returns (address); } abstract contract GnoHelpers is Test, ValidatorsHelpers { - uint256 internal constant forkBlockNumber = 39014183; - uint256 internal constant _securityDeposit = 1e9; - address private constant _keeper = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; - address private constant _validatorsRegistry = 0x0B98057eA310F4d31F2a452B414647007d1645d9; - address private constant _vaultsRegistry = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; - address private constant _osTokenVaultController = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; - address private constant _osTokenConfig = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; - address private constant _osTokenVaultEscrow = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; - address private constant _sharedMevEscrow = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; - address internal constant _depositDataRegistry = 0x58e16621B5c0786D6667D2d54E28A20940269E16; - address private constant _gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; - address internal constant _poolEscrow = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; - address internal constant _rewardGnoToken = 0x6aC78efae880282396a335CA2F79863A1e6831D4; - address private constant _merkleDistributor = 0xFBceefdBB0ca25a4043b35EF49C2810425243710; - address private constant _savingsXDaiAdapter = 0xD499b51fcFc66bd31248ef4b28d656d67E591A94; - address private constant _sDaiToken = 0xaf204776c7245bF4147c2612BF6e5972Ee483701; - uint256 internal constant _exitingAssetsClaimDelay = 1 days; - - enum VaultType { - GnoVault, - GnoBlocklistVault, - GnoPrivVault, - GnoGenesisVault, - GnoErc20Vault, - GnoBlocklistErc20Vault, - GnoPrivErc20Vault - } - - struct ForkContracts { - Keeper keeper; - IGnoValidatorsRegistry validatorsRegistry; - VaultsRegistry vaultsRegistry; - IOsTokenVaultController osTokenVaultController; - IOsTokenConfig osTokenConfig; - IOsTokenVaultEscrow osTokenVaultEscrow; - ISharedMevEscrow sharedMevEscrow; - IERC20 gnoToken; - IERC20 sdaiToken; - IConsolidationsChecker consolidationsChecker; - IGnoDaiDistributor gnoDaiDistributor; - IMerkleDistributor merkleDistributor; - } - - mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; - mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; - - address private _gnoDaiDistributor; - address private _consolidationsChecker; - address private _validatorsWithdrawals; - address private _validatorsConsolidations; - - function _activateGnosisFork() internal returns (ForkContracts memory) { - vm.createSelectFork(vm.envString('GNOSIS_RPC_URL'), forkBlockNumber); - - _gnoDaiDistributor = address( - new GnoDaiDistributor(_sDaiToken, _vaultsRegistry, _savingsXDaiAdapter, _merkleDistributor) - ); - _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); - _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); - _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); - - vm.prank(IMerkleDistributor(_merkleDistributor).owner()); - IMerkleDistributor(_merkleDistributor).setDistributor(_gnoDaiDistributor, true); - return - ForkContracts({ - keeper: Keeper(_keeper), - validatorsRegistry: IGnoValidatorsRegistry(_validatorsRegistry), - vaultsRegistry: VaultsRegistry(_vaultsRegistry), - osTokenVaultController: IOsTokenVaultController(_osTokenVaultController), - osTokenConfig: IOsTokenConfig(_osTokenConfig), - osTokenVaultEscrow: IOsTokenVaultEscrow(_osTokenVaultEscrow), - sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), - gnoToken: IERC20(_gnoToken), - sdaiToken: IERC20(_sDaiToken), - consolidationsChecker: IConsolidationsChecker(_consolidationsChecker), - gnoDaiDistributor: IGnoDaiDistributor(_gnoDaiDistributor), - merkleDistributor: IMerkleDistributor(_merkleDistributor) - }); - } - - function _mintGnoToken(address to, uint256 amount) internal { - vm.prank(IGnoToken(_gnoToken).owner()); - IGnoToken(_gnoToken).mint(to, amount); - } - - function _depositToVault(address vault, uint256 amount, address from, address to) internal { - vm.startPrank(from); - IERC20(_gnoToken).approve(vault, amount); - IGnoVault(vault).deposit(amount, to, address(0)); - vm.stopPrank(); - } - - function _collateralizeGnoVault(address vault) internal { - _collateralizeVault(_keeper, _validatorsRegistry, vault); - } - - function _setGnoVaultReward( - address vault, - int160 totalReward, - uint160 unlockedMevReward - ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { - (totalReward, unlockedMevReward) = _getVaultRewards(vault, totalReward, unlockedMevReward); - SetVaultRewardParams memory params = SetVaultRewardParams({ - keeper: _keeper, - osTokenCtrl: _osTokenVaultController, - vault: vault, - totalReward: totalReward, - unlockedMevReward: unlockedMevReward - }); - return _setVaultReward(params); - } - - function _registerGnoValidator( - address vault, - uint256 depositAmount, - bool isV1Validator - ) internal returns (bytes memory publicKey) { - // multiply by 32 to convert GNO to mGNO - return - _registerValidator(_keeper, _validatorsRegistry, vault, depositAmount * 32, isV1Validator); - } - - function _getGnoValidatorApproval( - address vault, - uint256 depositAmount, - string memory ipfsHash, - bool isV1Validator - ) internal view returns (IKeeperValidators.ApprovalParams memory harvestParams) { - uint256[] memory deposits = new uint256[](1); - deposits[0] = (depositAmount * 32) / 1 gwei; - - harvestParams = _getValidatorsApproval( - _keeper, - _validatorsRegistry, - vault, - ipfsHash, - deposits, - isV1Validator - ); - } - - function _getOrCreateVault( - VaultType vaultType, - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address vault) { - vault = _getForkVault(vaultType); - if (vault != address(0)) { - _upgradeVault(vaultType, vault); - if (Keeper(_keeper).isHarvestRequired(vault)) { - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, 0, 0); - IVaultState(vault).updateState(harvestParams); - } - } else { - vault = _createVault(vaultType, admin, initParams, isOwnMevEscrow); + uint256 internal constant forkBlockNumber = 39014183; + uint256 internal constant _securityDeposit = 1e9; + address private constant _keeper = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; + address private constant _validatorsRegistry = 0x0B98057eA310F4d31F2a452B414647007d1645d9; + address private constant _vaultsRegistry = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; + address private constant _osTokenVaultController = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; + address private constant _osTokenConfig = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; + address private constant _osTokenVaultEscrow = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; + address private constant _sharedMevEscrow = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; + address internal constant _depositDataRegistry = 0x58e16621B5c0786D6667D2d54E28A20940269E16; + address private constant _gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; + address internal constant _poolEscrow = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; + address internal constant _rewardGnoToken = 0x6aC78efae880282396a335CA2F79863A1e6831D4; + address private constant _merkleDistributor = 0xFBceefdBB0ca25a4043b35EF49C2810425243710; + address private constant _savingsXDaiAdapter = 0xD499b51fcFc66bd31248ef4b28d656d67E591A94; + address private constant _sDaiToken = 0xaf204776c7245bF4147c2612BF6e5972Ee483701; + uint256 internal constant _exitingAssetsClaimDelay = 1 days; + + enum VaultType { + GnoVault, + GnoBlocklistVault, + GnoPrivVault, + GnoGenesisVault, + GnoErc20Vault, + GnoBlocklistErc20Vault, + GnoPrivErc20Vault } - address currentAdmin = IGnoVault(vault).admin(); - if (currentAdmin != admin) { - vm.prank(currentAdmin); - IGnoVault(vault).setAdmin(admin); + struct ForkContracts { + Keeper keeper; + IGnoValidatorsRegistry validatorsRegistry; + VaultsRegistry vaultsRegistry; + IOsTokenVaultController osTokenVaultController; + IOsTokenConfig osTokenConfig; + IOsTokenVaultEscrow osTokenVaultEscrow; + ISharedMevEscrow sharedMevEscrow; + IERC20 gnoToken; + IERC20 sdaiToken; + IConsolidationsChecker consolidationsChecker; + IGnoDaiDistributor gnoDaiDistributor; + IMerkleDistributor merkleDistributor; } - } - function _getOrCreateFactory(VaultType _vaultType) internal returns (GnoVaultFactory) { - if (_vaultFactories[_vaultType] != address(0)) { - return GnoVaultFactory(_vaultFactories[_vaultType]); + mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; + mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; + + address private _gnoDaiDistributor; + address private _consolidationsChecker; + address private _validatorsWithdrawals; + address private _validatorsConsolidations; + + function _activateGnosisFork() internal returns (ForkContracts memory) { + vm.createSelectFork(vm.envString("GNOSIS_RPC_URL"), forkBlockNumber); + + _gnoDaiDistributor = + address(new GnoDaiDistributor(_sDaiToken, _vaultsRegistry, _savingsXDaiAdapter, _merkleDistributor)); + _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); + _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); + _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); + + vm.prank(IMerkleDistributor(_merkleDistributor).owner()); + IMerkleDistributor(_merkleDistributor).setDistributor(_gnoDaiDistributor, true); + return ForkContracts({ + keeper: Keeper(_keeper), + validatorsRegistry: IGnoValidatorsRegistry(_validatorsRegistry), + vaultsRegistry: VaultsRegistry(_vaultsRegistry), + osTokenVaultController: IOsTokenVaultController(_osTokenVaultController), + osTokenConfig: IOsTokenConfig(_osTokenConfig), + osTokenVaultEscrow: IOsTokenVaultEscrow(_osTokenVaultEscrow), + sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), + gnoToken: IERC20(_gnoToken), + sdaiToken: IERC20(_sDaiToken), + consolidationsChecker: IConsolidationsChecker(_consolidationsChecker), + gnoDaiDistributor: IGnoDaiDistributor(_gnoDaiDistributor), + merkleDistributor: IMerkleDistributor(_merkleDistributor) + }); } - address impl = _getOrCreateVaultImpl(_vaultType); - GnoVaultFactory factory = new GnoVaultFactory( - impl, - IVaultsRegistry(_vaultsRegistry), - _gnoToken - ); - - _vaultFactories[_vaultType] = address(factory); - - vm.prank(VaultsRegistry(_vaultsRegistry).owner()); - VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); - - return factory; - } - - function _getPrevVersionVaultFactory( - VaultType _vaultType - ) internal pure returns (GnoVaultFactory) { - if (_vaultType == VaultType.GnoVault) { - return GnoVaultFactory(0xC2ecc7620416bd65bfab7010B0db955a0e49579a); - } else if (_vaultType == VaultType.GnoPrivVault) { - return GnoVaultFactory(0x574952EC88b2fC271d0C0dB130794c86Ea42139A); - } else if (_vaultType == VaultType.GnoBlocklistVault) { - return GnoVaultFactory(0x78FbfBd1DD38892476Ac469325df36604A27F5B7); - } else if (_vaultType == VaultType.GnoErc20Vault) { - return GnoVaultFactory(0xF6BBBc05536Ab198d4b7Ab74a93f8e2d4cAd5354); - } else if (_vaultType == VaultType.GnoPrivErc20Vault) { - return GnoVaultFactory(0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86); + function _mintGnoToken(address to, uint256 amount) internal { + vm.prank(IGnoToken(_gnoToken).owner()); + IGnoToken(_gnoToken).mint(to, amount); } - return GnoVaultFactory(0x99E4300326867FE3f97864a74e500d19654c19e9); - } - - function _setGnoWithdrawals(address vault, uint256 amount) internal { - // Mint GNO to the validators registry - _mintGnoToken(_validatorsRegistry, amount); - - // Access the system address to execute withdrawals - address systemAddr = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; - vm.deal(systemAddr, 1 ether); - - // Calculate the call amount - uint64 callAmount = uint64((amount * 32) / 1 gwei); - - uint64[] memory amounts = new uint64[](1); - amounts[0] = callAmount; - - address[] memory addresses = new address[](1); - addresses[0] = address(vault); - - // Execute system withdrawals as the system account - vm.startPrank(systemAddr); - // Call the executor function - this may need to be adjusted based on the registry implementation - (bool success, ) = _validatorsRegistry.call( - abi.encodeWithSignature('executeSystemWithdrawals(uint64[],address[])', amounts, addresses) - ); - vm.stopPrank(); - - // Ensure the call was successful - require(success, 'Setting GNO withdrawals failed'); - } - - function _startSnapshotGas(string memory label) internal { - if (vm.envBool('USE_FORK_VAULTS')) return; - return vm.startSnapshotGas(label); - } - - function _stopSnapshotGas() internal { - if (vm.envBool('USE_FORK_VAULTS')) return; - vm.stopSnapshotGas(); - } - - function _getForkVault(VaultType vaultType) internal view returns (address) { - if (vaultType == VaultType.GnoGenesisVault) { - return 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a; + + function _depositToVault(address vault, uint256 amount, address from, address to) internal { + vm.startPrank(from); + IERC20(_gnoToken).approve(vault, amount); + IGnoVault(vault).deposit(amount, to, address(0)); + vm.stopPrank(); } - if (!vm.envBool('USE_FORK_VAULTS')) return address(0); - - if (vaultType == VaultType.GnoVault) { - return 0x00025C729A3364FaEf02c7D1F577068d87E90ba6; - } else if (vaultType == VaultType.GnoBlocklistVault) { - return 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC; - } else if (vaultType == VaultType.GnoPrivVault) { - return 0x52Bd0fbF4839824680001d3653f2d503C6081085; - } else if (vaultType == VaultType.GnoErc20Vault) { - return 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD; - } else if (vaultType == VaultType.GnoPrivErc20Vault) { - return 0xdfdA4238359703180DAEc01e48F4625C1569c4dE; + function _collateralizeGnoVault(address vault) internal { + _collateralizeVault(_keeper, _validatorsRegistry, vault); } - return address(0); - } - - function _getVaultRewards( - address vault, - int160 newTotalReward, - uint160 newUnlockedMevReward - ) private view returns (int160, uint160) { - if (vault == 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a) { - newTotalReward += 14465786742141121046698; - newUnlockedMevReward += 12291679027502580216003; + + function _setGnoVaultReward(address vault, int160 totalReward, uint160 unlockedMevReward) + internal + returns (IKeeperRewards.HarvestParams memory harvestParams) + { + (totalReward, unlockedMevReward) = _getVaultRewards(vault, totalReward, unlockedMevReward); + SetVaultRewardParams memory params = SetVaultRewardParams({ + keeper: _keeper, + osTokenCtrl: _osTokenVaultController, + vault: vault, + totalReward: totalReward, + unlockedMevReward: unlockedMevReward + }); + return _setVaultReward(params); } - if (!vm.envBool('USE_FORK_VAULTS')) { - return (newTotalReward, newUnlockedMevReward); + function _registerGnoValidator(address vault, uint256 depositAmount, bool isV1Validator) + internal + returns (bytes memory publicKey) + { + // multiply by 32 to convert GNO to mGNO + return _registerValidator(_keeper, _validatorsRegistry, vault, depositAmount * 32, isV1Validator); + } + + function _getGnoValidatorApproval(address vault, uint256 depositAmount, string memory ipfsHash, bool isV1Validator) + internal + view + returns (IKeeperValidators.ApprovalParams memory harvestParams) + { + uint256[] memory deposits = new uint256[](1); + deposits[0] = (depositAmount * 32) / 1 gwei; + + harvestParams = _getValidatorsApproval(_keeper, _validatorsRegistry, vault, ipfsHash, deposits, isV1Validator); } - if (vault == 0x00025C729A3364FaEf02c7D1F577068d87E90ba6) { - newTotalReward += 393962803328781250000; - newUnlockedMevReward += 1680633820544574435947; - } else if (vault == 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC) { - newTotalReward += 1050592958531250000; - newUnlockedMevReward += 3442955231281615690; - } else if (vault == 0x52Bd0fbF4839824680001d3653f2d503C6081085) { - newTotalReward += 32023359208750000000; - } else if (vault == 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD) { - newTotalReward += 93551557523312500000; - newUnlockedMevReward += 199880304782632057829; - } else if (vault == 0xdfdA4238359703180DAEc01e48F4625C1569c4dE) { - newTotalReward += 5690635875000000; + function _getOrCreateVault(VaultType vaultType, address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address vault) + { + vault = _getForkVault(vaultType); + if (vault != address(0)) { + _upgradeVault(vaultType, vault); + if (Keeper(_keeper).isHarvestRequired(vault)) { + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(vault, 0, 0); + IVaultState(vault).updateState(harvestParams); + } + } else { + vault = _createVault(vaultType, admin, initParams, isOwnMevEscrow); + } + + address currentAdmin = IGnoVault(vault).admin(); + if (currentAdmin != admin) { + vm.prank(currentAdmin); + IGnoVault(vault).setAdmin(admin); + } + } + + function _getOrCreateFactory(VaultType _vaultType) internal returns (GnoVaultFactory) { + if (_vaultFactories[_vaultType] != address(0)) { + return GnoVaultFactory(_vaultFactories[_vaultType]); + } + + address impl = _getOrCreateVaultImpl(_vaultType); + GnoVaultFactory factory = new GnoVaultFactory(impl, IVaultsRegistry(_vaultsRegistry), _gnoToken); + + _vaultFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; } - return (newTotalReward, newUnlockedMevReward); - } - - function _createVault( - VaultType vaultType, - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address) { - GnoVaultFactory factory = _getOrCreateFactory(vaultType); - - vm.startPrank(admin); - IERC20(_gnoToken).approve(address(factory), _securityDeposit); - address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); - vm.stopPrank(); - - return vaultAddress; - } - - function _createPrevVersionVault( - VaultType vaultType, - address admin, - bytes memory initParams, - bool isOwnMevEscrow - ) internal returns (address) { - GnoVaultFactory factory = _getPrevVersionVaultFactory(vaultType); - - vm.startPrank(admin); - IERC20(_gnoToken).approve(address(factory), _securityDeposit); - address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); - vm.stopPrank(); - - return vaultAddress; - } - - function _upgradeVault(VaultType vaultType, address vault) internal { - GnoVault vaultContract = GnoVault(payable(vault)); - uint256 currentVersion = vaultContract.version(); - if (vaultType == VaultType.GnoGenesisVault) { - if (currentVersion == 4) return; - require(currentVersion == 3, 'Invalid vault version'); - } else { - if (currentVersion == 3) return; - require(currentVersion == 2, 'Invalid vault version'); + + function _getPrevVersionVaultFactory(VaultType _vaultType) internal pure returns (GnoVaultFactory) { + if (_vaultType == VaultType.GnoVault) { + return GnoVaultFactory(0xC2ecc7620416bd65bfab7010B0db955a0e49579a); + } else if (_vaultType == VaultType.GnoPrivVault) { + return GnoVaultFactory(0x574952EC88b2fC271d0C0dB130794c86Ea42139A); + } else if (_vaultType == VaultType.GnoBlocklistVault) { + return GnoVaultFactory(0x78FbfBd1DD38892476Ac469325df36604A27F5B7); + } else if (_vaultType == VaultType.GnoErc20Vault) { + return GnoVaultFactory(0xF6BBBc05536Ab198d4b7Ab74a93f8e2d4cAd5354); + } else if (_vaultType == VaultType.GnoPrivErc20Vault) { + return GnoVaultFactory(0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86); + } + return GnoVaultFactory(0x99E4300326867FE3f97864a74e500d19654c19e9); } - address newImpl = _getOrCreateVaultImpl(vaultType); - address admin = vaultContract.admin(); - vm.deal(admin, admin.balance + 1 ether); - vm.prank(admin); - vaultContract.upgradeToAndCall(newImpl, '0x'); - } + function _setGnoWithdrawals(address vault, uint256 amount) internal { + // Mint GNO to the validators registry + _mintGnoToken(_validatorsRegistry, amount); + + // Access the system address to execute withdrawals + address systemAddr = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; + vm.deal(systemAddr, 1 ether); + + // Calculate the call amount + uint64 callAmount = uint64((amount * 32) / 1 gwei); - function _getOrCreateVaultImpl(VaultType _vaultType) internal returns (address impl) { - if (_vaultImplementations[_vaultType] != address(0)) { - return _vaultImplementations[_vaultType]; + uint64[] memory amounts = new uint64[](1); + amounts[0] = callAmount; + + address[] memory addresses = new address[](1); + addresses[0] = address(vault); + + // Execute system withdrawals as the system account + vm.startPrank(systemAddr); + // Call the executor function - this may need to be adjusted based on the registry implementation + (bool success,) = _validatorsRegistry.call( + abi.encodeWithSignature("executeSystemWithdrawals(uint64[],address[])", amounts, addresses) + ); + vm.stopPrank(); + + // Ensure the call was successful + require(success, "Setting GNO withdrawals failed"); } - IGnoVault.GnoVaultConstructorArgs memory gnoArgs = IGnoVault.GnoVaultConstructorArgs( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - _validatorsWithdrawals, - _validatorsConsolidations, - _consolidationsChecker, - _osTokenVaultController, - _osTokenConfig, - _osTokenVaultEscrow, - _sharedMevEscrow, - _depositDataRegistry, - _gnoToken, - _gnoDaiDistributor, - _exitingAssetsClaimDelay - ); - IGnoErc20Vault.GnoErc20VaultConstructorArgs memory gnoErc20Args = IGnoErc20Vault - .GnoErc20VaultConstructorArgs( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - _validatorsWithdrawals, - _validatorsConsolidations, - _consolidationsChecker, - _osTokenVaultController, - _osTokenConfig, - _osTokenVaultEscrow, - _sharedMevEscrow, - _depositDataRegistry, - _gnoToken, - _gnoDaiDistributor, - _exitingAssetsClaimDelay - ); - - if (_vaultType == VaultType.GnoVault) { - impl = address(new GnoVault(gnoArgs)); - } else if (_vaultType == VaultType.GnoBlocklistVault) { - impl = address(new GnoBlocklistVault(gnoArgs)); - } else if (_vaultType == VaultType.GnoPrivVault) { - impl = address(new GnoPrivVault(gnoArgs)); - } else if (_vaultType == VaultType.GnoGenesisVault) { - impl = address(new GnoGenesisVault(gnoArgs, _poolEscrow, _rewardGnoToken)); - } else if (_vaultType == VaultType.GnoErc20Vault) { - impl = address(new GnoErc20Vault(gnoErc20Args)); - } else if (_vaultType == VaultType.GnoBlocklistErc20Vault) { - impl = address(new GnoBlocklistErc20Vault(gnoErc20Args)); - } else if (_vaultType == VaultType.GnoPrivErc20Vault) { - impl = address(new GnoPrivErc20Vault(gnoErc20Args)); + + function _startSnapshotGas(string memory label) internal { + if (vm.envBool("SKIP_SNAPSHOTS")) return; + return vm.startSnapshotGas(label); } - _vaultImplementations[_vaultType] = impl; - vm.prank(VaultsRegistry(_vaultsRegistry).owner()); - VaultsRegistry(_vaultsRegistry).addVaultImpl(impl); - } + function _stopSnapshotGas() internal { + if (vm.envBool("SKIP_SNAPSHOTS")) return; + vm.stopSnapshotGas(); + } + + function _getForkVault(VaultType vaultType) internal view returns (address) { + if (vaultType == VaultType.GnoGenesisVault) { + return 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a; + } + + if (!vm.envBool("USE_FORK_VAULTS")) return address(0); + + if (vaultType == VaultType.GnoVault) { + return 0x00025C729A3364FaEf02c7D1F577068d87E90ba6; + } else if (vaultType == VaultType.GnoBlocklistVault) { + return 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC; + } else if (vaultType == VaultType.GnoPrivVault) { + return 0x52Bd0fbF4839824680001d3653f2d503C6081085; + } else if (vaultType == VaultType.GnoErc20Vault) { + return 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD; + } else if (vaultType == VaultType.GnoPrivErc20Vault) { + return 0xdfdA4238359703180DAEc01e48F4625C1569c4dE; + } + return address(0); + } + + function _getVaultRewards(address vault, int160 newTotalReward, uint160 newUnlockedMevReward) + private + view + returns (int160, uint160) + { + if (vault == 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a) { + newTotalReward += 14465786742141121046698; + newUnlockedMevReward += 12291679027502580216003; + } + + if (!vm.envBool("USE_FORK_VAULTS")) { + return (newTotalReward, newUnlockedMevReward); + } + + if (vault == 0x00025C729A3364FaEf02c7D1F577068d87E90ba6) { + newTotalReward += 393962803328781250000; + newUnlockedMevReward += 1680633820544574435947; + } else if (vault == 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC) { + newTotalReward += 1050592958531250000; + newUnlockedMevReward += 3442955231281615690; + } else if (vault == 0x52Bd0fbF4839824680001d3653f2d503C6081085) { + newTotalReward += 32023359208750000000; + } else if (vault == 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD) { + newTotalReward += 93551557523312500000; + newUnlockedMevReward += 199880304782632057829; + } else if (vault == 0xdfdA4238359703180DAEc01e48F4625C1569c4dE) { + newTotalReward += 5690635875000000; + } + return (newTotalReward, newUnlockedMevReward); + } + + function _createVault(VaultType vaultType, address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address) + { + GnoVaultFactory factory = _getOrCreateFactory(vaultType); + + vm.startPrank(admin); + IERC20(_gnoToken).approve(address(factory), _securityDeposit); + address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); + vm.stopPrank(); + + return vaultAddress; + } + + function _createPrevVersionVault(VaultType vaultType, address admin, bytes memory initParams, bool isOwnMevEscrow) + internal + returns (address) + { + GnoVaultFactory factory = _getPrevVersionVaultFactory(vaultType); + + vm.startPrank(admin); + IERC20(_gnoToken).approve(address(factory), _securityDeposit); + address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); + vm.stopPrank(); + + return vaultAddress; + } + + function _upgradeVault(VaultType vaultType, address vault) internal { + GnoVault vaultContract = GnoVault(payable(vault)); + uint256 currentVersion = vaultContract.version(); + if (vaultType == VaultType.GnoGenesisVault) { + if (currentVersion == 4) return; + require(currentVersion == 3, "Invalid vault version"); + } else { + if (currentVersion == 3) return; + require(currentVersion == 2, "Invalid vault version"); + } + address newImpl = _getOrCreateVaultImpl(vaultType); + address admin = vaultContract.admin(); + + vm.deal(admin, admin.balance + 1 ether); + vm.prank(admin); + vaultContract.upgradeToAndCall(newImpl, "0x"); + } + + function _getOrCreateVaultImpl(VaultType _vaultType) internal returns (address impl) { + if (_vaultImplementations[_vaultType] != address(0)) { + return _vaultImplementations[_vaultType]; + } + IGnoVault.GnoVaultConstructorArgs memory gnoArgs = IGnoVault.GnoVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + _gnoToken, + _gnoDaiDistributor, + _exitingAssetsClaimDelay + ); + IGnoErc20Vault.GnoErc20VaultConstructorArgs memory gnoErc20Args = IGnoErc20Vault.GnoErc20VaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _sharedMevEscrow, + _depositDataRegistry, + _gnoToken, + _gnoDaiDistributor, + _exitingAssetsClaimDelay + ); + + if (_vaultType == VaultType.GnoVault) { + impl = address(new GnoVault(gnoArgs)); + } else if (_vaultType == VaultType.GnoBlocklistVault) { + impl = address(new GnoBlocklistVault(gnoArgs)); + } else if (_vaultType == VaultType.GnoPrivVault) { + impl = address(new GnoPrivVault(gnoArgs)); + } else if (_vaultType == VaultType.GnoGenesisVault) { + impl = address(new GnoGenesisVault(gnoArgs, _poolEscrow, _rewardGnoToken)); + } else if (_vaultType == VaultType.GnoErc20Vault) { + impl = address(new GnoErc20Vault(gnoErc20Args)); + } else if (_vaultType == VaultType.GnoBlocklistErc20Vault) { + impl = address(new GnoBlocklistErc20Vault(gnoErc20Args)); + } else if (_vaultType == VaultType.GnoPrivErc20Vault) { + impl = address(new GnoPrivErc20Vault(gnoErc20Args)); + } + _vaultImplementations[_vaultType] = impl; + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addVaultImpl(impl); + } } diff --git a/test/helpers/KeeperHelpers.sol b/test/helpers/KeeperHelpers.sol index c1fd2e9c..cc07dfdf 100644 --- a/test/helpers/KeeperHelpers.sol +++ b/test/helpers/KeeperHelpers.sol @@ -2,131 +2,122 @@ pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; -import {IKeeperRewards} from '../../contracts/interfaces/IKeeperRewards.sol'; -import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; -import {IOsTokenVaultController} from '../../contracts/interfaces/IOsTokenVaultController.sol'; -import {Keeper} from '../../contracts/keeper/Keeper.sol'; +import {Test} from "forge-std/Test.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; +import {IOsTokenVaultController} from "../../contracts/interfaces/IOsTokenVaultController.sol"; +import {Keeper} from "../../contracts/keeper/Keeper.sol"; abstract contract KeeperHelpers is Test { - struct SetVaultRewardParams { - address keeper; - address osTokenCtrl; - address vault; - int160 totalReward; - uint160 unlockedMevReward; - } - - address private _oracle; - uint256 internal _oraclePrivateKey; - uint256 private _validatorsMinOraclesBefore; - uint256 private _rewardsMinOraclesBefore; - - function _startOracleImpersonate(address keeper) internal { - if (_oracle != address(0)) return; - - _validatorsMinOraclesBefore = Keeper(keeper).validatorsMinOracles(); - _rewardsMinOraclesBefore = Keeper(keeper).rewardsMinOracles(); - - (_oracle, _oraclePrivateKey) = makeAddrAndKey('oracle'); - vm.startPrank(Keeper(keeper).owner()); - Keeper(keeper).setValidatorsMinOracles(1); - Keeper(keeper).setRewardsMinOracles(1); - Keeper(keeper).addOracle(_oracle); - vm.stopPrank(); - } - - function _stopOracleImpersonate(address keeper) internal { - if (_oracle == address(0)) return; - vm.startPrank(Keeper(keeper).owner()); - Keeper(keeper).setValidatorsMinOracles(_validatorsMinOraclesBefore); - Keeper(keeper).setRewardsMinOracles(_rewardsMinOraclesBefore); - Keeper(keeper).removeOracle(_oracle); - vm.stopPrank(); - - _oracle = address(0); - _oraclePrivateKey = 0; - _validatorsMinOraclesBefore = 0; - _rewardsMinOraclesBefore = 0; - } - - function _setVaultReward( - SetVaultRewardParams memory params - ) internal returns (IKeeperRewards.HarvestParams memory harvestParams) { - // setup oracle - _startOracleImpersonate(params.keeper); - - bytes32 rewardsRoot = keccak256( - bytes.concat( - keccak256(abi.encode(params.vault, params.totalReward, params.unlockedMevReward)) - ) - ); - - uint256 avgRewardPerSecond = IOsTokenVaultController(params.osTokenCtrl).avgRewardPerSecond(); - uint64 updateTimestamp = uint64(vm.getBlockTimestamp()); - string memory ipfsHash = 'rewardsIpfsHash'; - uint256 rewardsNonce = Keeper(params.keeper).rewardsNonce(); - bytes32 digest = _hashKeeperTypedData( - params.keeper, - keccak256( - abi.encode( - keccak256( - 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' - ), - rewardsRoot, - keccak256(bytes(ipfsHash)), - avgRewardPerSecond, - updateTimestamp, - rewardsNonce - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - - // push down the stack - SetVaultRewardParams memory _params = params; - IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ - rewardsRoot: rewardsRoot, - rewardsIpfsHash: ipfsHash, - avgRewardPerSecond: avgRewardPerSecond, - updateTimestamp: updateTimestamp, - signatures: abi.encodePacked(r, s, v) - }); - - vm.warp(vm.getBlockTimestamp() + Keeper(_params.keeper).rewardsDelay() + 1); - Keeper(_params.keeper).updateRewards(updateParams); - - _stopOracleImpersonate(params.keeper); - - bytes32[] memory proof = new bytes32[](0); - return - IKeeperRewards.HarvestParams({ - rewardsRoot: rewardsRoot, - reward: _params.totalReward, - unlockedMevReward: _params.unlockedMevReward, - proof: proof - }); - } - - function _hashKeeperTypedData( - address keeper, - bytes32 structHash - ) internal view returns (bytes32) { - return - MessageHashUtils.toTypedDataHash( - keccak256( - abi.encode( + struct SetVaultRewardParams { + address keeper; + address osTokenCtrl; + address vault; + int160 totalReward; + uint160 unlockedMevReward; + } + + address private _oracle; + uint256 internal _oraclePrivateKey; + uint256 private _validatorsMinOraclesBefore; + uint256 private _rewardsMinOraclesBefore; + + function _startOracleImpersonate(address keeper) internal { + if (_oracle != address(0)) return; + + _validatorsMinOraclesBefore = Keeper(keeper).validatorsMinOracles(); + _rewardsMinOraclesBefore = Keeper(keeper).rewardsMinOracles(); + + (_oracle, _oraclePrivateKey) = makeAddrAndKey("oracle"); + vm.startPrank(Keeper(keeper).owner()); + Keeper(keeper).setValidatorsMinOracles(1); + Keeper(keeper).setRewardsMinOracles(1); + Keeper(keeper).addOracle(_oracle); + vm.stopPrank(); + } + + function _stopOracleImpersonate(address keeper) internal { + if (_oracle == address(0)) return; + vm.startPrank(Keeper(keeper).owner()); + Keeper(keeper).setValidatorsMinOracles(_validatorsMinOraclesBefore); + Keeper(keeper).setRewardsMinOracles(_rewardsMinOraclesBefore); + Keeper(keeper).removeOracle(_oracle); + vm.stopPrank(); + + _oracle = address(0); + _oraclePrivateKey = 0; + _validatorsMinOraclesBefore = 0; + _rewardsMinOraclesBefore = 0; + } + + function _setVaultReward(SetVaultRewardParams memory params) + internal + returns (IKeeperRewards.HarvestParams memory harvestParams) + { + // setup oracle + _startOracleImpersonate(params.keeper); + + bytes32 rewardsRoot = + keccak256(bytes.concat(keccak256(abi.encode(params.vault, params.totalReward, params.unlockedMevReward)))); + + uint256 avgRewardPerSecond = IOsTokenVaultController(params.osTokenCtrl).avgRewardPerSecond(); + uint64 updateTimestamp = uint64(vm.getBlockTimestamp()); + string memory ipfsHash = "rewardsIpfsHash"; + uint256 rewardsNonce = Keeper(params.keeper).rewardsNonce(); + bytes32 digest = _hashKeeperTypedData( + params.keeper, keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' + abi.encode( + keccak256( + "KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)" + ), + rewardsRoot, + keccak256(bytes(ipfsHash)), + avgRewardPerSecond, + updateTimestamp, + rewardsNonce + ) + ) + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + + // push down the stack + SetVaultRewardParams memory _params = params; + IKeeperRewards.RewardsUpdateParams memory updateParams = IKeeperRewards.RewardsUpdateParams({ + rewardsRoot: rewardsRoot, + rewardsIpfsHash: ipfsHash, + avgRewardPerSecond: avgRewardPerSecond, + updateTimestamp: updateTimestamp, + signatures: abi.encodePacked(r, s, v) + }); + + vm.warp(vm.getBlockTimestamp() + Keeper(_params.keeper).rewardsDelay() + 1); + Keeper(_params.keeper).updateRewards(updateParams); + + _stopOracleImpersonate(params.keeper); + + bytes32[] memory proof = new bytes32[](0); + return IKeeperRewards.HarvestParams({ + rewardsRoot: rewardsRoot, + reward: _params.totalReward, + unlockedMevReward: _params.unlockedMevReward, + proof: proof + }); + } + + function _hashKeeperTypedData(address keeper, bytes32 structHash) internal view returns (bytes32) { + return MessageHashUtils.toTypedDataHash( + keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes("KeeperOracles")), + keccak256(bytes("1")), + block.chainid, + keeper + ) ), - keccak256(bytes('KeeperOracles')), - keccak256(bytes('1')), - block.chainid, - keeper - ) - ), - structHash - ); - } + structHash + ); + } } diff --git a/test/helpers/ValidatorsHelpers.sol b/test/helpers/ValidatorsHelpers.sol index 8f8f86d5..f18247e6 100644 --- a/test/helpers/ValidatorsHelpers.sol +++ b/test/helpers/ValidatorsHelpers.sol @@ -2,196 +2,173 @@ pragma solidity ^0.8.22; -import {Test} from 'forge-std/Test.sol'; -import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import {Keeper, IKeeper} from '../../contracts/keeper/Keeper.sol'; -import {IKeeperValidators} from '../../contracts/interfaces/IKeeperValidators.sol'; -import {IVaultValidators} from '../../contracts/interfaces/IVaultValidators.sol'; -import {IValidatorsRegistry} from '../../contracts/interfaces/IValidatorsRegistry.sol'; -import {KeeperHelpers} from './KeeperHelpers.sol'; +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Keeper, IKeeper} from "../../contracts/keeper/Keeper.sol"; +import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; +import {IVaultValidators} from "../../contracts/interfaces/IVaultValidators.sol"; +import {IValidatorsRegistry} from "../../contracts/interfaces/IValidatorsRegistry.sol"; +import {KeeperHelpers} from "./KeeperHelpers.sol"; abstract contract ValidatorsHelpers is Test, KeeperHelpers { - function _registerValidator( - address keeper, - address validatorsRegistry, - address vault, - uint256 depositAmount, - bool isV1Validator - ) internal returns (bytes memory) { - // setup oracle - _startOracleImpersonate(keeper); - - uint256[] memory deposits = new uint256[](1); - deposits[0] = (depositAmount) / 1 gwei; - - // Test successful registration with 0x01 prefix - IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( - keeper, - validatorsRegistry, - vault, - 'ipfsHash', - deposits, - isV1Validator - ); - - address validatorsManager = IVaultValidators(vault).validatorsManager(); - vm.prank(validatorsManager); - IVaultValidators(vault).registerValidators(approvalParams, ''); - - _stopOracleImpersonate(keeper); - - return _extractBytes(approvalParams.validators, 0, 48); - } - - function _extractBytes( - bytes memory data, - uint256 offset, - uint256 length - ) internal pure returns (bytes memory) { - bytes memory result = new bytes(length); - for (uint i = 0; i < length; i++) { - if (offset + i < data.length) { - result[i] = data[offset + i]; - } else { - break; // Prevent reading beyond array bounds - } + function _registerValidator( + address keeper, + address validatorsRegistry, + address vault, + uint256 depositAmount, + bool isV1Validator + ) internal returns (bytes memory) { + // setup oracle + _startOracleImpersonate(keeper); + + uint256[] memory deposits = new uint256[](1); + deposits[0] = (depositAmount) / 1 gwei; + + // Test successful registration with 0x01 prefix + IKeeperValidators.ApprovalParams memory approvalParams = + _getValidatorsApproval(keeper, validatorsRegistry, vault, "ipfsHash", deposits, isV1Validator); + + address validatorsManager = IVaultValidators(vault).validatorsManager(); + vm.prank(validatorsManager); + IVaultValidators(vault).registerValidators(approvalParams, ""); + + _stopOracleImpersonate(keeper); + + return _extractBytes(approvalParams.validators, 0, 48); } - return result; - } - - function _collateralizeVault(address keeper, address validatorsRegistry, address vault) internal { - if (IKeeper(keeper).isCollateralized(vault)) return; - - _startOracleImpersonate(keeper); - - uint256[] memory depositAmounts = new uint256[](1); - depositAmounts[0] = 32 ether / 1 gwei; - IKeeperValidators.ApprovalParams memory approvalParams = _getValidatorsApproval( - keeper, - validatorsRegistry, - vault, - 'ipfsHash', - depositAmounts, - false - ); - - vm.prank(vault); - IKeeper(keeper).approveValidators(approvalParams); - - // revert previous state - _stopOracleImpersonate(keeper); - } - - function _getValidatorsApproval( - address keeper, - address validatorsRegistry, - address vault, - string memory ipfsHash, - uint256[] memory deposits, - bool isV1Validator - ) internal view returns (IKeeperValidators.ApprovalParams memory approvalParams) { - bytes memory validators; - for (uint i = 0; i < deposits.length; i++) { - bytes memory validator = _getValidatorDepositData(vault, deposits[i], isV1Validator); - validators = bytes.concat(validators, validator); + + function _extractBytes(bytes memory data, uint256 offset, uint256 length) internal pure returns (bytes memory) { + bytes memory result = new bytes(length); + for (uint256 i = 0; i < length; i++) { + if (offset + i < data.length) { + result[i] = data[offset + i]; + } else { + break; // Prevent reading beyond array bounds + } + } + return result; + } + + function _collateralizeVault(address keeper, address validatorsRegistry, address vault) internal { + if (IKeeper(keeper).isCollateralized(vault)) return; + + _startOracleImpersonate(keeper); + + uint256[] memory depositAmounts = new uint256[](1); + depositAmounts[0] = 32 ether / 1 gwei; + IKeeperValidators.ApprovalParams memory approvalParams = + _getValidatorsApproval(keeper, validatorsRegistry, vault, "ipfsHash", depositAmounts, false); + + vm.prank(vault); + IKeeper(keeper).approveValidators(approvalParams); + + // revert previous state + _stopOracleImpersonate(keeper); } - approvalParams = IKeeperValidators.ApprovalParams({ - validatorsRegistryRoot: IValidatorsRegistry(validatorsRegistry).get_deposit_root(), - deadline: vm.getBlockTimestamp() + 1, - validators: validators, - signatures: '', - exitSignaturesIpfsHash: ipfsHash - }); - bytes32 digest = _hashKeeperTypedData( - keeper, - keccak256( - abi.encode( - keccak256( - 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' - ), - approvalParams.validatorsRegistryRoot, - vault, - keccak256(approvalParams.validators), - keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), - approvalParams.deadline - ) - ) - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); - approvalParams.signatures = abi.encodePacked(r, s, v); - } - - function _getValidatorDepositData( - address vault, - uint256 depositAmount, - bool isV1Validator - ) internal view returns (bytes memory) { - bytes memory publicKey = vm.randomBytes(48); - bytes memory signature = vm.randomBytes(96); - bytes memory withdrawalCredentials = abi.encodePacked( - isV1Validator ? bytes1(0x01) : bytes1(0x02), - bytes11(0x0), - vault - ); - bytes32 depositDataRoot = _getDepositDataRoot( - publicKey, - signature, - withdrawalCredentials, - depositAmount - ); - return - isV1Validator - ? bytes.concat(publicKey, signature, depositDataRoot) - : bytes.concat( - publicKey, - signature, - depositDataRoot, - bytes8(SafeCast.toUint64(depositAmount)) + function _getValidatorsApproval( + address keeper, + address validatorsRegistry, + address vault, + string memory ipfsHash, + uint256[] memory deposits, + bool isV1Validator + ) internal view returns (IKeeperValidators.ApprovalParams memory approvalParams) { + bytes memory validators; + bytes32 validatorsRegistryRoot = IValidatorsRegistry(validatorsRegistry).get_deposit_root(); + for (uint256 i = 0; i < deposits.length; i++) { + bytes memory validator = _getValidatorDepositData(vault, deposits[i], validatorsRegistryRoot, isV1Validator); + validators = bytes.concat(validators, validator); + } + + approvalParams = IKeeperValidators.ApprovalParams({ + validatorsRegistryRoot: validatorsRegistryRoot, + deadline: vm.getBlockTimestamp() + 1, + validators: validators, + signatures: "", + exitSignaturesIpfsHash: ipfsHash + }); + bytes32 digest = _hashKeeperTypedData( + keeper, + keccak256( + abi.encode( + keccak256( + "KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)" + ), + approvalParams.validatorsRegistryRoot, + vault, + keccak256(approvalParams.validators), + keccak256(bytes(approvalParams.exitSignaturesIpfsHash)), + approvalParams.deadline + ) + ) ); - } - - function _getDepositDataRoot( - bytes memory publicKey, - bytes memory signature, - bytes memory withdrawalCredentials, - uint256 depositAmount - ) internal pure returns (bytes32) { - bytes memory amount = _toLittleEndian64(uint64(depositAmount)); - bytes32 publicKeyRoot = sha256(abi.encodePacked(publicKey, bytes16(0))); - - bytes memory signatureFirstHalf = new bytes(64); - bytes memory signatureSecondHalf = new bytes(64); - for (uint i = 0; i < 64; i++) { - signatureFirstHalf[i] = signature[i]; + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_oraclePrivateKey, digest); + approvalParams.signatures = abi.encodePacked(r, s, v); } - for (uint i = 0; i < 32; i++) { - signatureSecondHalf[i] = signature[i + 64]; + + function _getValidatorDepositData( + address vault, + uint256 depositAmount, + bytes32 validatorsRegistryRoot, + bool isV1Validator + ) internal pure returns (bytes memory) { + bytes memory publicKey = _getDeterministicBytes(validatorsRegistryRoot, 48); + bytes memory signature = _getDeterministicBytes(validatorsRegistryRoot, 96); + bytes memory withdrawalCredentials = + abi.encodePacked(isV1Validator ? bytes1(0x01) : bytes1(0x02), bytes11(0x0), vault); + bytes32 depositDataRoot = _getDepositDataRoot(publicKey, signature, withdrawalCredentials, depositAmount); + return isV1Validator + ? bytes.concat(publicKey, signature, depositDataRoot) + : bytes.concat(publicKey, signature, depositDataRoot, bytes8(SafeCast.toUint64(depositAmount))); + } + + function _getDepositDataRoot( + bytes memory publicKey, + bytes memory signature, + bytes memory withdrawalCredentials, + uint256 depositAmount + ) internal pure returns (bytes32) { + bytes memory amount = _toLittleEndian64(uint64(depositAmount)); + bytes32 publicKeyRoot = sha256(abi.encodePacked(publicKey, bytes16(0))); + + bytes memory signatureFirstHalf = new bytes(64); + bytes memory signatureSecondHalf = new bytes(64); + for (uint256 i = 0; i < 64; i++) { + signatureFirstHalf[i] = signature[i]; + } + for (uint256 i = 0; i < 32; i++) { + signatureSecondHalf[i] = signature[i + 64]; + } + + bytes32 signatureRoot = sha256(abi.encodePacked(sha256(signatureFirstHalf), sha256(signatureSecondHalf))); + return sha256( + abi.encodePacked( + sha256(abi.encodePacked(publicKeyRoot, withdrawalCredentials)), + sha256(abi.encodePacked(amount, bytes24(0), signatureRoot)) + ) + ); } - bytes32 signatureRoot = sha256( - abi.encodePacked(sha256(signatureFirstHalf), sha256(signatureSecondHalf)) - ); - return - sha256( - abi.encodePacked( - sha256(abi.encodePacked(publicKeyRoot, withdrawalCredentials)), - sha256(abi.encodePacked(amount, bytes24(0), signatureRoot)) - ) - ); - } - - function _toLittleEndian64(uint64 value) private pure returns (bytes memory ret) { - ret = new bytes(8); - bytes8 bytesValue = bytes8(value); - // Byte swapping during copying to bytes. - ret[0] = bytesValue[7]; - ret[1] = bytesValue[6]; - ret[2] = bytesValue[5]; - ret[3] = bytesValue[4]; - ret[4] = bytesValue[3]; - ret[5] = bytesValue[2]; - ret[6] = bytesValue[1]; - ret[7] = bytesValue[0]; - } + function _toLittleEndian64(uint64 value) private pure returns (bytes memory ret) { + ret = new bytes(8); + bytes8 bytesValue = bytes8(value); + // Byte swapping during copying to bytes. + ret[0] = bytesValue[7]; + ret[1] = bytesValue[6]; + ret[2] = bytesValue[5]; + ret[3] = bytesValue[4]; + ret[4] = bytesValue[3]; + ret[5] = bytesValue[2]; + ret[6] = bytesValue[1]; + ret[7] = bytesValue[0]; + } + + function _getDeterministicBytes(bytes32 seed, uint256 length) internal pure returns (bytes memory) { + bytes memory result = new bytes(length); + for (uint256 i = 0; i < length; i++) { + result[i] = bytes1(uint8(uint256(keccak256(abi.encodePacked(seed, i))) % 256)); + } + return result; + } } From 3e49eaeddc39ee16284f17f8037f8519702f77e1 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Sun, 13 Apr 2025 20:53:21 +0300 Subject: [PATCH 10/15] Do not run coverage on main push (#110) --- .github/workflows/coverage.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 403135d3..f6e4970c 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -1,9 +1,6 @@ name: code coverage on: - push: - branches: - - main pull_request: jobs: From 4a00479509c3ea485baa05e6531141e237a17df7 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Mon, 14 Apr 2025 13:29:38 +0300 Subject: [PATCH 11/15] Decrease fee change cooldown (#111) --- contracts/vaults/modules/VaultFee.sol | 2 +- test/VaultFee.t.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/vaults/modules/VaultFee.sol b/contracts/vaults/modules/VaultFee.sol index fd6015fd..709d0e68 100644 --- a/contracts/vaults/modules/VaultFee.sol +++ b/contracts/vaults/modules/VaultFee.sol @@ -15,7 +15,7 @@ import {VaultImmutables} from "./VaultImmutables.sol"; */ abstract contract VaultFee is VaultImmutables, Initializable, VaultAdmin, IVaultFee { uint256 internal constant _maxFeePercent = 10_000; // @dev 100.00 % - uint256 private constant _feeUpdateDelay = 7 days; + uint256 private constant _feeUpdateDelay = 3 days; /// @inheritdoc IVaultFee address public override feeRecipient; diff --git a/test/VaultFee.t.sol b/test/VaultFee.t.sol index 0a546772..1ed80560 100644 --- a/test/VaultFee.t.sol +++ b/test/VaultFee.t.sol @@ -21,7 +21,7 @@ contract VaultFeeTest is Test, EthHelpers { uint16 public initialFeePercent; uint256 public depositAmount = 10 ether; uint256 public rewardAmount = 1 ether; - uint256 public feeChangeDelay = 7 days; + uint256 public feeChangeDelay = 3 days; function setUp() public { // Activate Ethereum fork and get the contracts From af11052a47b28808d77b174fdd17de2d0c9dca0e Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Tue, 15 Apr 2025 16:38:22 +0300 Subject: [PATCH 12/15] Fix script (#112) * Update env variables names * add deployments, update end example, foundry.toml * Update deployment files * Update deploy scripts, readme, .env.example * Update execute governor txs script * Add contracts to deployments * Add deploy script for gnosis * Fix test profile in foundry --- .env.example | 20 +- .github/workflows/coverage.yaml | 4 +- .github/workflows/test-fork.yaml | 4 +- .github/workflows/test.yaml | 4 +- README.md | 11 +- deployments/chiado.json | 29 +++ deployments/gnosis.json | 29 +++ deployments/hoodi.json | 26 +++ deployments/mainnet.json | 26 +++ foundry.toml | 13 ++ script/ExecuteGovernorTxs.s.sol | 52 +++++ script/Network.sol | 375 +++++++++++++++++++++---------- script/UpgradeEthNetwork.s.sol | 175 ++++++++------- script/UpgradeGnoNetwork.s.sol | 182 +++++++++++++++ test/helpers/EthHelpers.sol | 8 +- test/helpers/GnoHelpers.sol | 8 +- 16 files changed, 747 insertions(+), 219 deletions(-) create mode 100644 deployments/chiado.json create mode 100644 deployments/gnosis.json create mode 100644 deployments/hoodi.json create mode 100644 deployments/mainnet.json create mode 100644 script/ExecuteGovernorTxs.s.sol create mode 100644 script/UpgradeGnoNetwork.s.sol diff --git a/.env.example b/.env.example index a4d553cf..adc716dc 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,20 @@ +# endpoints MAINNET_RPC_URL=http://localhost:8545 GNOSIS_RPC_URL=http://localhost:8546 -USE_FORK_VAULTS=false -SKIP_SNAPSHOTS=false \ No newline at end of file +HOODI_RPC_URL=http://localhost:8547 +CHIADO_RPC_URL=http://localhost:8548 + +# verification +ETHERSCAN_API_KEY=123 +GNOSISSCAN_API_KEY=456 + +# test settings +# Use this to run tests with a forked vault contracts +TEST_USE_FORK_VAULTS=false +# Skip snapshots update in tests +TEST_SKIP_SNAPSHOTS=false + +# deployment +PRIVATE_KEY=0x12345 +# Add transactions to remove vault factories in current deployment files +REMOVE_PREV_FACTORIES=false \ No newline at end of file diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index f6e4970c..3af07c92 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -39,8 +39,8 @@ jobs: env: MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} GNOSIS_RPC_URL: ${{ secrets.GNOSIS_RPC_URL }} - SKIP_SNAPSHOTS: true - USE_FORK_VAULTS: false + TEST_SKIP_SNAPSHOTS: true + TEST_USE_FORK_VAULTS: false - name: Check coverage is updated uses: actions/github-script@v5 diff --git a/.github/workflows/test-fork.yaml b/.github/workflows/test-fork.yaml index ced24763..bfd96d15 100644 --- a/.github/workflows/test-fork.yaml +++ b/.github/workflows/test-fork.yaml @@ -25,8 +25,8 @@ jobs: run: forge test --isolate -vvv env: FORGE_SNAPSHOT_CHECK: false - USE_FORK_VAULTS: true - SKIP_SNAPSHOTS: true + TEST_USE_FORK_VAULTS: true + TEST_SKIP_SNAPSHOTS: true MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} GNOSIS_RPC_URL: ${{ secrets.GNOSIS_RPC_URL }} FOUNDRY_PROFILE: test diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2401c297..fc22b751 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -24,8 +24,8 @@ jobs: - name: Run tests run: forge test --isolate --gas-snapshot-check=true -vvv env: - USE_FORK_VAULTS: false - SKIP_SNAPSHOTS: false + TEST_USE_FORK_VAULTS: false + TEST_SKIP_SNAPSHOTS: false MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} GNOSIS_RPC_URL: ${{ secrets.GNOSIS_RPC_URL }} FOUNDRY_PROFILE: test diff --git a/README.md b/README.md index e271ae4d..573e915a 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,12 @@ cd v3-core forge install ``` +3. Create and update .env file + +```shell +cp .env.example .env +``` + ## Development ### Compilation @@ -91,13 +97,16 @@ FOUNDRY_PROFILE=test forge test --isolate 1. Start a local Anvil node (Foundry's local chain): ```shell -anvil +anvil --fork-url https://eth.merkle.io ``` 2. Deploy contracts using Foundry scripts: ```shell +# Ethereum forge script script/UpgradeEthNetwork.s.sol:UpgradeEthNetwork --rpc-url http://localhost:8545 --broadcast +# Gnosis Chain +forge script script/UpgradeGnoNetwork.s.sol:UpgradeGnoNetwork --rpc-url http://localhost:8545 --broadcast ``` ### Gas Analysis diff --git a/deployments/chiado.json b/deployments/chiado.json new file mode 100644 index 00000000..b4f6cb95 --- /dev/null +++ b/deployments/chiado.json @@ -0,0 +1,29 @@ +{ + "VaultsRegistry": "0x8750594B33516232e751C8B9C350a660cD5f1BB8", + "Keeper": "0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988", + "DepositDataRegistry": "0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D", + "ValidatorsChecker": "0x35B119c61B3Bb97f324423Ef5D3A82243daBb1B6", + "XdaiExchange": "0x3517FD486D275FD3A49128E50e67FFb24a537B26", + "GenesisVault": "0xF82f6E46d0d0a9536b9CA4bc480372EeaFcd9E6c", + "VaultFactory": "0x14892a30Be63A7ecB56300357C77B7c9f1760193", + "PrivVaultFactory": "0xeF693eCCd1904279aE05248f1349D5848948AAB2", + "BlocklistVaultFactory": "0xB0db872d2F1F6cC807e09e65F7c0dFcCA5F5f2B0", + "Erc20VaultFactory": "0xd97a5a24c05A0C068fB0277879f4a1Fc7bdaF5d8", + "PrivErc20VaultFactory": "0x2cC4E3410039082Fb91a7aACB693d2B96FdFb052", + "BlocklistErc20VaultFactory": "0x45C9D93F786C71A08B10477f1eB8c42753616EBe", + "SharedMevEscrow": "0x453056f0bc4631abB15eEC656139f88067668E3E", + "OsToken": "0x0b4F6bFB694790051E0203Db83edbB5888099556", + "OsTokenConfig": "0x6D5957e075fd93b3B9F36Da93d7462F14387706d", + "OsTokenVaultController": "0x5518052f2d898f062ee59964004A560F24E2eE7d", + "OsTokenVaultEscrow": "0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7", + "OsTokenFlashLoans": "0x7bC48037433d610C6069a873beA8CF7D3cE1Ff01", + "PriceFeed": "0x3CC131e6f6b975423151E5aaE8C466f4f81A8A4c", + "RewardSplitterFactory": "0x6EE912596DCC3a8b7308164A65Af529a4276737C", + "ValidatorsRegistry": "0xb97036A26259B7147018913bD58a774cf91acf25", + "LegacyPoolEscrow": "0x928F9a91E674C886Cae0c377670109aBeF7e19d6", + "LegacyRewardToken": "0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4", + "MerkleDistributor": "0xd0747320d5457256D0203dfe61209Afbb90d22D7", + "GnoToken": "0x19C653Da7c37c66208fbfbE8908A5051B57b4C70", + "SDaiToken": "0x20e5eB701E8d711D419D444814308f8c2243461F", + "SavingsXDaiAdapter": "0xc1529e13A5842D790da01F778Bf23a3677830986" +} \ No newline at end of file diff --git a/deployments/gnosis.json b/deployments/gnosis.json new file mode 100644 index 00000000..2a5a83e8 --- /dev/null +++ b/deployments/gnosis.json @@ -0,0 +1,29 @@ +{ + "VaultsRegistry": "0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB", + "Keeper": "0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa", + "DepositDataRegistry": "0x58e16621B5c0786D6667D2d54E28A20940269E16", + "ValidatorsChecker": "0x3E2CC1584a2fB4FB2D4f4aF68AE47B57BE76dC65", + "XdaiExchange": "0x000108f8dFc532263C307242cF6773312b28f855", + "GenesisVault": "0x4b4406Ed8659D03423490D8b62a1639206dA0A7a", + "VaultFactory": "0x78c54FEfAB5DAb75ee7461565b85341dd8b92e30", + "PrivVaultFactory": "0x79168E105a72b97AA95FC8496e3B5D5F96f90491", + "BlocklistVaultFactory": "0x16B7Ef24eF7a85b49F77fF4c7fff819DA9c1E236", + "Erc20VaultFactory": "0x0aaa2b3Cf5F14eF24Afb2CD7Cf4CcCC065Be108B", + "PrivErc20VaultFactory": "0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd", + "BlocklistErc20VaultFactory": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", + "SharedMevEscrow": "0x30db0d10d3774e78f8cB214b9e8B72D4B402488a", + "OsToken": "0xF490c80aAE5f2616d3e3BDa2483E30C4CB21d1A0", + "OsTokenConfig": "0xd6672fbE1D28877db598DC0ac2559A15745FC3ec", + "OsTokenVaultController": "0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a", + "OsTokenVaultEscrow": "0x28F325dD287a5984B754d34CfCA38af3A8429e71", + "OsTokenFlashLoans": "0xe84183EfFbcc76D022Cccc31b95EAa332bB5Bb11", + "PriceFeed": "0x9B1b13afA6a57e54C03AD0428a4766C39707D272", + "RewardSplitterFactory": "0x4c6306BA1821D88803e27A115433520F2d6276Fb", + "ValidatorsRegistry": "0x0B98057eA310F4d31F2a452B414647007d1645d9", + "LegacyPoolEscrow": "0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394", + "LegacyRewardToken": "0x6aC78efae880282396a335CA2F79863A1e6831D4", + "MerkleDistributor": "0xFBceefdBB0ca25a4043b35EF49C2810425243710", + "GnoToken": "0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb", + "SDaiToken": "0xaf204776c7245bF4147c2612BF6e5972Ee483701", + "SavingsXDaiAdapter": "0xD499b51fcFc66bd31248ef4b28d656d67E591A94" +} diff --git a/deployments/hoodi.json b/deployments/hoodi.json new file mode 100644 index 00000000..77e0f5f6 --- /dev/null +++ b/deployments/hoodi.json @@ -0,0 +1,26 @@ +{ + "VaultsRegistry": "0xf16fea93D3253A401C3f73B0De890C6586740B25", + "Keeper": "0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f", + "DepositDataRegistry": "0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487", + "ValidatorsChecker": "0xB790391ee99b9193Ebb80022bf127d24Bac586c4", + "GenesisVault": "0xba447498DC4c169f2b4f427B2c4D532320457E89", + "VaultFactory": "0x508e82B5119CCfB923C387d62D2Ae7B56Df79906", + "PrivVaultFactory": "0x9115E176C3d034339036194c3EB7014Ef04A2e4b", + "BlocklistVaultFactory": "0xE2121568066C0a9d794bbB95D0Ade0ebd81cCaf9", + "Erc20VaultFactory": "0xBb1B3E55315967c65133A0e942d8EA7a992aF6C7", + "PrivErc20VaultFactory": "0x76D90928645065b4D4212eE62ce1ba8f90718f14", + "BlocklistErc20VaultFactory": "0x4E3dE90882B3d10D067b8954909D4A4b0Bb390D0", + "SharedMevEscrow": "0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd", + "OsToken": "0x7345fC8268459413beE9e9dd327f31283C65Ee7e", + "OsTokenConfig": "0x5b817621EBE00622b9a71b53c942b392751c8197", + "OsTokenVaultController": "0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1", + "OsTokenVaultEscrow": "0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B", + "OsTokenFlashLoans": "0xCd5F3C1BA0342e1de907eEE09aeC52183ef5D99e", + "PriceFeed": "0xe8a222D887b468a71Ee8a27df4fa3b886A4B7BA1", + "RewardSplitterFactory": "0x80353898B72417AC5701a9809A9eF63F691BdE86", + "FoxVault": "0xE96aC18cFE5A7AF8FE1FE7Bc37FF110d88bc67fF", + "ValidatorsRegistry": "0x00000000219ab540356cBB839Cbe05303d7705Fa", + "LegacyPoolEscrow": "0x291Fa5849215847081B475450cBE5De46CfD4fAE", + "LegacyRewardToken": "0x75c57bd50A3EB7291Da3429956D3566E0153A38f", + "MerkleDistributor": "0xc61847d6fc1f64162ff9f1d06205d9c4cdb2f239" +} \ No newline at end of file diff --git a/deployments/mainnet.json b/deployments/mainnet.json new file mode 100644 index 00000000..7c029222 --- /dev/null +++ b/deployments/mainnet.json @@ -0,0 +1,26 @@ +{ + "VaultsRegistry": "0x3a0008a588772446f6e656133C2D5029CC4FC20E", + "Keeper": "0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5", + "DepositDataRegistry": "0x75AB6DdCe07556639333d3Df1eaa684F5735223e", + "ValidatorsChecker": "0xaC9125646185Cb58e86E77d5f402eFa3fAfAFc84", + "GenesisVault": "0xAC0F906E433d58FA868F936E8A43230473652885", + "FoxVault": "0x4FEF9D741011476750A243aC70b9789a63dd47Df", + "VaultFactory": "0xDF82E5D27E175618e5bC4581ee336F59AdabfBB2", + "PrivVaultFactory": "0x80fC05f62C35C1b1361bc8908ea0aF06C510D390", + "BlocklistVaultFactory": "0x8b6c2C9E09c6022780D164F3cFd882808b8bDBF0", + "Erc20VaultFactory": "0x978302cAcAdEDE5d503390E176e86F3889Df6Ce6", + "PrivErc20VaultFactory": "0x291Fa5849215847081B475450cBE5De46CfD4fAE", + "BlocklistErc20VaultFactory": "0xe487EDDB7C5802e416385544f0A6a4426AF4AE87", + "SharedMevEscrow": "0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86", + "OsToken": "0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38", + "OsTokenConfig": "0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59", + "OsTokenVaultController": "0x2A261e60FB14586B474C208b1B7AC6D0f5000306", + "OsTokenVaultEscrow": "0x09e84205DF7c68907e619D07aFD90143c5763605", + "OsTokenFlashLoans": "0xeBe12d858E55DDc5FC5A8153dC3e117824fbf5d2", + "PriceFeed": "0x8023518b2192FB5384DAdc596765B3dD1cdFe471", + "RewardSplitterFactory": "0x256aF27ce81282A0491A5361172c1Db08f6cC5F8", + "ValidatorsRegistry": "0x00000000219ab540356cBB839Cbe05303d7705Fa", + "LegacyPoolEscrow": "0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079", + "LegacyRewardToken": "0x20BC832ca081b91433ff6c17f85701B6e92486c5", + "MerkleDistributor": "0xa9dc250dF4EE9273D09CFa455da41FB1cAC78d34" +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index d7a0f23b..87995134 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,5 +1,6 @@ [profile.default] src = 'contracts' +fs_permissions = [{ access = "read-write", path = "./deployments"}] solc = "0.8.26" evm_version = "cancun" optimizer = true @@ -10,3 +11,15 @@ bytecode_hash = 'none' [profile.test] via_ir = false + +[rpc_endpoints] +mainnet = "${MAINNET_RPC_URL}" +hoodi = "${HOODI_RPC_URL}" +chiado = "${CHIADO_RPC_URL}" +gnosis = "${GNOSIS_RPC_URL}" + +[etherscan] +mainnet = { key = "${ETHERSCAN_API_KEY}" } +hoodi = { key = "${ETHERSCAN_API_KEY}", chain = 560048, url = "https://api-hoodi.etherscan.io/api" } +chiado = { key = "${GNOSISSCAN_API_KEY}" } +gnosis = { key = "${GNOSISSCAN_API_KEY}" } diff --git a/script/ExecuteGovernorTxs.s.sol b/script/ExecuteGovernorTxs.s.sol new file mode 100644 index 00000000..7d2803eb --- /dev/null +++ b/script/ExecuteGovernorTxs.s.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {console} from "forge-std/console.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {Network} from "./Network.sol"; + +contract ExecuteGovernorTxs is Network { + using stdJson for string; + + struct Transaction { + bytes data; + string method; + } + + function run() public { + // Read and parse the JSON file + string memory jsonString = vm.readFile(getGovernorTxsFilePath()); + console.log("JSON file loaded successfully"); + + // Parse and extract transactions manually + bytes memory transactionsRaw = jsonString.parseRaw(".transactions"); + Transaction[] memory transactions = abi.decode(transactionsRaw, (Transaction[])); + + uint256 txCount = transactions.length; + console.log("Found %d transactions to execute", txCount); + + // Start broadcast with private key from environment variable + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address sender = vm.addr(privateKey); + console.log("Executing transactions from address: %s", sender); + + Deployment memory deployment = getDeploymentData(); + + vm.startBroadcast(privateKey); + + // Execute each transaction + for (uint256 i = 0; i < txCount; i++) { + Transaction memory transaction = transactions[i]; + + console.log("Executing tx %d: %s", i, transaction.method); + + // Execute the transaction + Address.functionCall(deployment.vaultsRegistry, transaction.data); + } + + vm.stopBroadcast(); + console.log("All transactions processed"); + } +} diff --git a/script/Network.sol b/script/Network.sol index 9286b21c..c2dcc24f 100644 --- a/script/Network.sol +++ b/script/Network.sol @@ -1,12 +1,21 @@ // SPDX-License-Identifier: BUSL-1.1 + pragma solidity ^0.8.22; +import {Script} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; +import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; + /** * @title Network * @author StakeWise - * @notice Solidity library containing constants for the StakeWise protocol + * @notice Contains utils for network constants */ -library Network { +abstract contract Network is Script { + using stdJson for string; + uint256 internal constant MAINNET = 1; uint256 internal constant HOODI = 560048; uint256 internal constant CHIADO = 10200; @@ -18,137 +27,265 @@ library Network { address internal constant VALIDATORS_WITHDRAWALS = 0x00000961Ef480Eb55e80D19ad83579A64c007002; address internal constant VALIDATORS_CONSOLIDATIONS = 0x0000BBdDc7CE488642fb579F8B00f3a590007251; - // MAINNET - address internal constant MAINNET_KEEPER = 0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5; - address internal constant MAINNET_VAULTS_REGISTRY = 0x3a0008a588772446f6e656133C2D5029CC4FC20E; - address internal constant MAINNET_VALIDATORS_REGISTRY = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address internal constant MAINNET_OS_TOKEN_VAULT_CONTROLLER = 0x2A261e60FB14586B474C208b1B7AC6D0f5000306; - address internal constant MAINNET_OS_TOKEN_CONFIG = 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59; - address internal constant MAINNET_OS_TOKEN_VAULT_ESCROW = 0x09e84205DF7c68907e619D07aFD90143c5763605; - address internal constant MAINNET_SHARED_MEV_ESCROW = 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86; - address internal constant MAINNET_DEPOSIT_DATA_REGISTRY = 0x75AB6DdCe07556639333d3Df1eaa684F5735223e; - address internal constant MAINNET_LEGACY_POOL_ESCROW = 0x2296e122c1a20Fca3CAc3371357BdAd3be0dF079; - address internal constant MAINNET_LEGACY_REWARD_TOKEN = 0x20BC832ca081b91433ff6c17f85701B6e92486c5; - - // HOODI - address internal constant HOODI_KEEPER = 0xA7D1Ac9D6F32B404C75626874BA56f7654c1dC0f; - address internal constant HOODI_VAULTS_REGISTRY = 0xf16fea93D3253A401C3f73B0De890C6586740B25; - address internal constant HOODI_VALIDATORS_REGISTRY = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address internal constant HOODI_OS_TOKEN_VAULT_CONTROLLER = 0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1; - address internal constant HOODI_OS_TOKEN_CONFIG = 0x5b817621EBE00622b9a71b53c942b392751c8197; - address internal constant HOODI_OS_TOKEN_VAULT_ESCROW = 0xdC1347cC04d4a8945b98A09C3c5585286bbA5C2B; - address internal constant HOODI_SHARED_MEV_ESCROW = 0x51FD45BAEfB12f54766B5C4d639b360Ea50063bd; - address internal constant HOODI_DEPOSIT_DATA_REGISTRY = 0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487; - address internal constant HOODI_LEGACY_POOL_ESCROW = 0x291Fa5849215847081B475450cBE5De46CfD4fAE; - address internal constant HOODI_LEGACY_REWARD_TOKEN = 0x75c57bd50A3EB7291Da3429956D3566E0153A38f; - - // GNOSIS - address internal constant GNOSIS_KEEPER = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; - address internal constant GNOSIS_VAULTS_REGISTRY = 0x7d014B3C6ee446563d4e0cB6fBD8C3D0419867cB; - address internal constant GNOSIS_VALIDATORS_REGISTRY = 0x0B98057eA310F4d31F2a452B414647007d1645d9; - address internal constant GNOSIS_OS_TOKEN_VAULT_CONTROLLER = 0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a; - address internal constant GNOSIS_OS_TOKEN_CONFIG = 0xd6672fbE1D28877db598DC0ac2559A15745FC3ec; - address internal constant GNOSIS_OS_TOKEN_VAULT_ESCROW = 0x28F325dD287a5984B754d34CfCA38af3A8429e71; - address internal constant GNOSIS_SHARED_MEV_ESCROW = 0x30db0d10d3774e78f8cB214b9e8B72D4B402488a; - address internal constant GNOSIS_DEPOSIT_DATA_REGISTRY = 0x58e16621B5c0786D6667D2d54E28A20940269E16; - address internal constant GNOSIS_LEGACY_POOL_ESCROW = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; - address internal constant GNOSIS_LEGACY_REWARD_TOKEN = 0x6aC78efae880282396a335CA2F79863A1e6831D4; - - // CHIADO - address internal constant CHIADO_KEEPER = 0x5f31eD13eBF81B67a9f9498F3d1D2Da553058988; - address internal constant CHIADO_VAULTS_REGISTRY = 0x8750594B33516232e751C8B9C350a660cD5f1BB8; - address internal constant CHIADO_VALIDATORS_REGISTRY = 0xb97036A26259B7147018913bD58a774cf91acf25; - address internal constant CHIADO_OS_TOKEN_VAULT_CONTROLLER = 0x5518052f2d898f062ee59964004A560F24E2eE7d; - address internal constant CHIADO_OS_TOKEN_CONFIG = 0x6D5957e075fd93b3B9F36Da93d7462F14387706d; - address internal constant CHIADO_OS_TOKEN_VAULT_ESCROW = 0x00aa8A78d88a9865b5b0F4ce50c3bB018c93FBa7; - address internal constant CHIADO_SHARED_MEV_ESCROW = 0x453056f0bc4631abB15eEC656139f88067668E3E; - address internal constant CHIADO_DEPOSIT_DATA_REGISTRY = 0xFAce8504462AEb9BB6ae7Ecb206BD7B1EdF7956D; - address internal constant CHIADO_LEGACY_POOL_ESCROW = 0x928F9a91E674C886Cae0c377670109aBeF7e19d6; - address internal constant CHIADO_LEGACY_REWARD_TOKEN = 0x14c74b1C7eCa8362D4ABcCd71051Ce174d61a3D4; - - struct Constants { + struct Deployment { address keeper; address vaultsRegistry; - address validatorsRegistry; - address validatorsWithdrawals; - address validatorsConsolidations; - address osTokenVaultController; + address depositDataRegistry; + address genesisVault; + address foxVault; + address vaultFactory; + address privVaultFactory; + address blocklistVaultFactory; + address erc20VaultFactory; + address privErc20VaultFactory; + address blocklistErc20VaultFactory; + address sharedMevEscrow; + address osToken; address osTokenConfig; + address osTokenVaultController; address osTokenVaultEscrow; - address sharedMevEscrow; - address depositDataRegistry; + address osTokenFlashLoans; + address priceFeed; + address validatorsRegistry; address legacyPoolEscrow; address legacyRewardToken; - uint64 exitedAssetsClaimDelay; + address merkleDistributor; + address gnoToken; + address sDaiToken; + address savingsXDaiAdapter; + } + + struct Factory { + string name; + address factory; } - function getNetworkConstants(uint256 chainId) internal pure returns (Constants memory) { + Deployment private _deployment; + string[] private _governorCalls; + + function getNetworkName() internal view returns (string memory) { + uint256 chainId = block.chainid; if (chainId == MAINNET) { - return Constants({ - keeper: MAINNET_KEEPER, - vaultsRegistry: MAINNET_VAULTS_REGISTRY, - validatorsRegistry: MAINNET_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: MAINNET_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: MAINNET_OS_TOKEN_CONFIG, - osTokenVaultEscrow: MAINNET_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: MAINNET_SHARED_MEV_ESCROW, - depositDataRegistry: MAINNET_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: MAINNET_LEGACY_POOL_ESCROW, - legacyRewardToken: MAINNET_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); + return "mainnet"; } else if (chainId == HOODI) { - return Constants({ - keeper: HOODI_KEEPER, - vaultsRegistry: HOODI_VAULTS_REGISTRY, - validatorsRegistry: HOODI_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: HOODI_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: HOODI_OS_TOKEN_CONFIG, - osTokenVaultEscrow: HOODI_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: HOODI_SHARED_MEV_ESCROW, - depositDataRegistry: HOODI_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: HOODI_LEGACY_POOL_ESCROW, - legacyRewardToken: HOODI_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); + return "hoodi"; } else if (chainId == GNOSIS) { - return Constants({ - keeper: GNOSIS_KEEPER, - vaultsRegistry: GNOSIS_VAULTS_REGISTRY, - validatorsRegistry: GNOSIS_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: GNOSIS_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: GNOSIS_OS_TOKEN_CONFIG, - osTokenVaultEscrow: GNOSIS_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: GNOSIS_SHARED_MEV_ESCROW, - depositDataRegistry: GNOSIS_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: GNOSIS_LEGACY_POOL_ESCROW, - legacyRewardToken: GNOSIS_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); + return "gnosis"; } else if (chainId == CHIADO) { - return Constants({ - keeper: CHIADO_KEEPER, - vaultsRegistry: CHIADO_VAULTS_REGISTRY, - validatorsRegistry: CHIADO_VALIDATORS_REGISTRY, - validatorsWithdrawals: VALIDATORS_WITHDRAWALS, - validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, - osTokenVaultController: CHIADO_OS_TOKEN_VAULT_CONTROLLER, - osTokenConfig: CHIADO_OS_TOKEN_CONFIG, - osTokenVaultEscrow: CHIADO_OS_TOKEN_VAULT_ESCROW, - sharedMevEscrow: CHIADO_SHARED_MEV_ESCROW, - depositDataRegistry: CHIADO_DEPOSIT_DATA_REGISTRY, - legacyPoolEscrow: CHIADO_LEGACY_POOL_ESCROW, - legacyRewardToken: CHIADO_LEGACY_REWARD_TOKEN, - exitedAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY - }); + return "chiado"; } else { revert("Unsupported chain ID"); } } + + function isGnosisNetwork() internal view returns (bool) { + return block.chainid == GNOSIS || block.chainid == CHIADO; + } + + function getDeploymentFilePath() internal view returns (string memory) { + string memory networkName = getNetworkName(); + return string.concat("./deployments/", networkName, ".json"); + } + + function getGovernorTxsFilePath() internal view returns (string memory) { + string memory networkName = getNetworkName(); + return string.concat("./deployments/", networkName, "-governor-txs.json"); + } + + function getUpgradesFilePath() internal view returns (string memory) { + string memory networkName = getNetworkName(); + return string.concat("./deployments/", networkName, "-vault-upgrades.json"); + } + + function getDeploymentData() internal returns (Deployment memory) { + Deployment memory deployment = _deployment; + if (deployment.keeper != address(0)) { + return deployment; + } + string memory deploymentData = vm.readFile(getDeploymentFilePath()); + deployment.vaultsRegistry = deploymentData.readAddress(".VaultsRegistry"); + deployment.keeper = deploymentData.readAddress(".Keeper"); + deployment.depositDataRegistry = deploymentData.readAddress(".DepositDataRegistry"); + deployment.genesisVault = deploymentData.readAddress(".GenesisVault"); + deployment.vaultFactory = deploymentData.readAddress(".VaultFactory"); + deployment.privVaultFactory = deploymentData.readAddress(".PrivVaultFactory"); + deployment.blocklistVaultFactory = deploymentData.readAddress(".BlocklistVaultFactory"); + deployment.erc20VaultFactory = deploymentData.readAddress(".Erc20VaultFactory"); + deployment.privErc20VaultFactory = deploymentData.readAddress(".PrivErc20VaultFactory"); + deployment.blocklistErc20VaultFactory = deploymentData.readAddress(".BlocklistErc20VaultFactory"); + deployment.sharedMevEscrow = deploymentData.readAddress(".SharedMevEscrow"); + deployment.osToken = deploymentData.readAddress(".OsToken"); + deployment.osTokenConfig = deploymentData.readAddress(".OsTokenConfig"); + deployment.osTokenVaultController = deploymentData.readAddress(".OsTokenVaultController"); + deployment.osTokenVaultEscrow = deploymentData.readAddress(".OsTokenVaultEscrow"); + deployment.osTokenFlashLoans = deploymentData.readAddress(".OsTokenFlashLoans"); + deployment.priceFeed = deploymentData.readAddress(".PriceFeed"); + deployment.validatorsRegistry = deploymentData.readAddress(".ValidatorsRegistry"); + deployment.legacyPoolEscrow = deploymentData.readAddress(".LegacyPoolEscrow"); + deployment.legacyRewardToken = deploymentData.readAddress(".LegacyRewardToken"); + deployment.merkleDistributor = deploymentData.readAddress(".MerkleDistributor"); + + bool isGnosis = isGnosisNetwork(); + if (isGnosis) { + deployment.gnoToken = deploymentData.readAddress(".GnoToken"); + deployment.sDaiToken = deploymentData.readAddress(".SDaiToken"); + deployment.savingsXDaiAdapter = deploymentData.readAddress(".SavingsXDaiAdapter"); + deployment.foxVault = address(0); + } else { + deployment.gnoToken = address(0); + deployment.sDaiToken = address(0); + deployment.savingsXDaiAdapter = address(0); + deployment.foxVault = deploymentData.readAddress(".FoxVault"); + } + _deployment = deployment; + return deployment; + } + + function generateGovernorTxJson(address[] memory vaultImpls, Factory[] memory vaultFactories) internal { + if (_governorCalls.length > 0) { + return; + } + + bool removePrevVaultFactories = vm.envBool("REMOVE_PREV_FACTORIES"); + + for (uint256 i = 0; i < vaultImpls.length; i++) { + _governorCalls.push(_serializeAddVaultImpl(vaultImpls[i])); + } + + for (uint256 i = 0; i < vaultFactories.length; i++) { + _governorCalls.push(_serializeAddFactory(vaultFactories[i].factory)); + } + + if (removePrevVaultFactories) { + Deployment memory deployment = getDeploymentData(); + _governorCalls.push(_serializeRemoveFactory(deployment.vaultFactory)); + _governorCalls.push(_serializeRemoveFactory(deployment.privVaultFactory)); + _governorCalls.push(_serializeRemoveFactory(deployment.blocklistVaultFactory)); + _governorCalls.push(_serializeRemoveFactory(deployment.erc20VaultFactory)); + _governorCalls.push(_serializeRemoveFactory(deployment.privErc20VaultFactory)); + _governorCalls.push(_serializeRemoveFactory(deployment.blocklistErc20VaultFactory)); + } + + string memory output = vm.serializeString("governorCalls", "transactions", _governorCalls); + string memory filePath = getGovernorTxsFilePath(); + vm.writeJson(output, filePath); + } + + function generateUpgradesJson(address[] memory vaultImpls) internal { + string memory upgrades = "upgrades"; + + string memory output; + for (uint256 i = 0; i < vaultImpls.length; i++) { + address vaultImpl = vaultImpls[i]; + bytes32 vaultId = IVaultVersion(vaultImpl).vaultId(); + uint8 version = IVaultVersion(vaultImpl).version(); + + string memory object = vm.serializeAddress(Strings.toString(i), Strings.toString(version), vaultImpl); + output = vm.serializeString(upgrades, Strings.toHexString(uint256(vaultId)), object); + } + vm.writeJson(output, getUpgradesFilePath()); + } + + function generateAddressesJson( + Factory[] memory newFactories, + address validatorsChecker, + address consolidationsChecker, + address rewardSplitterFactory, + address gnoDaiDistributor + ) internal { + Deployment memory deployment = getDeploymentData(); + + string memory json = "addresses"; + vm.serializeAddress(json, "VaultsRegistry", deployment.vaultsRegistry); + vm.serializeAddress(json, "Keeper", deployment.keeper); + vm.serializeAddress(json, "DepositDataRegistry", deployment.depositDataRegistry); + vm.serializeAddress(json, "GenesisVault", deployment.genesisVault); + vm.serializeAddress(json, "SharedMevEscrow", deployment.sharedMevEscrow); + vm.serializeAddress(json, "OsToken", deployment.osToken); + vm.serializeAddress(json, "OsTokenConfig", deployment.osTokenConfig); + vm.serializeAddress(json, "OsTokenVaultController", deployment.osTokenVaultController); + vm.serializeAddress(json, "OsTokenVaultEscrow", deployment.osTokenVaultEscrow); + vm.serializeAddress(json, "OsTokenFlashLoans", deployment.osTokenFlashLoans); + vm.serializeAddress(json, "PriceFeed", deployment.priceFeed); + vm.serializeAddress(json, "ValidatorsRegistry", deployment.validatorsRegistry); + vm.serializeAddress(json, "LegacyPoolEscrow", deployment.legacyPoolEscrow); + vm.serializeAddress(json, "LegacyRewardToken", deployment.legacyRewardToken); + vm.serializeAddress(json, "MerkleDistributor", deployment.merkleDistributor); + + for (uint256 i = 0; i < newFactories.length; i++) { + Factory memory factory = newFactories[i]; + vm.serializeAddress(json, factory.name, factory.factory); + } + + bool isGnosis = isGnosisNetwork(); + if (isGnosis) { + vm.serializeAddress(json, "GnoToken", deployment.gnoToken); + vm.serializeAddress(json, "SDaiToken", deployment.sDaiToken); + vm.serializeAddress(json, "SavingsXDaiAdapter", deployment.savingsXDaiAdapter); + vm.serializeAddress(json, "GnoDaiDistributor", gnoDaiDistributor); + } else { + vm.serializeAddress(json, "FoxVault", deployment.foxVault); + } + + vm.serializeAddress(json, "ValidatorsChecker", validatorsChecker); + vm.serializeAddress(json, "ConsolidationsChecker", consolidationsChecker); + string memory output = vm.serializeAddress(json, "RewardSplitterFactory", rewardSplitterFactory); + + string memory path = string.concat("./deployments/", getNetworkName(), "-new.json"); + vm.writeJson(output, path); + } + + function _serializeAddVaultImpl(address vaultImpl) private returns (string memory) { + string memory object = "addVaultImpl"; + Deployment memory deployment = getDeploymentData(); + vm.serializeAddress(object, "to", deployment.vaultsRegistry); + vm.serializeString(object, "operation", "0"); + vm.serializeString(object, "method", "addVaultImpl(address)"); + vm.serializeString(object, "value", "0.0"); + vm.serializeBytes( + object, + "data", + abi.encodeWithSelector(IVaultsRegistry(deployment.vaultsRegistry).addVaultImpl.selector, vaultImpl) + ); + + address[] memory params = new address[](1); + params[0] = vaultImpl; + return vm.serializeAddress(object, "params", params); + } + + function _serializeAddFactory(address factory) private returns (string memory) { + string memory object = "addFactory"; + Deployment memory deployment = getDeploymentData(); + vm.serializeAddress(object, "to", deployment.vaultsRegistry); + vm.serializeString(object, "operation", "0"); + vm.serializeString(object, "method", "addFactory(address)"); + vm.serializeString(object, "value", "0.0"); + vm.serializeBytes( + object, + "data", + abi.encodeWithSelector(IVaultsRegistry(deployment.vaultsRegistry).addFactory.selector, factory) + ); + + address[] memory params = new address[](1); + params[0] = factory; + return vm.serializeAddress(object, "params", params); + } + + function _serializeRemoveFactory(address factory) private returns (string memory) { + string memory object = "removeFactory"; + Deployment memory deployment = getDeploymentData(); + vm.serializeAddress(object, "to", deployment.vaultsRegistry); + vm.serializeString(object, "operation", "0"); + vm.serializeString(object, "method", "removeFactory(address)"); + vm.serializeString(object, "value", "0.0"); + vm.serializeBytes( + object, + "data", + abi.encodeWithSelector(IVaultsRegistry(deployment.vaultsRegistry).removeFactory.selector, factory) + ); + + address[] memory params = new address[](1); + params[0] = factory; + return vm.serializeAddress(object, "params", params); + } } diff --git a/script/UpgradeEthNetwork.s.sol b/script/UpgradeEthNetwork.s.sol index cf4f6d7a..045e79c6 100644 --- a/script/UpgradeEthNetwork.s.sol +++ b/script/UpgradeEthNetwork.s.sol @@ -1,9 +1,8 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: BUSL-1.1 + pragma solidity ^0.8.22; -import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; @@ -17,42 +16,66 @@ import {EthPrivErc20Vault} from "../contracts/vaults/ethereum/EthPrivErc20Vault. import {EthPrivVault} from "../contracts/vaults/ethereum/EthPrivVault.sol"; import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; import {EthVaultFactory} from "../contracts/vaults/ethereum/EthVaultFactory.sol"; +import {EthValidatorsChecker} from "../contracts/validators/EthValidatorsChecker.sol"; +import {EthRewardSplitter} from "../contracts/misc/EthRewardSplitter.sol"; +import {RewardSplitterFactory} from "../contracts/misc/RewardSplitterFactory.sol"; import {Network} from "./Network.sol"; -contract UpgradeEthNetwork is Script { - Network.Constants public constants; +contract UpgradeEthNetwork is Network { address public consolidationsChecker; + address public validatorsChecker; + address public rewardSplitterFactory; + address[] public vaultImpls; - address[] public vaultFactories; + Factory[] public vaultFactories; function run() external { - vm.startBroadcast(vm.envUint("PRIVATE_KEY")); - console.log("Deploying from: ", msg.sender); - - constants = Network.getNetworkConstants(block.chainid); - - // Deploy consolidations checker - consolidationsChecker = address(new ConsolidationsChecker(constants.keeper)); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address sender = vm.addr(privateKey); + console.log("Deploying from: ", sender); + + vm.startBroadcast(privateKey); + Deployment memory deployment = getDeploymentData(); + + // Deploy common contracts + consolidationsChecker = address(new ConsolidationsChecker(deployment.keeper)); + validatorsChecker = address( + new EthValidatorsChecker( + deployment.validatorsRegistry, + deployment.keeper, + deployment.vaultsRegistry, + deployment.depositDataRegistry + ) + ); + address rewardsSplitterImpl = address(new EthRewardSplitter()); + rewardSplitterFactory = address(new RewardSplitterFactory(rewardsSplitterImpl)); _deployImplementations(); _deployFactories(); - vm.stopBroadcast(); + + generateGovernorTxJson(vaultImpls, vaultFactories); + generateUpgradesJson(vaultImpls); + generateAddressesJson( + vaultFactories, validatorsChecker, consolidationsChecker, rewardSplitterFactory, address(0) + ); } function _deployImplementations() internal { // constructors for implementations IEthVault.EthVaultConstructorArgs memory vaultArgs = _getEthVaultConstructorArgs(); IEthErc20Vault.EthErc20VaultConstructorArgs memory erc20VaultArgs = _getEthErc20VaultConstructorArgs(); + Deployment memory deployment = getDeploymentData(); - // deploy genesis vault - vaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; - erc20VaultArgs.exitingAssetsClaimDelay = Network.PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + // update exited assets claim delay for public vaults + vaultArgs.exitingAssetsClaimDelay = PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + // deploy genesis vault EthGenesisVault ethGenesisVault = - new EthGenesisVault(vaultArgs, constants.legacyPoolEscrow, constants.legacyRewardToken); + new EthGenesisVault(vaultArgs, deployment.legacyPoolEscrow, deployment.legacyRewardToken); - // deploy normal vaults + // deploy public vaults EthVault ethVault = new EthVault(vaultArgs); EthErc20Vault ethErc20Vault = new EthErc20Vault(erc20VaultArgs); @@ -60,10 +83,11 @@ contract UpgradeEthNetwork is Script { EthBlocklistVault ethBlocklistVault = new EthBlocklistVault(vaultArgs); EthBlocklistErc20Vault ethBlocklistErc20Vault = new EthBlocklistErc20Vault(erc20VaultArgs); - // deploy private vaults // update exited assets claim delay for private vaults - vaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; - erc20VaultArgs.exitingAssetsClaimDelay = Network.PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + vaultArgs.exitingAssetsClaimDelay = PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + + // deploy private vaults EthPrivVault ethPrivVault = new EthPrivVault(vaultArgs); EthPrivErc20Vault ethPrivErc20Vault = new EthPrivErc20Vault(erc20VaultArgs); @@ -77,81 +101,66 @@ contract UpgradeEthNetwork is Script { } function _deployFactories() internal { + Deployment memory deployment = getDeploymentData(); for (uint256 i = 0; i < vaultImpls.length; i++) { address vaultImpl = vaultImpls[i]; - if (IVaultVersion(vaultImpl).vaultId() == keccak256("EthGenesisVault")) { + bytes32 vaultId = IVaultVersion(vaultImpl).vaultId(); + + // skip factory creation for EthGenesisVault or EthFoxVault + if (vaultId == keccak256("EthGenesisVault") || vaultId == keccak256("EthFoxVault")) { continue; } - EthVaultFactory factory = new EthVaultFactory(vaultImpl, IVaultsRegistry(constants.vaultsRegistry)); - vaultFactories.push(address(factory)); + + EthVaultFactory factory = new EthVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry)); + if (vaultId == keccak256("EthVault")) { + vaultFactories.push(Factory({name: "VaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("EthErc20Vault")) { + vaultFactories.push(Factory({name: "Erc20VaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("EthBlocklistVault")) { + vaultFactories.push(Factory({name: "BlocklistVaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("EthPrivVault")) { + vaultFactories.push(Factory({name: "PrivVaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("EthBlocklistErc20Vault")) { + vaultFactories.push(Factory({name: "BlocklistErc20VaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("EthPrivErc20Vault")) { + vaultFactories.push(Factory({name: "PrivErc20VaultFactory", factory: address(factory)})); + } } } - function _getEthVaultConstructorArgs() internal view returns (IEthVault.EthVaultConstructorArgs memory) { + function _getEthVaultConstructorArgs() internal returns (IEthVault.EthVaultConstructorArgs memory) { + Deployment memory deployment = getDeploymentData(); return IEthVault.EthVaultConstructorArgs({ - keeper: constants.keeper, - vaultsRegistry: constants.vaultsRegistry, - validatorsRegistry: constants.validatorsRegistry, - validatorsWithdrawals: constants.validatorsWithdrawals, - validatorsConsolidations: constants.validatorsConsolidations, + keeper: deployment.keeper, + vaultsRegistry: deployment.vaultsRegistry, + validatorsRegistry: deployment.validatorsRegistry, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, consolidationsChecker: consolidationsChecker, - osTokenVaultController: constants.osTokenVaultController, - osTokenConfig: constants.osTokenConfig, - osTokenVaultEscrow: constants.osTokenVaultEscrow, - sharedMevEscrow: constants.sharedMevEscrow, - depositDataRegistry: constants.depositDataRegistry, - exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay + osTokenVaultController: deployment.osTokenVaultController, + osTokenConfig: deployment.osTokenConfig, + osTokenVaultEscrow: deployment.osTokenVaultEscrow, + sharedMevEscrow: deployment.sharedMevEscrow, + depositDataRegistry: deployment.depositDataRegistry, + exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } - function _getEthErc20VaultConstructorArgs() - internal - view - returns (IEthErc20Vault.EthErc20VaultConstructorArgs memory) - { + function _getEthErc20VaultConstructorArgs() internal returns (IEthErc20Vault.EthErc20VaultConstructorArgs memory) { + Deployment memory deployment = getDeploymentData(); return IEthErc20Vault.EthErc20VaultConstructorArgs({ - keeper: constants.keeper, - vaultsRegistry: constants.vaultsRegistry, - validatorsRegistry: constants.validatorsRegistry, - validatorsWithdrawals: constants.validatorsWithdrawals, - validatorsConsolidations: constants.validatorsConsolidations, + keeper: deployment.keeper, + vaultsRegistry: deployment.vaultsRegistry, + validatorsRegistry: deployment.validatorsRegistry, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, consolidationsChecker: consolidationsChecker, - osTokenVaultController: constants.osTokenVaultController, - osTokenConfig: constants.osTokenConfig, - osTokenVaultEscrow: constants.osTokenVaultEscrow, - sharedMevEscrow: constants.sharedMevEscrow, - depositDataRegistry: constants.depositDataRegistry, - exitingAssetsClaimDelay: constants.exitedAssetsClaimDelay + osTokenVaultController: deployment.osTokenVaultController, + osTokenConfig: deployment.osTokenConfig, + osTokenVaultEscrow: deployment.osTokenVaultEscrow, + sharedMevEscrow: deployment.sharedMevEscrow, + depositDataRegistry: deployment.depositDataRegistry, + exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } - - function _generateGovernorTxJson() internal { - string[] memory objects = new string[](vaultImpls.length + vaultFactories.length); - for (uint256 i = 0; i < vaultImpls.length; i++) { - string memory object = Strings.toString(i); - vm.serializeAddress(object, "to", constants.vaultsRegistry); - vm.serializeString(object, "operation", "0"); - vm.serializeBytes( - object, - "data", - abi.encodeWithSelector(IVaultsRegistry(constants.vaultsRegistry).addVaultImpl.selector, vaultImpls[i]) - ); - objects[i] = vm.serializeString(object, "value", "0.0"); - } - - for (uint256 i = 0; i < vaultFactories.length; i++) { - string memory object = Strings.toString(vaultImpls.length + i); - vm.serializeAddress(object, "to", constants.vaultsRegistry); - vm.serializeString(object, "operation", "0"); - vm.serializeBytes( - object, - "data", - abi.encodeWithSelector(IVaultsRegistry(constants.vaultsRegistry).addFactory.selector, vaultFactories[i]) - ); - objects[vaultImpls.length + i] = vm.serializeString(object, "value", "0.0"); - } - string memory json = "json"; - string memory output = vm.serializeString(json, "transactions", objects); - vm.writeJson(output, "./output/example.json"); - } } diff --git a/script/UpgradeGnoNetwork.s.sol b/script/UpgradeGnoNetwork.s.sol new file mode 100644 index 00000000..6cfa4643 --- /dev/null +++ b/script/UpgradeGnoNetwork.s.sol @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {console} from "forge-std/console.sol"; +import {IGnoVault} from "../contracts/interfaces/IGnoVault.sol"; +import {IGnoErc20Vault} from "../contracts/interfaces/IGnoErc20Vault.sol"; +import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; +import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; +import {ConsolidationsChecker} from "../contracts/validators/ConsolidationsChecker.sol"; +import {GnoValidatorsChecker} from "../contracts/validators/GnoValidatorsChecker.sol"; +import {GnoRewardSplitter} from "../contracts/misc/GnoRewardSplitter.sol"; +import {GnoDaiDistributor} from "../contracts/misc/GnoDaiDistributor.sol"; +import {RewardSplitterFactory} from "../contracts/misc/RewardSplitterFactory.sol"; +import {GnoGenesisVault} from "../contracts/vaults/gnosis/GnoGenesisVault.sol"; +import {GnoVault} from "../contracts/vaults/gnosis/GnoVault.sol"; +import {GnoErc20Vault} from "../contracts/vaults/gnosis/GnoErc20Vault.sol"; +import {GnoBlocklistVault} from "../contracts/vaults/gnosis/GnoBlocklistVault.sol"; +import {GnoBlocklistErc20Vault} from "../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol"; +import {GnoPrivVault} from "../contracts/vaults/gnosis/GnoPrivVault.sol"; +import {GnoPrivErc20Vault} from "../contracts/vaults/gnosis/GnoPrivErc20Vault.sol"; +import {GnoVaultFactory} from "../contracts/vaults/gnosis/GnoVaultFactory.sol"; +import {Network} from "./Network.sol"; + +contract UpgradeGnoNetwork is Network { + address public consolidationsChecker; + address public validatorsChecker; + address public rewardSplitterFactory; + address public gnoDaiDistributor; + + address[] public vaultImpls; + Factory[] public vaultFactories; + + function run() external { + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address sender = vm.addr(privateKey); + console.log("Deploying from: ", sender); + + vm.startBroadcast(privateKey); + Deployment memory deployment = getDeploymentData(); + + // Deploy common contracts + consolidationsChecker = address(new ConsolidationsChecker(deployment.keeper)); + validatorsChecker = address( + new GnoValidatorsChecker( + deployment.validatorsRegistry, + deployment.keeper, + deployment.vaultsRegistry, + deployment.depositDataRegistry, + deployment.gnoToken + ) + ); + address rewardsSplitterImpl = address(new GnoRewardSplitter(deployment.gnoToken)); + rewardSplitterFactory = address(new RewardSplitterFactory(rewardsSplitterImpl)); + gnoDaiDistributor = address( + new GnoDaiDistributor( + deployment.sDaiToken, + deployment.vaultsRegistry, + deployment.savingsXDaiAdapter, + deployment.merkleDistributor + ) + ); + + _deployImplementations(); + _deployFactories(); + vm.stopBroadcast(); + + generateGovernorTxJson(vaultImpls, vaultFactories); + generateUpgradesJson(vaultImpls); + generateAddressesJson( + vaultFactories, validatorsChecker, consolidationsChecker, rewardSplitterFactory, gnoDaiDistributor + ); + } + + function _deployImplementations() internal { + // constructors for implementations + IGnoVault.GnoVaultConstructorArgs memory vaultArgs = _getGnoVaultConstructorArgs(); + IGnoErc20Vault.GnoErc20VaultConstructorArgs memory erc20VaultArgs = _getGnoErc20VaultConstructorArgs(); + Deployment memory deployment = getDeploymentData(); + + // update exited assets claim delay for public vaults + vaultArgs.exitingAssetsClaimDelay = PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY; + + // deploy genesis vault + GnoGenesisVault gnoGenesisVault = + new GnoGenesisVault(vaultArgs, deployment.legacyPoolEscrow, deployment.legacyRewardToken); + + // deploy public vaults + GnoVault gnoVault = new GnoVault(vaultArgs); + GnoErc20Vault gnoErc20Vault = new GnoErc20Vault(erc20VaultArgs); + + // deploy blocklist vaults + GnoBlocklistVault gnoBlocklistVault = new GnoBlocklistVault(vaultArgs); + GnoBlocklistErc20Vault gnoBlocklistErc20Vault = new GnoBlocklistErc20Vault(erc20VaultArgs); + + // update exited assets claim delay for private vaults + vaultArgs.exitingAssetsClaimDelay = PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + erc20VaultArgs.exitingAssetsClaimDelay = PRIVATE_VAULT_EXITED_ASSETS_CLAIM_DELAY; + + // deploy private vaults + GnoPrivVault gnoPrivVault = new GnoPrivVault(vaultArgs); + GnoPrivErc20Vault gnoPrivErc20Vault = new GnoPrivErc20Vault(erc20VaultArgs); + + vaultImpls.push(address(gnoGenesisVault)); + vaultImpls.push(address(gnoVault)); + vaultImpls.push(address(gnoErc20Vault)); + vaultImpls.push(address(gnoBlocklistVault)); + vaultImpls.push(address(gnoBlocklistErc20Vault)); + vaultImpls.push(address(gnoPrivVault)); + vaultImpls.push(address(gnoPrivErc20Vault)); + } + + function _deployFactories() internal { + Deployment memory deployment = getDeploymentData(); + for (uint256 i = 0; i < vaultImpls.length; i++) { + address vaultImpl = vaultImpls[i]; + bytes32 vaultId = IVaultVersion(vaultImpl).vaultId(); + + // skip factory creation for GnoGenesisVault + if (vaultId == keccak256("GnoGenesisVault")) { + continue; + } + + GnoVaultFactory factory = + new GnoVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry), deployment.gnoToken); + if (vaultId == keccak256("GnoVault")) { + vaultFactories.push(Factory({name: "VaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("GnoErc20Vault")) { + vaultFactories.push(Factory({name: "Erc20VaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("GnoBlocklistVault")) { + vaultFactories.push(Factory({name: "BlocklistVaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("GnoPrivVault")) { + vaultFactories.push(Factory({name: "PrivVaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("GnoBlocklistErc20Vault")) { + vaultFactories.push(Factory({name: "BlocklistErc20VaultFactory", factory: address(factory)})); + } else if (vaultId == keccak256("GnoPrivErc20Vault")) { + vaultFactories.push(Factory({name: "PrivErc20VaultFactory", factory: address(factory)})); + } + } + } + + function _getGnoVaultConstructorArgs() internal returns (IGnoVault.GnoVaultConstructorArgs memory) { + Deployment memory deployment = getDeploymentData(); + return IGnoVault.GnoVaultConstructorArgs({ + keeper: deployment.keeper, + vaultsRegistry: deployment.vaultsRegistry, + validatorsRegistry: deployment.validatorsRegistry, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + consolidationsChecker: consolidationsChecker, + osTokenVaultController: deployment.osTokenVaultController, + osTokenConfig: deployment.osTokenConfig, + osTokenVaultEscrow: deployment.osTokenVaultEscrow, + sharedMevEscrow: deployment.sharedMevEscrow, + depositDataRegistry: deployment.depositDataRegistry, + gnoToken: deployment.gnoToken, + gnoDaiDistributor: gnoDaiDistributor, + exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } + + function _getGnoErc20VaultConstructorArgs() internal returns (IGnoErc20Vault.GnoErc20VaultConstructorArgs memory) { + Deployment memory deployment = getDeploymentData(); + return IGnoErc20Vault.GnoErc20VaultConstructorArgs({ + keeper: deployment.keeper, + vaultsRegistry: deployment.vaultsRegistry, + validatorsRegistry: deployment.validatorsRegistry, + validatorsWithdrawals: VALIDATORS_WITHDRAWALS, + validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, + consolidationsChecker: consolidationsChecker, + osTokenVaultController: deployment.osTokenVaultController, + osTokenConfig: deployment.osTokenConfig, + osTokenVaultEscrow: deployment.osTokenVaultEscrow, + sharedMevEscrow: deployment.sharedMevEscrow, + depositDataRegistry: deployment.depositDataRegistry, + gnoToken: deployment.gnoToken, + gnoDaiDistributor: gnoDaiDistributor, + exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } +} diff --git a/test/helpers/EthHelpers.sol b/test/helpers/EthHelpers.sol index e231e6f5..0cbf5ca3 100644 --- a/test/helpers/EthHelpers.sol +++ b/test/helpers/EthHelpers.sol @@ -212,12 +212,12 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { } function _startSnapshotGas(string memory label) internal { - if (vm.envBool("SKIP_SNAPSHOTS")) return; + if (vm.envBool("TEST_SKIP_SNAPSHOTS")) return; return vm.startSnapshotGas(label); } function _stopSnapshotGas() internal { - if (vm.envBool("SKIP_SNAPSHOTS")) return; + if (vm.envBool("TEST_SKIP_SNAPSHOTS")) return; vm.stopSnapshotGas(); } @@ -228,7 +228,7 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { return 0x4FEF9D741011476750A243aC70b9789a63dd47Df; } - if (!vm.envBool("USE_FORK_VAULTS")) return address(0); + if (!vm.envBool("TEST_USE_FORK_VAULTS")) return address(0); // Update with actual deployed vault addresses for each type if (vaultType == VaultType.EthVault) { @@ -259,7 +259,7 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { newTotalReward += 242948554351000000000; } - if (!vm.envBool("USE_FORK_VAULTS")) { + if (!vm.envBool("TEST_USE_FORK_VAULTS")) { return (newTotalReward, newUnlockedMevReward); } diff --git a/test/helpers/GnoHelpers.sol b/test/helpers/GnoHelpers.sol index cbbd57ca..e9890943 100644 --- a/test/helpers/GnoHelpers.sol +++ b/test/helpers/GnoHelpers.sol @@ -247,12 +247,12 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { } function _startSnapshotGas(string memory label) internal { - if (vm.envBool("SKIP_SNAPSHOTS")) return; + if (vm.envBool("TEST_SKIP_SNAPSHOTS")) return; return vm.startSnapshotGas(label); } function _stopSnapshotGas() internal { - if (vm.envBool("SKIP_SNAPSHOTS")) return; + if (vm.envBool("TEST_SKIP_SNAPSHOTS")) return; vm.stopSnapshotGas(); } @@ -261,7 +261,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { return 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a; } - if (!vm.envBool("USE_FORK_VAULTS")) return address(0); + if (!vm.envBool("TEST_USE_FORK_VAULTS")) return address(0); if (vaultType == VaultType.GnoVault) { return 0x00025C729A3364FaEf02c7D1F577068d87E90ba6; @@ -287,7 +287,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { newUnlockedMevReward += 12291679027502580216003; } - if (!vm.envBool("USE_FORK_VAULTS")) { + if (!vm.envBool("TEST_USE_FORK_VAULTS")) { return (newTotalReward, newUnlockedMevReward); } From abbf933c0e70ef00688c6b160d589c99093761bc Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Thu, 15 May 2025 12:17:23 +0300 Subject: [PATCH 13/15] Implement Meta vaults (#113) * Implement Meta vaults * Implement Meta vaults for gnosis * Update MetaVault, add tests * Add test functions interfaces for add subvaults * Add tests for adding new sub vault * Remove vault impl check * Add reject vault tests, fix BalancedCurator * Add deposit to vaults tests for SubVaults * Total assets delta with ejecting vault * Add tests for VaultSubVaults update state * Add claim exited assets tests to VaultSubVaults module * Add EthMetaVaultTest tests * Add MetaVault to GnoHelpers * Update BalancedCurator * Implement meta vault factories * Add zero address admin test * Update snapshots * Fix snapshots * Remove zero check for _checkHarvested in VaultSubVaults module * Fix snapshots * Add donateAssets function * Add donateAssets tests * Remove redundant submodule * Remove oz upgradeable dep * Add oz upgradeable dep * Update snapshots * Remove version check for the sub vault --- .env.example | 15 +- .gitmodules | 3 - contracts/curators/BalancedCurator.sol | 97 ++ contracts/curators/CuratorsRegistry.sol | 46 + contracts/interfaces/ICuratorsRegistry.sol | 49 + contracts/interfaces/IEthFoxVault.sol | 24 + contracts/interfaces/IEthMetaVault.sol | 124 ++ contracts/interfaces/IEthMetaVaultFactory.sol | 38 + contracts/interfaces/IGnoMetaVault.sol | 85 + contracts/interfaces/IGnoMetaVaultFactory.sol | 38 + contracts/interfaces/ISubVaultsCurator.sol | 57 + contracts/interfaces/IVaultEthStaking.sol | 5 + contracts/interfaces/IVaultGnoStaking.sol | 6 + contracts/interfaces/IVaultState.sol | 7 + contracts/interfaces/IVaultSubVaults.sol | 127 ++ contracts/libraries/Errors.sol | 5 + contracts/validators/ValidatorsChecker.sol | 4 +- .../vaults/ethereum/custom/EthFoxVault.sol | 38 +- .../vaults/ethereum/custom/EthMetaVault.sol | 205 +++ .../ethereum/custom/EthMetaVaultFactory.sol | 65 + .../vaults/gnosis/custom/GnoMetaVault.sol | 190 +++ .../gnosis/custom/GnoMetaVaultFactory.sol | 76 + contracts/vaults/modules/VaultEthStaking.sol | 9 + contracts/vaults/modules/VaultGnoStaking.sol | 12 + contracts/vaults/modules/VaultImmutables.sol | 4 +- contracts/vaults/modules/VaultMev.sol | 18 +- contracts/vaults/modules/VaultState.sol | 5 +- contracts/vaults/modules/VaultSubVaults.sol | 635 ++++++++ lib/openzeppelin-contracts-upgradeable | 2 +- script/Network.sol | 4 + script/UpgradeEthNetwork.s.sol | 70 +- script/UpgradeGnoNetwork.s.sol | 64 +- snapshots/ConsolidationsCheckerTest.json | 20 +- snapshots/DepositDataRegistryTest.json | 14 +- snapshots/EthBlocklistErc20VaultTest.json | 12 +- snapshots/EthBlocklistVaultTest.json | 10 +- snapshots/EthErc20VaultTest.json | 26 +- snapshots/EthFoxVaultTest.json | 12 +- snapshots/EthGenesisVaultTest.json | 10 +- snapshots/EthMetaVaultTest.json | 9 + snapshots/EthOsTokenVaultEscrowTest.json | 40 +- snapshots/EthPrivErc20VaultTest.json | 14 +- snapshots/EthPrivVaultTest.json | 14 +- snapshots/EthRewardSplitterTest.json | 20 +- snapshots/EthVaultTest.json | 18 +- snapshots/GnoBlocklistErc20VaultTest.json | 10 +- snapshots/GnoBlocklistVaultTest.json | 8 +- snapshots/GnoErc20VaultTest.json | 18 +- snapshots/GnoGenesisVaultTest.json | 6 +- snapshots/GnoMetaVaultTest.json | 9 + snapshots/GnoOsTokenVaultEscrowTest.json | 4 +- snapshots/GnoPrivErc20VaultTest.json | 10 +- snapshots/GnoPrivVaultTest.json | 8 +- snapshots/GnoRewardSplitterTest.json | 22 +- snapshots/GnoVaultExitQueueTest.json | 10 +- snapshots/GnoVaultTest.json | 12 +- snapshots/KeeperOraclesTest.json | 10 +- snapshots/KeeperRewardsTest.json | 32 +- snapshots/KeeperValidatorsTest.json | 12 +- snapshots/OsTokenConfigTest.json | 8 +- snapshots/OsTokenTest.json | 22 +- snapshots/OwnMevEscrowTest.json | 12 +- snapshots/PriceFeedTest.json | 6 +- snapshots/VaultAdminTest.json | 2 +- snapshots/VaultEnterExitTest.json | 32 +- snapshots/VaultEthStakingTest.json | 32 +- snapshots/VaultFeeTest.json | 10 +- snapshots/VaultGnoStakingTest.json | 22 +- snapshots/VaultOsTokenTest.json | 80 +- snapshots/VaultSubVaultsTest.json | 15 + snapshots/VaultTokenTest.json | 36 +- snapshots/VaultValidatorsTest.json | 78 +- snapshots/VaultVersionTest.json | 20 +- snapshots/VaultsRegistryTest.json | 4 +- test/BalancedCurator.t.sol | 332 ++++ test/CuratorsRegistry.t.sol | 126 ++ test/EthGenesisVault.t.sol | 6 +- test/EthMetaVault.t.sol | 472 ++++++ test/VaultEthStaking.t.sol | 41 + test/VaultSubVaults.t.sol | 1397 +++++++++++++++++ test/gnosis/GnoMetaVault.t.sol | 489 ++++++ test/gnosis/VaultGnoStaking.t.sol | 49 + test/helpers/EthHelpers.sol | 86 +- test/helpers/GnoHelpers.sol | 59 +- 84 files changed, 5500 insertions(+), 453 deletions(-) create mode 100644 contracts/curators/BalancedCurator.sol create mode 100644 contracts/curators/CuratorsRegistry.sol create mode 100644 contracts/interfaces/ICuratorsRegistry.sol create mode 100644 contracts/interfaces/IEthMetaVault.sol create mode 100644 contracts/interfaces/IEthMetaVaultFactory.sol create mode 100644 contracts/interfaces/IGnoMetaVault.sol create mode 100644 contracts/interfaces/IGnoMetaVaultFactory.sol create mode 100644 contracts/interfaces/ISubVaultsCurator.sol create mode 100644 contracts/interfaces/IVaultSubVaults.sol create mode 100644 contracts/vaults/ethereum/custom/EthMetaVault.sol create mode 100644 contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol create mode 100644 contracts/vaults/gnosis/custom/GnoMetaVault.sol create mode 100644 contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol create mode 100644 contracts/vaults/modules/VaultSubVaults.sol create mode 100644 snapshots/EthMetaVaultTest.json create mode 100644 snapshots/GnoMetaVaultTest.json create mode 100644 snapshots/VaultSubVaultsTest.json create mode 100644 test/BalancedCurator.t.sol create mode 100644 test/CuratorsRegistry.t.sol create mode 100644 test/EthMetaVault.t.sol create mode 100644 test/VaultSubVaults.t.sol create mode 100644 test/gnosis/GnoMetaVault.t.sol diff --git a/.env.example b/.env.example index adc716dc..0f23c3e1 100644 --- a/.env.example +++ b/.env.example @@ -17,4 +17,17 @@ TEST_SKIP_SNAPSHOTS=false # deployment PRIVATE_KEY=0x12345 # Add transactions to remove vault factories in current deployment files -REMOVE_PREV_FACTORIES=false \ No newline at end of file +REMOVE_PREV_FACTORIES=false + +# contract variables +# mainnet +#META_VAULT_FACTORY_OWNER= + +# hoodi +#META_VAULT_FACTORY_OWNER=0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6 + +# chiado +#META_VAULT_FACTORY_OWNER=0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6 + +# gnosis +#META_VAULT_FACTORY_OWNER= diff --git a/.gitmodules b/.gitmodules index 23acfb1d..178960bd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/openzeppelin-foundry-upgrades"] - path = lib/openzeppelin-foundry-upgrades - url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades [submodule "lib/openzeppelin-contracts-upgradeable"] path = lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable diff --git a/contracts/curators/BalancedCurator.sol b/contracts/curators/BalancedCurator.sol new file mode 100644 index 00000000..ed2193c1 --- /dev/null +++ b/contracts/curators/BalancedCurator.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {ISubVaultsCurator} from "../interfaces/ISubVaultsCurator.sol"; +import {Errors} from "../libraries/Errors.sol"; + +/** + * @title BalancedCurator + * @author StakeWise + * @notice Defines the functionality for evenly managing assets in sub-vaults. + */ +contract BalancedCurator is ISubVaultsCurator { + /// @inheritdoc ISubVaultsCurator + function getDeposits(uint256 assetsToDeposit, address[] calldata subVaults, address ejectingVault) + external + pure + override + returns (Deposit[] memory deposits) + { + if (assetsToDeposit == 0) { + return deposits; + } + + uint256 subVaultsCount = subVaults.length; + uint256 depositSubVaultsCount = ejectingVault != address(0) ? subVaultsCount - 1 : subVaultsCount; + if (depositSubVaultsCount == 0) { + revert Errors.EmptySubVaults(); + } + uint256 amountPerVault = assetsToDeposit / depositSubVaultsCount; + + // distribute assets evenly across sub-vaults + address subVault; + deposits = new Deposit[](subVaultsCount); + for (uint256 i = 0; i < subVaultsCount;) { + subVault = subVaults[i]; + if (subVault == ejectingVault) { + deposits[i] = Deposit({vault: subVault, assets: 0}); + } else { + deposits[i] = Deposit({vault: subVault, assets: amountPerVault}); + } + unchecked { + // cannot realistically overflow + ++i; + } + } + } + + /// @inheritdoc ISubVaultsCurator + function getExitRequests( + uint256 assetsToExit, + address[] calldata subVaults, + uint256[] memory balances, + address ejectingVault + ) external pure override returns (ExitRequest[] memory exitRequests) { + if (assetsToExit == 0) { + return exitRequests; + } + + uint256 subVaultsCount = subVaults.length; + uint256 exitSubVaultsCount = ejectingVault != address(0) ? subVaultsCount - 1 : subVaultsCount; + if (exitSubVaultsCount == 0) { + revert Errors.EmptySubVaults(); + } + + exitRequests = new ExitRequest[](subVaultsCount); + uint256 amountPerVault = assetsToExit / exitSubVaultsCount; + + uint256 exitAmount; + ExitRequest memory exitRequest; + while (assetsToExit > 0) { + for (uint256 i = 0; i < subVaultsCount;) { + if (subVaults[i] == ejectingVault) { + exitAmount = 0; + } else { + exitAmount = Math.min(Math.min(balances[i], amountPerVault), assetsToExit); + } + exitRequest = exitRequests[i]; + exitRequest.vault = subVaults[i]; + exitRequest.assets += exitAmount; + exitRequests[i] = exitRequest; + + assetsToExit -= exitAmount; + if (assetsToExit == 0) { + break; + } + + balances[i] -= exitAmount; + unchecked { + // cannot realistically overflow + ++i; + } + } + } + } +} diff --git a/contracts/curators/CuratorsRegistry.sol b/contracts/curators/CuratorsRegistry.sol new file mode 100644 index 00000000..2668571a --- /dev/null +++ b/contracts/curators/CuratorsRegistry.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {ICuratorsRegistry} from "../interfaces/ICuratorsRegistry.sol"; +import {Errors} from "../libraries/Errors.sol"; + +/** + * @title CuratorsRegistry + * @author StakeWise + * @notice Defines the registry functionality that keeps track of Curators for the sub-vaults. + */ +contract CuratorsRegistry is Ownable2Step, ICuratorsRegistry { + /// @inheritdoc ICuratorsRegistry + mapping(address curator => bool isCurator) public override curators; + + bool private _initialized; + + /** + * @dev Constructor + */ + constructor() Ownable(msg.sender) {} + + /// @inheritdoc ICuratorsRegistry + function addCurator(address curator) external override onlyOwner { + curators[curator] = true; + emit CuratorAdded(msg.sender, curator); + } + + /// @inheritdoc ICuratorsRegistry + function removeCurator(address curator) external override onlyOwner { + curators[curator] = false; + emit CuratorRemoved(msg.sender, curator); + } + + /// @inheritdoc ICuratorsRegistry + function initialize(address _owner) external override onlyOwner { + if (_owner == address(0)) revert Errors.ZeroAddress(); + if (_initialized) revert Errors.AccessDenied(); + + // transfer ownership + _transferOwnership(_owner); + _initialized = true; + } +} diff --git a/contracts/interfaces/ICuratorsRegistry.sol b/contracts/interfaces/ICuratorsRegistry.sol new file mode 100644 index 00000000..e9f06414 --- /dev/null +++ b/contracts/interfaces/ICuratorsRegistry.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title ICuratorsRegistry + * @author StakeWise + * @notice Defines the interface for the CuratorsRegistry + */ +interface ICuratorsRegistry { + /** + * @notice Emitted when a new curator is added + * @param sender The address of the sender + * @param curator The address of the curator + */ + event CuratorAdded(address indexed sender, address indexed curator); + + /** + * @notice Emitted when a curator is removed + * @param sender The address of the sender + * @param curator The address of the curator + */ + event CuratorRemoved(address indexed sender, address indexed curator); + + /** + * @notice Checks if an address is a curator + * @param curator The address of the curator + * @return True if the address is a curator, false otherwise + */ + function curators(address curator) external view returns (bool); + + /** + * @notice Initializes the CuratorsRegistry + * @param _owner The address of the owner + */ + function initialize(address _owner) external; + + /** + * @notice Adds a new curator + * @param curator The address of the curator to add + */ + function addCurator(address curator) external; + + /** + * @notice Removes a curator + * @param curator The address of the curator to remove + */ + function removeCurator(address curator) external; +} diff --git a/contracts/interfaces/IEthFoxVault.sol b/contracts/interfaces/IEthFoxVault.sol index 5d88a7e3..e0146ccc 100644 --- a/contracts/interfaces/IEthFoxVault.sol +++ b/contracts/interfaces/IEthFoxVault.sol @@ -31,6 +31,30 @@ interface IEthFoxVault is IVaultBlocklist, IMulticall { + /** + * @dev Struct for deploying the EthFoxVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param validatorsRegistry The contract address used for registering validators in beacon chain + * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain + * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain + * @param consolidationsChecker The contract address used for checking consolidations + * @param sharedMevEscrow The address of the shared MEV escrow + * @param depositDataRegistry The address of the DepositDataRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct EthFoxVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address validatorsRegistry; + address validatorsWithdrawals; + address validatorsConsolidations; + address consolidationsChecker; + address sharedMevEscrow; + address depositDataRegistry; + uint64 exitingAssetsClaimDelay; + } + /** * @notice Event emitted when a user is ejected from the Vault * @param user The address of the user diff --git a/contracts/interfaces/IEthMetaVault.sol b/contracts/interfaces/IEthMetaVault.sol new file mode 100644 index 00000000..a065f1af --- /dev/null +++ b/contracts/interfaces/IEthMetaVault.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IKeeperRewards} from "./IKeeperRewards.sol"; +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultSubVaults} from "./IVaultSubVaults.sol"; +import {IMulticall} from "./IMulticall.sol"; + +/** + * @title IEthMetaVault + * @author StakeWise + * @notice Defines the interface for the EthMetaVault contract + */ +interface IEthMetaVault is + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultEnterExit, + IVaultOsToken, + IVaultSubVaults, + IMulticall +{ + /** + * @dev Struct for deploying the EthMetaVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param curatorsRegistry The address of the CuratorsRegistry contract + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct EthMetaVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address curatorsRegistry; + uint64 exitingAssetsClaimDelay; + } + + /** + * @dev Struct for initializing the EthMetaVault contract + * @param subVaultsCurator The address of the initial sub-vaults curator + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct EthMetaVaultInitParams { + address subVaultsCurator; + uint256 capacity; + uint16 feePercent; + string metadataIpfsHash; + } + + /** + * @notice Initializes or upgrades the EthMetaVault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the EthVault contract + */ + function initialize(bytes calldata params) external payable; + + /** + * @notice Deposit ETH to the Vault + * @param receiver The address that will receive Vault's shares + * @param referrer The address of the referrer. Set to zero address if not used. + * @return shares The number of shares minted + */ + function deposit(address receiver, address referrer) external payable returns (uint256 shares); + + /** + * @notice Updates Vault state and deposits ETH to the Vault + * @param receiver The address that will receive Vault's shares + * @param referrer The address of the referrer. Set to zero address if not used. + * @param harvestParams The parameters for harvesting Keeper rewards + * @return shares The number of shares minted + */ + function updateStateAndDeposit( + address receiver, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable returns (uint256 shares); + + /** + * @notice Deposits assets to the vault and mints OsToken shares to the receiver + * @param receiver The address to receive the OsToken + * @param osTokenShares The amount of OsToken shares to mint. + * If set to type(uint256).max, max OsToken shares will be minted. + * @param referrer The address of the referrer + * @return The amount of OsToken assets minted + */ + function depositAndMintOsToken(address receiver, uint256 osTokenShares, address referrer) + external + payable + returns (uint256); + + /** + * @notice Updates the state, deposits assets to the vault and mints OsToken shares to the receiver + * @param receiver The address to receive the OsToken + * @param osTokenShares The amount of OsToken shares to mint. + * If set to type(uint256).max, max OsToken shares will be minted. + * @param referrer The address of the referrer + * @param harvestParams The parameters for the harvest + * @return The amount of OsToken assets minted + */ + function updateStateAndDepositAndMintOsToken( + address receiver, + uint256 osTokenShares, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable returns (uint256); + + /** + * @notice Donate assets to the Vault. Must transfer ETH together with the call. + */ + function donateAssets() external payable; +} diff --git a/contracts/interfaces/IEthMetaVaultFactory.sol b/contracts/interfaces/IEthMetaVaultFactory.sol new file mode 100644 index 00000000..7c2b9f99 --- /dev/null +++ b/contracts/interfaces/IEthMetaVaultFactory.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IEthMetaVaultFactory + * @author StakeWise + * @notice Defines the interface for the ETH Meta Vault Factory contract + */ +interface IEthMetaVaultFactory { + /** + * @notice Event emitted on a MetaVault creation + * @param caller The address of the factory caller + * @param admin The address of the Vault admin + * @param vault The address of the created Vault + * @param params The encoded parameters for initializing the Vault contract + */ + event MetaVaultCreated(address indexed caller, address indexed admin, address indexed vault, bytes params); + + /** + * @notice The address of the Vault implementation contract used for proxy creation + * @return The address of the Vault implementation contract + */ + function implementation() external view returns (address); + + /** + * @notice The address of the Vault admin used for Vault creation + * @return The address of the Vault admin + */ + function vaultAdmin() external view returns (address); + + /** + * @notice Create Vault. Must transfer security deposit together with a call. + * @param admin The address of the Vault admin + * @param params The encoded parameters for initializing the Vault contract + */ + function createVault(address admin, bytes calldata params) external payable returns (address vault); +} diff --git a/contracts/interfaces/IGnoMetaVault.sol b/contracts/interfaces/IGnoMetaVault.sol new file mode 100644 index 00000000..3bd02008 --- /dev/null +++ b/contracts/interfaces/IGnoMetaVault.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IVaultAdmin} from "./IVaultAdmin.sol"; +import {IVaultVersion} from "./IVaultVersion.sol"; +import {IVaultFee} from "./IVaultFee.sol"; +import {IVaultState} from "./IVaultState.sol"; +import {IVaultEnterExit} from "./IVaultEnterExit.sol"; +import {IVaultOsToken} from "./IVaultOsToken.sol"; +import {IVaultSubVaults} from "./IVaultSubVaults.sol"; +import {IMulticall} from "./IMulticall.sol"; + +/** + * @title IGnoMetaVault + * @author StakeWise + * @notice Defines the interface for the GnoMetaVault contract + */ +interface IGnoMetaVault is + IVaultAdmin, + IVaultVersion, + IVaultFee, + IVaultState, + IVaultEnterExit, + IVaultOsToken, + IVaultSubVaults, + IMulticall +{ + /** + * @dev Struct for deploying the GnoMetaVault contract + * @param keeper The address of the Keeper contract + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param osTokenVaultController The address of the OsTokenVaultController contract + * @param osTokenConfig The address of the OsTokenConfig contract + * @param osTokenVaultEscrow The address of the OsTokenVaultEscrow contract + * @param curatorsRegistry The address of the CuratorsRegistry contract + * @param gnoToken The address of the GNO token + * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + */ + struct GnoMetaVaultConstructorArgs { + address keeper; + address vaultsRegistry; + address osTokenVaultController; + address osTokenConfig; + address osTokenVaultEscrow; + address curatorsRegistry; + address gnoToken; + uint64 exitingAssetsClaimDelay; + } + + /** + * @dev Struct for initializing the GnoMetaVault contract + * @param subVaultsCurator The address of the initial sub-vaults curator + * @param capacity The Vault stops accepting deposits after exceeding the capacity + * @param feePercent The fee percent that is charged by the Vault + * @param metadataIpfsHash The IPFS hash of the Vault's metadata file + */ + struct GnoMetaVaultInitParams { + address subVaultsCurator; + uint256 capacity; + uint16 feePercent; + string metadataIpfsHash; + } + + /** + * @notice Initializes or upgrades the GnoMetaVault contract. Must transfer security deposit during the deployment. + * @param params The encoded parameters for initializing the GnoVault contract + */ + function initialize(bytes calldata params) external payable; + + /** + * @notice Deposit GNO to the Vault + * @param assets The amount of GNO to deposit + * @param receiver The address that will receive Vault's shares + * @param referrer The address of the referrer. Set to zero address if not used. + * @return shares The number of shares minted + */ + function deposit(uint256 assets, address receiver, address referrer) external returns (uint256 shares); + + /** + * @notice Donate assets to the Vault. Must approve GNO transfer before the call. + * @param amount The amount of GNO to donate + */ + function donateAssets(uint256 amount) external; +} diff --git a/contracts/interfaces/IGnoMetaVaultFactory.sol b/contracts/interfaces/IGnoMetaVaultFactory.sol new file mode 100644 index 00000000..6996fcd9 --- /dev/null +++ b/contracts/interfaces/IGnoMetaVaultFactory.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IGnoMetaVaultFactory + * @author StakeWise + * @notice Defines the interface for the GNO Meta Vault Factory contract + */ +interface IGnoMetaVaultFactory { + /** + * @notice Event emitted on a MetaVault creation + * @param caller The address of the factory caller + * @param admin The address of the Vault admin + * @param vault The address of the created Vault + * @param params The encoded parameters for initializing the Vault contract + */ + event MetaVaultCreated(address indexed caller, address indexed admin, address indexed vault, bytes params); + + /** + * @notice The address of the Vault implementation contract used for proxy creation + * @return The address of the Vault implementation contract + */ + function implementation() external view returns (address); + + /** + * @notice The address of the Vault admin used for Vault creation + * @return The address of the Vault admin + */ + function vaultAdmin() external view returns (address); + + /** + * @notice Create Vault. Must transfer security deposit together with a call. + * @param admin The address of the Vault admin + * @param params The encoded parameters for initializing the Vault contract + */ + function createVault(address admin, bytes calldata params) external returns (address vault); +} diff --git a/contracts/interfaces/ISubVaultsCurator.sol b/contracts/interfaces/ISubVaultsCurator.sol new file mode 100644 index 00000000..19455ea8 --- /dev/null +++ b/contracts/interfaces/ISubVaultsCurator.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title ISubVaultsCurator + * @author StakeWise + * @notice Defines the interface for the SubVaultsCurator contract + */ +interface ISubVaultsCurator { + /** + * @notice Struct for storing deposit data + * @param vault The address of the vault + * @param assets The amount of assets to deposit + */ + struct Deposit { + address vault; + uint256 assets; + } + + /** + * @notice Struct for storing exit request data + * @param vault The address of the vault + * @param assets The amount of assets to exit + */ + struct ExitRequest { + address vault; + uint256 assets; + } + + /** + * @notice Function to get the deposits to the sub-vaults + * @param assetsToDeposit The amount of assets to deposit + * @param subVaults The addresses of the sub-vaults + * @param ejectingVault The address of the sub-vault that is currently ejecting. Should be zero if none. + * @return deposits An array of Deposit structs containing the vault addresses and the amounts to deposit + */ + function getDeposits(uint256 assetsToDeposit, address[] calldata subVaults, address ejectingVault) + external + pure + returns (Deposit[] memory deposits); + + /** + * @notice Function to get the exit requests to the sub-vaults + * @param assetsToExit The amount of assets to exit + * @param subVaults The addresses of the sub-vaults + * @param balances The balances of the sub-vaults + * @param ejectingVault The address of the sub-vault that is currently ejecting. Should be zero if none. + * @return exitRequests An array of ExitRequest structs containing the vault addresses and the amounts to exit + */ + function getExitRequests( + uint256 assetsToExit, + address[] calldata subVaults, + uint256[] memory balances, + address ejectingVault + ) external pure returns (ExitRequest[] memory exitRequests); +} diff --git a/contracts/interfaces/IVaultEthStaking.sol b/contracts/interfaces/IVaultEthStaking.sol index 21a4b402..a827dd0c 100644 --- a/contracts/interfaces/IVaultEthStaking.sol +++ b/contracts/interfaces/IVaultEthStaking.sol @@ -27,6 +27,11 @@ interface IVaultEthStaking is IVaultState, IVaultValidators, IVaultEnterExit, IV */ function receiveFromMevEscrow() external payable; + /** + * @notice Donate assets to the Vault. Must transfer ETH together with the call. + */ + function donateAssets() external payable; + /** * @notice Updates Vault state and deposits ETH to the Vault * @param receiver The address that will receive Vault's shares diff --git a/contracts/interfaces/IVaultGnoStaking.sol b/contracts/interfaces/IVaultGnoStaking.sol index e0f27409..7e75f88f 100644 --- a/contracts/interfaces/IVaultGnoStaking.sol +++ b/contracts/interfaces/IVaultGnoStaking.sol @@ -26,4 +26,10 @@ interface IVaultGnoStaking is IVaultValidators, IVaultEnterExit { * @return shares The number of shares minted */ function deposit(uint256 assets, address receiver, address referrer) external returns (uint256 shares); + + /** + * @notice Donate assets to the Vault. Must approve GNO transfer before the call. + * @param amount The amount of GNO to donate + */ + function donateAssets(uint256 amount) external; } diff --git a/contracts/interfaces/IVaultState.sol b/contracts/interfaces/IVaultState.sol index a9ff7578..ac3dcd5f 100644 --- a/contracts/interfaces/IVaultState.sol +++ b/contracts/interfaces/IVaultState.sol @@ -32,6 +32,13 @@ interface IVaultState is IVaultFee { */ event ExitingAssetsPenalized(uint256 penalty); + /** + * @notice Event emitted when the assets are donated to the Vault + * @param sender The address of the sender + * @param assets The amount of donated assets + */ + event AssetsDonated(address sender, uint256 assets); + /** * @notice Total assets in the Vault * @return The total amount of the underlying asset that is "managed" by Vault diff --git a/contracts/interfaces/IVaultSubVaults.sol b/contracts/interfaces/IVaultSubVaults.sol new file mode 100644 index 00000000..49840fba --- /dev/null +++ b/contracts/interfaces/IVaultSubVaults.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IVaultSubVaults + * @author StakeWise + * @notice Defines the interface for the VaultSubVaults contract + */ +interface IVaultSubVaults { + /** + * @notice Struct for sub vault state + * @param stakedShares The number of shares staked in the sub vault + * @param queuedShares The number of shares queued for exit in the sub vault + */ + struct SubVaultState { + uint128 stakedShares; + uint128 queuedShares; + } + + /** + * @notice Struct for submitting sub vault exit request + * @param exitQueueIndex The index of the exit queue + * @param vault The address of the vault + * @param timestamp The timestamp of the exit request + */ + struct SubVaultExitRequest { + uint256 exitQueueIndex; + address vault; + uint64 timestamp; + } + + /** + * @notice Emitted when the rewards nonce is updated + * @param rewardsNonce The new rewards nonce + */ + event RewardsNonceUpdated(uint256 rewardsNonce); + + /** + * @notice Emitted when the sub vaults are harvested + * @param totalAssetsDelta The change in total assets after the harvest + */ + event SubVaultsHarvested(int256 totalAssetsDelta); + + /** + * @notice Emitted when the new sub-vault is added + * @param caller The address of the caller + * @param vault The address of the sub-vault + */ + event SubVaultAdded(address indexed caller, address indexed vault); + + /** + * @notice Emitted when the sub-vault is ejecting + * @param caller The address of the caller + * @param vault The address of the sub-vault + */ + event SubVaultEjecting(address indexed caller, address indexed vault); + + /** + * @notice Emitted when the sub-vault is ejected + * @param caller The address of the caller + * @param vault The address of the sub-vault + */ + event SubVaultEjected(address indexed caller, address indexed vault); + + /** + * @notice Emitted when the sub-vaults curator is updated + * @param caller The address of the caller + * @param curator The address of the new sub-vaults curator + */ + event SubVaultsCuratorUpdated(address indexed caller, address indexed curator); + + /** + * @notice Sub-vaults curator contract + * @return The address of the Sub-vaults curator contract + */ + function subVaultsCurator() external view returns (address); + + /** + * @notice Ejecting sub-vault + * @return The address of the ejecting sub-vault + */ + function ejectingSubVault() external view returns (address); + + /** + * @notice Function to get the list sub-vaults + * @return An array of addresses of the sub-vaults + */ + function getSubVaults() external view returns (address[] memory); + + /** + * @notice Function to get the state of a sub-vault + * @param vault The address of the sub-vault + * @return The state of the sub-vault + */ + function subVaultsStates(address vault) external view returns (SubVaultState memory); + + /** + * @notice Function to update the the sub-vaults curator. Can only be called by the admin. + * @param curator The address of the new sub-vaults curator + */ + function setSubVaultsCurator(address curator) external; + + /** + * @notice Function to add a new sub-vault. Can only be called by the admin. + * @param vault The address of the sub-vault to add + */ + function addSubVault(address vault) external; + + /** + * @notice Function to remove a sub-vault. Can only be called by the admin. + * All the sub-vault shares will be added to the exit queue. + * @param vault The address of the sub-vault to remove + */ + function ejectSubVault(address vault) external; + + /** + * @notice Deposit available assets to the sub vaults + */ + function depositToSubVaults() external; + + /** + * @notice Claim the exited assets from the sub vaults + * @param exitRequests The array of exit requests to claim + */ + function claimSubVaultsExitedAssets(SubVaultExitRequest[] calldata exitRequests) external; +} diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index ac8bf284..c0083521 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -52,4 +52,9 @@ library Errors { error FlashLoanFailed(); error CannotTopUpV1Validators(); error InvalidSignatures(); + error EmptySubVaults(); + error UnclaimedAssets(); + error EjectingVault(); + error InvalidCurator(); + error RewardsNonceIsHigher(); } diff --git a/contracts/validators/ValidatorsChecker.sol b/contracts/validators/ValidatorsChecker.sol index 9383fd9b..4cdf4e03 100644 --- a/contracts/validators/ValidatorsChecker.sol +++ b/contracts/validators/ValidatorsChecker.sol @@ -57,7 +57,7 @@ abstract contract ValidatorsChecker is Multicall, IValidatorsChecker { /// @inheritdoc IValidatorsChecker function getExitQueueCumulativeTickets(address vault) external view override returns (uint256) { (uint128 queuedShares,, uint128 totalExitingTickets,, uint256 totalTickets) = - IVaultValidators(vault).getExitQueueData(); + IVaultState(vault).getExitQueueData(); return totalTickets + queuedShares + totalExitingTickets; } @@ -74,7 +74,7 @@ abstract contract ValidatorsChecker is Multicall, IValidatorsChecker { uint128 totalExitingTickets, uint128 totalExitingAssets, uint256 totalTickets - ) = IVaultValidators(vault).getExitQueueData(); + ) = IVaultState(vault).getExitQueueData(); // check whether already covered if (totalTickets >= targetCumulativeTickets) { return 0; diff --git a/contracts/vaults/ethereum/custom/EthFoxVault.sol b/contracts/vaults/ethereum/custom/EthFoxVault.sol index 15e2cb26..34bbf263 100644 --- a/contracts/vaults/ethereum/custom/EthFoxVault.sol +++ b/contracts/vaults/ethereum/custom/EthFoxVault.sol @@ -43,38 +43,20 @@ contract EthFoxVault is * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. - * @param keeper The address of the Keeper contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param validatorsRegistry The contract address used for registering validators in beacon chain - * @param validatorsWithdrawals The contract address used for withdrawing validators in beacon chain - * @param validatorsConsolidations The contract address used for consolidating validators in beacon chain - * @param consolidationsChecker The contract address used for checking consolidations - * @param sharedMevEscrow The address of the shared MEV escrow - * @param depositDataRegistry The address of the DepositDataRegistry contract - * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking + * @param args The arguments for initializing the EthFoxVault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor( - address keeper, - address vaultsRegistry, - address validatorsRegistry, - address validatorsWithdrawals, - address validatorsConsolidations, - address consolidationsChecker, - address sharedMevEscrow, - address depositDataRegistry, - uint256 exitingAssetsClaimDelay - ) - VaultImmutables(keeper, vaultsRegistry) + constructor(EthFoxVaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) VaultValidators( - depositDataRegistry, - validatorsRegistry, - validatorsWithdrawals, - validatorsConsolidations, - consolidationsChecker + args.depositDataRegistry, + args.validatorsRegistry, + args.validatorsWithdrawals, + args.validatorsConsolidations, + args.consolidationsChecker ) - VaultEnterExit(exitingAssetsClaimDelay) - VaultMev(sharedMevEscrow) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultMev(args.sharedMevEscrow) { _disableInitializers(); } diff --git a/contracts/vaults/ethereum/custom/EthMetaVault.sol b/contracts/vaults/ethereum/custom/EthMetaVault.sol new file mode 100644 index 00000000..3db29134 --- /dev/null +++ b/contracts/vaults/ethereum/custom/EthMetaVault.sol @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IVaultEthStaking} from "../../../interfaces/IVaultEthStaking.sol"; +import {IEthMetaVaultFactory} from "../../../interfaces/IEthMetaVaultFactory.sol"; +import {IKeeperRewards} from "../../../interfaces/IKeeperRewards.sol"; +import {IEthMetaVault} from "../../../interfaces/IEthMetaVault.sol"; +import {Errors} from "../../../libraries/Errors.sol"; +import {VaultImmutables} from "../../modules/VaultImmutables.sol"; +import {VaultAdmin} from "../../modules/VaultAdmin.sol"; +import {VaultVersion, IVaultVersion} from "../../modules/VaultVersion.sol"; +import {VaultFee} from "../../modules/VaultFee.sol"; +import {VaultState, IVaultState} from "../../modules/VaultState.sol"; +import {VaultEnterExit, IVaultEnterExit} from "../../modules/VaultEnterExit.sol"; +import {VaultOsToken} from "../../modules/VaultOsToken.sol"; +import {VaultSubVaults} from "../../modules/VaultSubVaults.sol"; +import {Multicall} from "../../../base/Multicall.sol"; + +/** + * @title EthMetaVault + * @author StakeWise + * @notice Defines the Meta Vault that delegates stake to the sub vaults on Ethereum + */ +contract EthMetaVault is + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultEnterExit, + VaultOsToken, + VaultSubVaults, + Multicall, + IEthMetaVault +{ + using EnumerableSet for EnumerableSet.AddressSet; + + uint8 private constant _version = 5; + uint256 private constant _securityDeposit = 1e9; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the EthMetaVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(EthMetaVaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultSubVaults(args.curatorsRegistry) + { + _disableInitializers(); + } + + /// @inheritdoc IEthMetaVault + function initialize(bytes calldata params) external payable virtual override reinitializer(_version) { + __EthMetaVault_init(IEthMetaVaultFactory(msg.sender).vaultAdmin(), abi.decode(params, (EthMetaVaultInitParams))); + } + + /// @inheritdoc IVaultState + function isStateUpdateRequired() public view override(IVaultState, VaultState, VaultSubVaults) returns (bool) { + return super.isStateUpdateRequired(); + } + + /// @inheritdoc IEthMetaVault + function deposit(address receiver, address referrer) public payable virtual override returns (uint256 shares) { + return _deposit(receiver, msg.value, referrer); + } + + /** + * @dev Function for depositing using fallback function + */ + receive() external payable virtual { + // claim exited assets from the sub vaults should not be processed as deposits + if (_subVaults.contains(msg.sender)) { + return; + } + _deposit(msg.sender, msg.value, address(0)); + } + + // @inheritdoc IVaultState + function updateState(IKeeperRewards.HarvestParams calldata harvestParams) + public + override(IVaultState, VaultState, VaultSubVaults) + { + super.updateState(harvestParams); + } + + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit, VaultOsToken) + returns (uint256 positionTicket) + { + return super.enterExitQueue(shares, receiver); + } + + /// @inheritdoc IEthMetaVault + function updateStateAndDeposit( + address receiver, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) public payable virtual override returns (uint256 shares) { + updateState(harvestParams); + return deposit(receiver, referrer); + } + + /// @inheritdoc IEthMetaVault + function depositAndMintOsToken(address receiver, uint256 osTokenShares, address referrer) + public + payable + override + returns (uint256) + { + deposit(msg.sender, referrer); + return mintOsToken(receiver, osTokenShares, referrer); + } + + /// @inheritdoc IEthMetaVault + function updateStateAndDepositAndMintOsToken( + address receiver, + uint256 osTokenShares, + address referrer, + IKeeperRewards.HarvestParams calldata harvestParams + ) external payable override returns (uint256) { + updateState(harvestParams); + return depositAndMintOsToken(receiver, osTokenShares, referrer); + } + + /// @inheritdoc IEthMetaVault + function donateAssets() external payable override { + if (msg.value == 0) { + revert Errors.InvalidAssets(); + } + _donatedAssets += msg.value; + emit AssetsDonated(msg.sender, msg.value); + } + + /// @inheritdoc VaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("EthMetaVault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } + + /// @inheritdoc VaultImmutables + function _checkHarvested() internal view override(VaultImmutables, VaultSubVaults) { + super._checkHarvested(); + } + + /// @inheritdoc VaultImmutables + function _isCollateralized() internal view virtual override(VaultImmutables, VaultSubVaults) returns (bool) { + return super._isCollateralized(); + } + + /// @inheritdoc VaultSubVaults + function _depositToVault(address vault, uint256 assets) internal override returns (uint256) { + return IVaultEthStaking(vault).deposit{value: assets}(address(this), address(0)); + } + + /// @inheritdoc VaultState + function _vaultAssets() internal view virtual override returns (uint256) { + return address(this).balance; + } + + /// @inheritdoc VaultEnterExit + function _transferVaultAssets(address receiver, uint256 assets) internal virtual override nonReentrant { + return Address.sendValue(payable(receiver), assets); + } + + /** + * @dev Initializes the EthMetaVault contract + * @param admin The address of the admin of the Vault + * @param params The parameters for initializing the EthMetaVault contract + */ + function __EthMetaVault_init(address admin, EthMetaVaultInitParams memory params) internal onlyInitializing { + __VaultAdmin_init(admin, params.metadataIpfsHash); + __VaultSubVaults_init(params.subVaultsCurator); + // fee recipient is initially set to admin address + __VaultFee_init(admin, params.feePercent); + __VaultState_init(params.capacity); + + // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 + if (msg.value < _securityDeposit) revert Errors.InvalidSecurityDeposit(); + _deposit(address(this), msg.value, address(0)); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol b/contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol new file mode 100644 index 00000000..a7e19a1f --- /dev/null +++ b/contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IEthMetaVaultFactory} from "../../../interfaces/IEthMetaVaultFactory.sol"; +import {IEthMetaVault} from "../../../interfaces/IEthMetaVault.sol"; +import {IVaultsRegistry} from "../../../interfaces/IVaultsRegistry.sol"; +import {Errors} from "../../../libraries/Errors.sol"; + +/** + * @title EthMetaVaultFactory + * @author StakeWise + * @notice Factory for deploying Ethereum meta Vaults + */ +contract EthMetaVaultFactory is Ownable2Step, IEthMetaVaultFactory { + IVaultsRegistry internal immutable _vaultsRegistry; + + /// @inheritdoc IEthMetaVaultFactory + address public immutable override implementation; + + /// @inheritdoc IEthMetaVaultFactory + address public override vaultAdmin; + + /** + * @dev Constructor + * @param initialOwner The address of the contract owner + * @param _implementation The implementation address of Vault + * @param vaultsRegistry The address of the VaultsRegistry contract + */ + constructor(address initialOwner, address _implementation, IVaultsRegistry vaultsRegistry) Ownable(initialOwner) { + implementation = _implementation; + _vaultsRegistry = vaultsRegistry; + } + + /// @inheritdoc IEthMetaVaultFactory + function createVault(address admin, bytes calldata params) + external + payable + override + onlyOwner + returns (address vault) + { + if (admin == address(0)) revert Errors.ZeroAddress(); + + // create vault + vault = address(new ERC1967Proxy(implementation, "")); + + // set admin so that it can be initialized in the Vault + vaultAdmin = admin; + + // initialize Vault + IEthMetaVault(vault).initialize{value: msg.value}(params); + + // cleanup admin + delete vaultAdmin; + + // add vault to the registry + _vaultsRegistry.addVault(vault); + + // emit event + emit MetaVaultCreated(msg.sender, admin, vault, params); + } +} diff --git a/contracts/vaults/gnosis/custom/GnoMetaVault.sol b/contracts/vaults/gnosis/custom/GnoMetaVault.sol new file mode 100644 index 00000000..9e086796 --- /dev/null +++ b/contracts/vaults/gnosis/custom/GnoMetaVault.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IGnoMetaVaultFactory} from "../../../interfaces/IGnoMetaVaultFactory.sol"; +import {IVaultGnoStaking} from "../../../interfaces/IVaultGnoStaking.sol"; +import {IKeeperRewards} from "../../../interfaces/IKeeperRewards.sol"; +import {IGnoMetaVault} from "../../../interfaces/IGnoMetaVault.sol"; +import {Errors} from "../../../libraries/Errors.sol"; +import {VaultImmutables} from "../../modules/VaultImmutables.sol"; +import {VaultAdmin} from "../../modules/VaultAdmin.sol"; +import {VaultVersion, IVaultVersion} from "../../modules/VaultVersion.sol"; +import {VaultFee} from "../../modules/VaultFee.sol"; +import {VaultState, IVaultState} from "../../modules/VaultState.sol"; +import {VaultEnterExit, IVaultEnterExit} from "../../modules/VaultEnterExit.sol"; +import {VaultOsToken} from "../../modules/VaultOsToken.sol"; +import {IVaultSubVaults, VaultSubVaults} from "../../modules/VaultSubVaults.sol"; +import {Multicall} from "../../../base/Multicall.sol"; + +/** + * @title GnoMetaVault + * @author StakeWise + * @notice Defines the Meta Vault that delegates stake to the sub vaults on Gnosis + */ +contract GnoMetaVault is + VaultImmutables, + Initializable, + VaultAdmin, + VaultVersion, + VaultFee, + VaultState, + VaultEnterExit, + VaultOsToken, + VaultSubVaults, + Multicall, + IGnoMetaVault +{ + using EnumerableSet for EnumerableSet.AddressSet; + + uint8 private constant _version = 3; + uint256 private constant _securityDeposit = 1e9; + + IERC20 private immutable _gnoToken; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param args The arguments for initializing the GnoMetaVault contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(GnoMetaVaultConstructorArgs memory args) + VaultImmutables(args.keeper, args.vaultsRegistry) + VaultEnterExit(args.exitingAssetsClaimDelay) + VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) + VaultSubVaults(args.curatorsRegistry) + { + _gnoToken = IERC20(args.gnoToken); + _disableInitializers(); + } + + /// @inheritdoc IGnoMetaVault + function initialize(bytes calldata params) external payable virtual override reinitializer(_version) { + __GnoMetaVault_init(IGnoMetaVaultFactory(msg.sender).vaultAdmin(), abi.decode(params, (GnoMetaVaultInitParams))); + } + + /// @inheritdoc IGnoMetaVault + function deposit(uint256 assets, address receiver, address referrer) + public + virtual + override + nonReentrant + returns (uint256 shares) + { + // withdraw GNO tokens from the user + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), assets); + shares = _deposit(receiver, assets, referrer); + } + + /// @inheritdoc IVaultState + function isStateUpdateRequired() public view override(IVaultState, VaultState, VaultSubVaults) returns (bool) { + return super.isStateUpdateRequired(); + } + + /// @inheritdoc IVaultSubVaults + function addSubVault(address vault) public virtual override(IVaultSubVaults, VaultSubVaults) { + super.addSubVault(vault); + // approve transferring GNO to sub-vault + _gnoToken.approve(vault, type(uint256).max); + } + + /// @inheritdoc IVaultSubVaults + function ejectSubVault(address vault) public virtual override(IVaultSubVaults, VaultSubVaults) { + super.ejectSubVault(vault); + // revoke transferring GNO to sub-vault + _gnoToken.approve(vault, 0); + } + + // @inheritdoc IVaultState + function updateState(IKeeperRewards.HarvestParams calldata harvestParams) + public + override(IVaultState, VaultState, VaultSubVaults) + { + super.updateState(harvestParams); + } + + /// @inheritdoc IVaultEnterExit + function enterExitQueue(uint256 shares, address receiver) + public + virtual + override(IVaultEnterExit, VaultEnterExit, VaultOsToken) + returns (uint256 positionTicket) + { + return super.enterExitQueue(shares, receiver); + } + + /// @inheritdoc IGnoMetaVault + function donateAssets(uint256 amount) external override nonReentrant { + if (amount == 0) { + revert Errors.InvalidAssets(); + } + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), amount); + + _donatedAssets += amount; + emit AssetsDonated(msg.sender, amount); + } + + /// @inheritdoc VaultVersion + function vaultId() public pure virtual override(IVaultVersion, VaultVersion) returns (bytes32) { + return keccak256("GnoMetaVault"); + } + + /// @inheritdoc IVaultVersion + function version() public pure virtual override(IVaultVersion, VaultVersion) returns (uint8) { + return _version; + } + + /// @inheritdoc VaultImmutables + function _checkHarvested() internal view override(VaultImmutables, VaultSubVaults) { + super._checkHarvested(); + } + + /// @inheritdoc VaultImmutables + function _isCollateralized() internal view virtual override(VaultImmutables, VaultSubVaults) returns (bool) { + return super._isCollateralized(); + } + + /// @inheritdoc VaultSubVaults + function _depositToVault(address vault, uint256 assets) internal override returns (uint256) { + return IVaultGnoStaking(vault).deposit(assets, address(this), address(0)); + } + + /// @inheritdoc VaultState + function _vaultAssets() internal view virtual override returns (uint256) { + return _gnoToken.balanceOf(address(this)); + } + + /// @inheritdoc VaultEnterExit + function _transferVaultAssets(address receiver, uint256 assets) internal virtual override nonReentrant { + SafeERC20.safeTransfer(_gnoToken, receiver, assets); + } + + /** + * @dev Initializes the GnoMetaVault contract + * @param admin The address of the admin of the Vault + * @param params The parameters for initializing the GnoMetaVault contract + */ + function __GnoMetaVault_init(address admin, GnoMetaVaultInitParams memory params) internal onlyInitializing { + __VaultAdmin_init(admin, params.metadataIpfsHash); + __VaultSubVaults_init(params.subVaultsCurator); + // fee recipient is initially set to admin address + __VaultFee_init(admin, params.feePercent); + __VaultState_init(params.capacity); + + _deposit(address(this), _securityDeposit, address(0)); + // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol b/contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol new file mode 100644 index 00000000..b3ff1ba8 --- /dev/null +++ b/contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IGnoMetaVaultFactory} from "../../../interfaces/IGnoMetaVaultFactory.sol"; +import {IGnoMetaVault} from "../../../interfaces/IGnoMetaVault.sol"; +import {IVaultsRegistry} from "../../../interfaces/IVaultsRegistry.sol"; +import {Errors} from "../../../libraries/Errors.sol"; + +/** + * @title GnoMetaVaultFactory + * @author StakeWise + * @notice Factory for deploying Gnosis meta Vaults + */ +contract GnoMetaVaultFactory is Ownable2Step, IGnoMetaVaultFactory { + uint256 private constant _securityDeposit = 1e9; + + IVaultsRegistry internal immutable _vaultsRegistry; + + IERC20 internal immutable _gnoToken; + + /// @inheritdoc IGnoMetaVaultFactory + address public immutable override implementation; + + /// @inheritdoc IGnoMetaVaultFactory + address public override vaultAdmin; + + /** + * @dev Constructor + * @param initialOwner The address of the contract owner + * @param _implementation The implementation address of Vault + * @param vaultsRegistry The address of the VaultsRegistry contract + * @param gnoToken The address of the GNO token contract + */ + constructor(address initialOwner, address _implementation, IVaultsRegistry vaultsRegistry, address gnoToken) + Ownable(initialOwner) + { + implementation = _implementation; + _vaultsRegistry = vaultsRegistry; + _gnoToken = IERC20(gnoToken); + } + + /// @inheritdoc IGnoMetaVaultFactory + function createVault(address admin, bytes calldata params) external override onlyOwner returns (address vault) { + if (admin == address(0)) revert Errors.ZeroAddress(); + + // transfer GNO security deposit to the factory + // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); + + // create vault + vault = address(new ERC1967Proxy(implementation, "")); + + // approve GNO token for the vault security deposit + _gnoToken.approve(vault, _securityDeposit); + + // set admin so that it can be initialized in the Vault + vaultAdmin = admin; + + // initialize Vault + IGnoMetaVault(vault).initialize(params); + + // cleanup admin + delete vaultAdmin; + + // add vault to the registry + _vaultsRegistry.addVault(vault); + + // emit event + emit MetaVaultCreated(msg.sender, admin, vault, params); + } +} diff --git a/contracts/vaults/modules/VaultEthStaking.sol b/contracts/vaults/modules/VaultEthStaking.sol index 361f99d8..b88d4674 100644 --- a/contracts/vaults/modules/VaultEthStaking.sol +++ b/contracts/vaults/modules/VaultEthStaking.sol @@ -56,6 +56,15 @@ abstract contract VaultEthStaking is if (msg.sender != mevEscrow()) revert Errors.AccessDenied(); } + /// @inheritdoc IVaultEthStaking + function donateAssets() external payable override { + if (msg.value == 0) { + revert Errors.InvalidAssets(); + } + _donatedAssets += msg.value; + emit AssetsDonated(msg.sender, msg.value); + } + /// @inheritdoc VaultValidators function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual override { uint256 totalDeposits = deposits.length; diff --git a/contracts/vaults/modules/VaultGnoStaking.sol b/contracts/vaults/modules/VaultGnoStaking.sol index 3ecd137e..d6783ffb 100644 --- a/contracts/vaults/modules/VaultGnoStaking.sol +++ b/contracts/vaults/modules/VaultGnoStaking.sol @@ -9,6 +9,7 @@ import {IGnoValidatorsRegistry} from "../../interfaces/IGnoValidatorsRegistry.so import {IVaultGnoStaking} from "../../interfaces/IVaultGnoStaking.sol"; import {IGnoDaiDistributor} from "../../interfaces/IGnoDaiDistributor.sol"; import {ValidatorUtils} from "../../libraries/ValidatorUtils.sol"; +import {Errors} from "../../libraries/Errors.sol"; import {VaultAdmin} from "./VaultAdmin.sol"; import {VaultState} from "./VaultState.sol"; import {VaultValidators} from "./VaultValidators.sol"; @@ -58,6 +59,17 @@ abstract contract VaultGnoStaking is shares = _deposit(receiver, assets, referrer); } + /// @inheritdoc IVaultGnoStaking + function donateAssets(uint256 amount) external override nonReentrant { + if (amount == 0) { + revert Errors.InvalidAssets(); + } + SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), amount); + + _donatedAssets += amount; + emit AssetsDonated(msg.sender, amount); + } + /// @inheritdoc VaultState function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override { super._processTotalAssetsDelta(assetsDelta); diff --git a/contracts/vaults/modules/VaultImmutables.sol b/contracts/vaults/modules/VaultImmutables.sol index 17a3ad3c..62e04b6d 100644 --- a/contracts/vaults/modules/VaultImmutables.sol +++ b/contracts/vaults/modules/VaultImmutables.sol @@ -33,7 +33,7 @@ abstract contract VaultImmutables { /** * @dev Internal method for checking whether the vault is harvested */ - function _checkHarvested() internal view { + function _checkHarvested() internal view virtual { if (IKeeperRewards(_keeper).isHarvestRequired(address(this))) revert Errors.NotHarvested(); } @@ -48,7 +48,7 @@ abstract contract VaultImmutables { * @dev Returns whether the vault is collateralized * @return true if the vault is collateralized */ - function _isCollateralized() internal view returns (bool) { + function _isCollateralized() internal view virtual returns (bool) { return IKeeperRewards(_keeper).isCollateralized(address(this)); } } diff --git a/contracts/vaults/modules/VaultMev.sol b/contracts/vaults/modules/VaultMev.sol index 35343b52..156f0e4c 100644 --- a/contracts/vaults/modules/VaultMev.sol +++ b/contracts/vaults/modules/VaultMev.sol @@ -41,10 +41,10 @@ abstract contract VaultMev is Initializable, VaultState, IVaultMev { function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) internal override - returns (int256, bool) + returns (int256 totalAssetsDelta, bool harvested) { - (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested) = - IKeeperRewards(_keeper).harvest(harvestParams); + uint256 unlockedMevDelta; + (totalAssetsDelta, unlockedMevDelta, harvested) = IKeeperRewards(_keeper).harvest(harvestParams); // harvest execution rewards only when consensus rewards were harvested if (!harvested) return (totalAssetsDelta, harvested); @@ -56,11 +56,17 @@ abstract contract VaultMev is Initializable, VaultState, IVaultMev { // withdraw assets from shared escrow only in case reward is positive ISharedMevEscrow(_mevEscrow).harvest(unlockedMevDelta); } - return (totalAssetsDelta, harvested); + } else { + // execution rewards are always equal to what was accumulated in own MEV escrow + totalAssetsDelta += int256(IOwnMevEscrow(_mevEscrow).harvest()); } - // execution rewards are always equal to what was accumulated in own MEV escrow - return (totalAssetsDelta + int256(IOwnMevEscrow(_mevEscrow).harvest()), harvested); + // SLOAD to memory + uint256 donatedAssets = _donatedAssets; + if (donatedAssets > 0) { + totalAssetsDelta += int256(donatedAssets); + _donatedAssets = 0; + } } /** diff --git a/contracts/vaults/modules/VaultState.sol b/contracts/vaults/modules/VaultState.sol index 4ea64edc..09337ab5 100644 --- a/contracts/vaults/modules/VaultState.sol +++ b/contracts/vaults/modules/VaultState.sol @@ -35,6 +35,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault uint128 internal _totalExitingAssets; // deprecated uint128 internal _totalExitingTickets; // deprecated uint256 internal _totalExitedTickets; // deprecated + uint256 internal _donatedAssets; /// @inheritdoc IVaultState function totalShares() external view override returns (uint256) { @@ -105,7 +106,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault } /// @inheritdoc IVaultState - function isStateUpdateRequired() external view override returns (bool) { + function isStateUpdateRequired() external view virtual override returns (bool) { return IKeeperRewards(_keeper).isHarvestRequired(address(this)); } @@ -343,5 +344,5 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[48] private __gap; + uint256[47] private __gap; } diff --git a/contracts/vaults/modules/VaultSubVaults.sol b/contracts/vaults/modules/VaultSubVaults.sol new file mode 100644 index 00000000..6b1a9cf3 --- /dev/null +++ b/contracts/vaults/modules/VaultSubVaults.sol @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {Packing} from "@openzeppelin/contracts/utils/Packing.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {DoubleEndedQueue} from "@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {IVaultsRegistry} from "../../interfaces/IVaultsRegistry.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; +import {IVaultEnterExit} from "../../interfaces/IVaultEnterExit.sol"; +import {ISubVaultsCurator} from "../../interfaces/ISubVaultsCurator.sol"; +import {IVaultSubVaults} from "../../interfaces/IVaultSubVaults.sol"; +import {ICuratorsRegistry} from "../../interfaces/ICuratorsRegistry.sol"; +import {ExitQueue} from "../../libraries/ExitQueue.sol"; +import {Errors} from "../../libraries/Errors.sol"; +import {VaultAdmin} from "./VaultAdmin.sol"; +import {VaultImmutables} from "./VaultImmutables.sol"; +import {VaultState, IVaultState} from "./VaultState.sol"; + +/** + * @title VaultSubVaults + * @author StakeWise + * @notice Defines the functionality for managing the Vault sub-vaults + */ +abstract contract VaultSubVaults is + VaultImmutables, + Initializable, + ReentrancyGuardUpgradeable, + VaultAdmin, + VaultState, + IVaultSubVaults +{ + using EnumerableSet for EnumerableSet.AddressSet; + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + + uint256 private constant _maxSubVaults = 50; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _curatorsRegistry; + + /// @inheritdoc IVaultSubVaults + address public override subVaultsCurator; + + /// @inheritdoc IVaultSubVaults + address public override ejectingSubVault; + + EnumerableSet.AddressSet internal _subVaults; + mapping(address vault => DoubleEndedQueue.Bytes32Deque) private _subVaultsExits; + mapping(address vault => SubVaultState state) private _subVaultsStates; + + uint256 private _totalProcessedExitQueueTickets; + uint128 private _subVaultsRewardsNonce; + uint128 private _subVaultsTotalAssets; + + uint256 private _ejectingSubVaultShares; + + /** + * @dev Constructor + * @dev Since the immutable variable value is stored in the bytecode, + * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. + * @param curatorsRegistry The address of the CuratorsRegistry contract + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address curatorsRegistry) { + _curatorsRegistry = curatorsRegistry; + } + + /// @inheritdoc IVaultSubVaults + function subVaultsStates(address vault) external view override returns (SubVaultState memory) { + return _subVaultsStates[vault]; + } + + /// @inheritdoc IVaultSubVaults + function getSubVaults() public view override returns (address[] memory) { + return _subVaults.values(); + } + + /// @inheritdoc IVaultSubVaults + function setSubVaultsCurator(address curator) external override { + _checkAdmin(); + _setSubVaultsCurator(curator); + } + + /// @inheritdoc IVaultSubVaults + function addSubVault(address vault) public virtual override { + _checkAdmin(); + // check whether the vault is registered in the registry + if (vault == address(0) || vault == address(this) || !IVaultsRegistry(_vaultsRegistry).vaults(vault)) { + revert Errors.InvalidVault(); + } + // check whether the vault is not already added + if (_subVaults.contains(vault)) { + revert Errors.AlreadyAdded(); + } + // check whether the vault is not exceeding the limit + uint256 subVaultsCount = _subVaults.length(); + if (subVaultsCount >= _maxSubVaults) { + revert Errors.CapacityExceeded(); + } + // check whether vault is collateralized + if (!IKeeperRewards(_keeper).isCollateralized(vault)) { + revert Errors.NotCollateralized(); + } + + // check whether legacy exit queue is processed, will revert if vault doesn't have `getExitQueueData` function + (,, uint128 totalExitingTickets, uint128 totalExitingAssets,) = IVaultState(vault).getExitQueueData(); + if (totalExitingTickets != 0 || totalExitingAssets != 0) { + revert Errors.ExitRequestNotProcessed(); + } + + // check harvested + (, uint256 vaultNonce) = IKeeperRewards(_keeper).rewards(vault); + uint256 lastSubVaultsRewardsNonce = _subVaultsRewardsNonce; + if (subVaultsCount == 0) { + _subVaultsRewardsNonce = SafeCast.toUint128(vaultNonce); + emit RewardsNonceUpdated(vaultNonce); + } else if (vaultNonce != lastSubVaultsRewardsNonce) { + revert Errors.NotHarvested(); + } + + // add the vault to the list of sub vaults + _subVaults.add(vault); + emit SubVaultAdded(msg.sender, vault); + } + + /// @inheritdoc IVaultSubVaults + function ejectSubVault(address vault) public virtual override { + _checkAdmin(); + + if (ejectingSubVault != address(0)) { + revert Errors.EjectingVault(); + } + if (!_subVaults.contains(vault)) { + revert Errors.AlreadyRemoved(); + } + if (_subVaults.length() == 1) { + revert Errors.EmptySubVaults(); + } + + // check the vault state + SubVaultState memory state = _subVaultsStates[vault]; + if (state.stakedShares > 0) { + // enter exit queue for all the vault staked shares + uint256 positionTicket = IVaultEnterExit(vault).enterExitQueue(state.stakedShares, address(this)); + // add ejecting shares to the vault's exit positions + _pushSubVaultExit(vault, SafeCast.toUint160(positionTicket), SafeCast.toUint96(state.stakedShares), false); + state.queuedShares += state.stakedShares; + } + + // update state + if (state.queuedShares > 0) { + ejectingSubVault = vault; + _ejectingSubVaultShares = state.stakedShares; + state.stakedShares = 0; + _subVaultsStates[vault] = state; + emit SubVaultEjecting(msg.sender, vault); + } else { + // no shares left + _subVaultsExits[vault].clear(); + // remove the vault from the list of sub vaults + _subVaults.remove(vault); + emit SubVaultEjected(msg.sender, vault); + } + } + + /// @inheritdoc IVaultState + function isStateUpdateRequired() public view virtual override returns (bool) { + // SLOAD to memory + uint256 currentNonce = IKeeperRewards(_keeper).rewardsNonce(); + uint256 subVaultsRewardsNonce = _subVaultsRewardsNonce; + unchecked { + // cannot overflow as nonce is uint64 + return subVaultsRewardsNonce + 1 < currentNonce; + } + } + + /// @inheritdoc IVaultSubVaults + function depositToSubVaults() external override nonReentrant { + _checkHarvested(); + + address[] memory vaults = getSubVaults(); + uint256 vaultsLength = vaults.length; + if (vaultsLength == 0) revert Errors.EmptySubVaults(); + + // deposit accumulated assets to sub vaults + uint256 availableAssets = withdrawableAssets(); + if (availableAssets == 0) { + revert Errors.InvalidAssets(); + } + ISubVaultsCurator.Deposit[] memory deposits = + ISubVaultsCurator(subVaultsCurator).getDeposits(availableAssets, vaults, ejectingSubVault); + + // process deposits + uint128 vaultShares; + ISubVaultsCurator.Deposit memory depositData; + + uint256 depositsLength = deposits.length; + // SLOAD to memory + uint256 subVaultsTotalAssets = _subVaultsTotalAssets; + for (uint256 i = 0; i < depositsLength;) { + depositData = deposits[i]; + if (depositData.assets == 0) { + // skip empty deposits + unchecked { + // cannot realistically overflow + ++i; + } + continue; + } + + // reverts if there are more deposits than available assets + availableAssets -= depositData.assets; + + // update state + vaultShares = SafeCast.toUint128(_depositToVault(depositData.vault, depositData.assets)); + _subVaultsStates[depositData.vault].stakedShares += vaultShares; + subVaultsTotalAssets += depositData.assets; + unchecked { + // cannot realistically overflow + ++i; + } + } + // update last sync sub vaults assets + _subVaultsTotalAssets = SafeCast.toUint128(subVaultsTotalAssets); + } + + /// @inheritdoc IVaultSubVaults + function claimSubVaultsExitedAssets(SubVaultExitRequest[] calldata exitRequests) external override { + uint256 leftShares; + uint256 exitedAssets; + uint256 exitedShares; + uint256 positionTicket; + uint256 positionShares; + SubVaultState memory subVaultState; + SubVaultExitRequest calldata exitRequest; + + uint256 exitRequestsLength = exitRequests.length; + // SLOAD to memory + uint256 subVaultsTotalAssets = _subVaultsTotalAssets; + address _ejectingSubVault = ejectingSubVault; + for (uint256 i = 0; i < exitRequestsLength;) { + exitRequest = exitRequests[i]; + subVaultState = _subVaultsStates[exitRequest.vault]; + (positionTicket, positionShares) = _popSubVaultExit(exitRequest.vault); + (leftShares, exitedShares, exitedAssets) = IVaultEnterExit(exitRequest.vault).calculateExitedAssets( + address(this), positionTicket, exitRequest.timestamp, exitRequest.exitQueueIndex + ); + + subVaultState.queuedShares -= SafeCast.toUint128(positionShares); + if (leftShares > 1) { + // exit request was not processed in full + _pushSubVaultExit( + exitRequest.vault, + SafeCast.toUint160(positionTicket + exitedShares), + SafeCast.toUint96(leftShares), + true + ); + subVaultState.queuedShares += SafeCast.toUint128(leftShares); + } + + // update total assets, vault state + subVaultsTotalAssets -= exitedAssets; + _subVaultsStates[exitRequest.vault] = subVaultState; + + // claim exited assets from the vault + IVaultEnterExit(exitRequest.vault).claimExitedAssets( + positionTicket, exitRequest.timestamp, exitRequest.exitQueueIndex + ); + if (_ejectingSubVault == exitRequest.vault && subVaultState.queuedShares == 0) { + // clean up ejecting vault + delete ejectingSubVault; + delete _ejectingSubVaultShares; + _subVaultsExits[exitRequest.vault].clear(); + _subVaults.remove(exitRequest.vault); + emit SubVaultEjected(msg.sender, exitRequest.vault); + } + + unchecked { + // cannot realistically overflow + ++i; + } + } + // update sub vaults total assets + _subVaultsTotalAssets = SafeCast.toUint128(subVaultsTotalAssets); + } + + /// @inheritdoc IVaultState + function updateState(IKeeperRewards.HarvestParams calldata) public virtual override { + // fetch all the vaults + address[] memory vaults = getSubVaults(); + uint256 vaultsLength = vaults.length; + if (vaultsLength == 0) revert Errors.EmptySubVaults(); + + // sync rewards nonce + bool isHarvested = _syncRewardsNonce(vaults); + if (!isHarvested) { + return; + } + + // check claims + _checkSubVaultsExitClaims(vaults); + + // calculate new total assets and save balances in each sub vault + address vault; + uint256 newSubVaultsTotalAssets; + uint256 vaultTotalShares; + SubVaultState memory vaultState; + uint256[] memory balances = new uint256[](vaultsLength); + for (uint256 i = 0; i < vaultsLength;) { + vault = vaults[i]; + vaultState = _subVaultsStates[vault]; + vaultTotalShares = vaultState.stakedShares + vaultState.queuedShares; + if (vaultTotalShares > 0) { + newSubVaultsTotalAssets += IVaultState(vault).convertToAssets(vaultTotalShares); + } + + if (vaultState.stakedShares > 0) { + balances[i] = IVaultState(vault).convertToAssets(vaultState.stakedShares); + } else { + balances[i] = 0; + } + unchecked { + // cannot realistically overflow + ++i; + } + } + + // store new sub vaults total assets delta + int256 totalAssetsDelta = SafeCast.toInt256(newSubVaultsTotalAssets) - SafeCast.toInt256(_subVaultsTotalAssets); + + // SLOAD to memory + uint256 donatedAssets = _donatedAssets; + if (donatedAssets > 0) { + totalAssetsDelta += int256(donatedAssets); + _donatedAssets = 0; + } + + _subVaultsTotalAssets = SafeCast.toUint128(newSubVaultsTotalAssets); + emit SubVaultsHarvested(totalAssetsDelta); + + _processTotalAssetsDelta(totalAssetsDelta); + + _updateExitQueue(); + + _enterSubVaultsExitQueue(vaults, balances); + } + + /// @inheritdoc VaultState + function _harvestAssets(IKeeperRewards.HarvestParams calldata) internal pure override returns (int256, bool) { + // not used + return (0, false); + } + + /** + * @dev Internal function to enter the exit queue for sub vaults + * @param vaults The addresses of the sub vaults + * @param balances The balances of the sub vaults + */ + function _enterSubVaultsExitQueue(address[] memory vaults, uint256[] memory balances) private nonReentrant { + // SLOAD to memory + uint256 totalExitedTickets = ExitQueue.getLatestTotalTickets(_exitQueue); + uint256 totalProcessedTickets = Math.max(_totalProcessedExitQueueTickets, totalExitedTickets); + + // calculate unprocessed exit queue tickets + uint256 unprocessedTickets = _queuedShares - (totalProcessedTickets - totalExitedTickets); + if (unprocessedTickets <= 1) { + // nothing to process + return; + } + + // update state + _totalProcessedExitQueueTickets = totalProcessedTickets + unprocessedTickets; + + // check whether ejecting vault has exiting assets + uint256 unprocessedAssets = convertToAssets(unprocessedTickets); + unprocessedAssets -= _consumeEjectingSubVaultAssets(unprocessedAssets); + if (unprocessedAssets == 0) { + return; + } + + // fetch exit requests from the curator + ISubVaultsCurator.ExitRequest[] memory exits = + ISubVaultsCurator(subVaultsCurator).getExitRequests(unprocessedAssets, vaults, balances, ejectingSubVault); + + // process exits + uint256 processedAssets; + uint256 vaultShares; + uint256 positionTicket; + SubVaultState memory vaultState; + ISubVaultsCurator.ExitRequest memory exitRequest; + + uint128 vaultShares128; + uint256 exitsLength = exits.length; + for (uint256 i = 0; i < exitsLength;) { + // submit exit request to the vault + exitRequest = exits[i]; + if (exitRequest.assets == 0) { + // skip empty exit requests + unchecked { + // cannot realistically overflow + ++i; + } + continue; + } + vaultState = _subVaultsStates[exitRequest.vault]; + vaultShares = IVaultState(exitRequest.vault).convertToShares(exitRequest.assets); + positionTicket = IVaultEnterExit(exitRequest.vault).enterExitQueue(vaultShares, address(this)); + + // save exit request + _pushSubVaultExit( + exitRequest.vault, SafeCast.toUint160(positionTicket), SafeCast.toUint96(vaultShares), false + ); + + // update state + vaultShares128 = SafeCast.toUint128(vaultShares); + vaultState.queuedShares += vaultShares128; + vaultState.stakedShares -= vaultShares128; + + _subVaultsStates[exitRequest.vault] = vaultState; + processedAssets += exitRequest.assets; + + unchecked { + // cannot realistically overflow + ++i; + } + } + if (processedAssets > unprocessedAssets) { + revert Errors.InvalidAssets(); + } + } + + /** + * @dev Internal function to check whether the sub vaults have claimed processed exit queue tickets + * @param vaults The addresses of the sub vaults + */ + function _checkSubVaultsExitClaims(address[] memory vaults) private view { + address vault; + uint256 totalExitedTickets; + uint256 positionTicket; + uint256 exitShares; + uint256 vaultsLength = vaults.length; + for (uint256 i = 0; i < vaultsLength;) { + vault = vaults[i]; + (positionTicket, exitShares) = _peekSubVaultExit(vault); + if (positionTicket == 0 && exitShares == 0) { + // no queue positions + unchecked { + // cannot realistically overflow + ++i; + } + continue; + } + (,,,, totalExitedTickets) = IVaultState(vault).getExitQueueData(); + if (totalExitedTickets > positionTicket) { + revert Errors.UnclaimedAssets(); + } + + unchecked { + // cannot realistically overflow + ++i; + } + } + } + + /** + * @dev Internal function to check whether the vaults are harvested + * @param vaults The addresses of the vaults + * @return Whether the nonce has been updated + */ + function _syncRewardsNonce(address[] memory vaults) private returns (bool) { + // process first vault in the array + address vault = vaults[0]; + (, uint256 vaultNonce) = IKeeperRewards(_keeper).rewards(vault); + + // check whether the first vault is harvested + uint256 currentNonce = IKeeperRewards(_keeper).rewardsNonce(); + if (vaultNonce + 1 < currentNonce) { + revert Errors.NotHarvested(); + } + + // fetch current nonce + currentNonce = vaultNonce; + uint256 lastRewardsNonce = _subVaultsRewardsNonce; + if (lastRewardsNonce > currentNonce) { + revert Errors.RewardsNonceIsHigher(); + } else if (lastRewardsNonce == currentNonce) { + return false; + } else { + // update last sync rewards nonce + _subVaultsRewardsNonce = SafeCast.toUint128(currentNonce); + emit RewardsNonceUpdated(currentNonce); + } + + // all the vaults must be with the same rewards nonce + uint256 vaultsLength = vaults.length; + for (uint256 i = 1; i < vaultsLength;) { + vault = vaults[i]; + (, vaultNonce) = IKeeperRewards(_keeper).rewards(vault); + + // check whether the vault is harvested + if (vaultNonce != currentNonce) { + revert Errors.NotHarvested(); + } + + unchecked { + // cannot realistically overflow + ++i; + } + } + return true; + } + + /** + * @dev Internal function to consume ejecting sub-vault assets + * @param unprocessedAssets The amount of unprocessed assets + * @return processedAssets The amount of processed assets + */ + function _consumeEjectingSubVaultAssets(uint256 unprocessedAssets) private returns (uint256 processedAssets) { + // SLOAD to memory + address _ejectingSubVault = ejectingSubVault; + if (_ejectingSubVault == address(0)) { + return 0; + } + uint256 ejectingSubVaultShares = _ejectingSubVaultShares; + if (ejectingSubVaultShares == 0) { + return 0; + } + + uint256 ejectingVaultAssets = IVaultState(_ejectingSubVault).convertToAssets(ejectingSubVaultShares); + processedAssets = Math.min(unprocessedAssets, ejectingVaultAssets); + + // update state + _ejectingSubVaultShares = + ejectingSubVaultShares - IVaultState(_ejectingSubVault).convertToShares(processedAssets); + } + + /** + * @dev Fetches the sub-vault exit data + * @param vault The address of the sub-vault + * @return positionTicket The position ticket of the sub-vault + * @return shares The shares to be exited from the sub-vault + */ + function _peekSubVaultExit(address vault) private view returns (uint160 positionTicket, uint96 shares) { + if (_subVaultsExits[vault].empty()) { + return (0, 0); + } + bytes32 packed = _subVaultsExits[vault].front(); + positionTicket = uint160(Packing.extract_32_20(packed, 0)); + shares = uint96(Packing.extract_32_12(packed, 20)); + } + + /** + * @dev Stores the sub-vault exit data + * @param vault The address of the sub-vault + * @param positionTicket The position ticket of the sub-vault + * @param shares The shares to be exited from the sub-vault + * @param front Whether to insert the exit data at the front of the queue + */ + function _pushSubVaultExit(address vault, uint160 positionTicket, uint96 shares, bool front) private { + if (shares == 0) revert Errors.InvalidShares(); + bytes32 packed = Packing.pack_20_12(bytes20(positionTicket), bytes12(shares)); + if (front) { + _subVaultsExits[vault].pushFront(packed); + } else { + _subVaultsExits[vault].pushBack(packed); + } + } + + /** + * @dev Removes the sub-vault exit data + * @param vault The address of the sub-vault + * @return positionTicket The position ticket of the sub-vault + * @return shares The shares to be exited from the sub-vault + */ + function _popSubVaultExit(address vault) private returns (uint160 positionTicket, uint96 shares) { + bytes32 packed = _subVaultsExits[vault].popFront(); + positionTicket = uint160(Packing.extract_32_20(packed, 0)); + shares = uint96(Packing.extract_32_12(packed, 20)); + } + + /// @inheritdoc VaultImmutables + function _checkHarvested() internal view virtual override { + if (isStateUpdateRequired()) { + revert Errors.NotHarvested(); + } + } + + /// @inheritdoc VaultImmutables + function _isCollateralized() internal view virtual override returns (bool) { + return _subVaults.length() > 0; + } + + /** + * @dev Internal function to set the sub-vaults curator + * @param curator The address of the sub-vaults curator + */ + function _setSubVaultsCurator(address curator) private { + if (curator == address(0)) revert Errors.ZeroAddress(); + if (curator == subVaultsCurator) revert Errors.ValueNotChanged(); + if (!ICuratorsRegistry(_curatorsRegistry).curators(curator)) { + revert Errors.InvalidCurator(); + } + subVaultsCurator = curator; + emit SubVaultsCuratorUpdated(msg.sender, curator); + } + + /** + * @dev Internal function to deposit assets to the vault + * @param vault The address of the vault + * @param assets The amount of assets to deposit + * @return The amount of vault shares received + */ + function _depositToVault(address vault, uint256 assets) internal virtual returns (uint256); + + /** + * @dev Initializes the VaultSubVaults contract + * @param curator The address of initial sub-vaults curator + */ + function __VaultSubVaults_init(address curator) internal onlyInitializing { + __ReentrancyGuard_init(); + _setSubVaultsCurator(curator); + _subVaultsRewardsNonce = IKeeperRewards(_keeper).rewardsNonce(); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable index 3d5fa5c2..60b305a8 160000 --- a/lib/openzeppelin-contracts-upgradeable +++ b/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit 3d5fa5c24c411112bab47bec25cfa9ad0af0e6e8 +Subproject commit 60b305a8f3ff0c7688f02ac470417b6bbf1c4d27 diff --git a/script/Network.sol b/script/Network.sol index c2dcc24f..e74df987 100644 --- a/script/Network.sol +++ b/script/Network.sol @@ -191,6 +191,8 @@ abstract contract Network is Script { address validatorsChecker, address consolidationsChecker, address rewardSplitterFactory, + address curatorsRegistry, + address balancedCurator, address gnoDaiDistributor ) internal { Deployment memory deployment = getDeploymentData(); @@ -211,6 +213,8 @@ abstract contract Network is Script { vm.serializeAddress(json, "LegacyPoolEscrow", deployment.legacyPoolEscrow); vm.serializeAddress(json, "LegacyRewardToken", deployment.legacyRewardToken); vm.serializeAddress(json, "MerkleDistributor", deployment.merkleDistributor); + vm.serializeAddress(json, "CuratorsRegistry", curatorsRegistry); + vm.serializeAddress(json, "BalancedCurator", balancedCurator); for (uint256 i = 0; i < newFactories.length; i++) { Factory memory factory = newFactories[i]; diff --git a/script/UpgradeEthNetwork.s.sol b/script/UpgradeEthNetwork.s.sol index 045e79c6..c8ac17b9 100644 --- a/script/UpgradeEthNetwork.s.sol +++ b/script/UpgradeEthNetwork.s.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.22; import {console} from "forge-std/console.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; import {IEthErc20Vault} from "../contracts/interfaces/IEthErc20Vault.sol"; import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; @@ -15,28 +16,38 @@ import {EthGenesisVault} from "../contracts/vaults/ethereum/EthGenesisVault.sol" import {EthPrivErc20Vault} from "../contracts/vaults/ethereum/EthPrivErc20Vault.sol"; import {EthPrivVault} from "../contracts/vaults/ethereum/EthPrivVault.sol"; import {EthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {EthMetaVault, IEthMetaVault} from "../contracts/vaults/ethereum/custom/EthMetaVault.sol"; import {EthVaultFactory} from "../contracts/vaults/ethereum/EthVaultFactory.sol"; +import {EthMetaVaultFactory} from "../contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol"; import {EthValidatorsChecker} from "../contracts/validators/EthValidatorsChecker.sol"; +import {CuratorsRegistry, ICuratorsRegistry} from "../contracts/curators/CuratorsRegistry.sol"; +import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; import {EthRewardSplitter} from "../contracts/misc/EthRewardSplitter.sol"; import {RewardSplitterFactory} from "../contracts/misc/RewardSplitterFactory.sol"; import {Network} from "./Network.sol"; contract UpgradeEthNetwork is Network { + address public metaVaultFactoryOwner; + address public consolidationsChecker; address public validatorsChecker; address public rewardSplitterFactory; + address public curatorsRegistry; + address public balancedCurator; address[] public vaultImpls; Factory[] public vaultFactories; function run() external { + metaVaultFactoryOwner = vm.envAddress("META_VAULT_FACTORY_OWNER"); uint256 privateKey = vm.envUint("PRIVATE_KEY"); address sender = vm.addr(privateKey); console.log("Deploying from: ", sender); - vm.startBroadcast(privateKey); Deployment memory deployment = getDeploymentData(); + vm.startBroadcast(privateKey); + // Deploy common contracts consolidationsChecker = address(new ConsolidationsChecker(deployment.keeper)); validatorsChecker = address( @@ -50,6 +61,12 @@ contract UpgradeEthNetwork is Network { address rewardsSplitterImpl = address(new EthRewardSplitter()); rewardSplitterFactory = address(new RewardSplitterFactory(rewardsSplitterImpl)); + // deploy curators + curatorsRegistry = address(new CuratorsRegistry()); + balancedCurator = address(new BalancedCurator()); + ICuratorsRegistry(curatorsRegistry).addCurator(balancedCurator); + ICuratorsRegistry(curatorsRegistry).initialize(Ownable(deployment.vaultsRegistry).owner()); + _deployImplementations(); _deployFactories(); vm.stopBroadcast(); @@ -57,7 +74,13 @@ contract UpgradeEthNetwork is Network { generateGovernorTxJson(vaultImpls, vaultFactories); generateUpgradesJson(vaultImpls); generateAddressesJson( - vaultFactories, validatorsChecker, consolidationsChecker, rewardSplitterFactory, address(0) + vaultFactories, + validatorsChecker, + consolidationsChecker, + rewardSplitterFactory, + curatorsRegistry, + balancedCurator, + address(0) ); } @@ -65,6 +88,7 @@ contract UpgradeEthNetwork is Network { // constructors for implementations IEthVault.EthVaultConstructorArgs memory vaultArgs = _getEthVaultConstructorArgs(); IEthErc20Vault.EthErc20VaultConstructorArgs memory erc20VaultArgs = _getEthErc20VaultConstructorArgs(); + IEthMetaVault.EthMetaVaultConstructorArgs memory metaVaultArgs = _getEthMetaVaultConstructorArgs(); Deployment memory deployment = getDeploymentData(); // update exited assets claim delay for public vaults @@ -91,6 +115,9 @@ contract UpgradeEthNetwork is Network { EthPrivVault ethPrivVault = new EthPrivVault(vaultArgs); EthPrivErc20Vault ethPrivErc20Vault = new EthPrivErc20Vault(erc20VaultArgs); + // deploy MetaVault + EthMetaVault ethMetaVault = new EthMetaVault(metaVaultArgs); + vaultImpls.push(address(ethGenesisVault)); vaultImpls.push(address(ethVault)); vaultImpls.push(address(ethErc20Vault)); @@ -98,6 +125,7 @@ contract UpgradeEthNetwork is Network { vaultImpls.push(address(ethBlocklistErc20Vault)); vaultImpls.push(address(ethPrivVault)); vaultImpls.push(address(ethPrivErc20Vault)); + vaultImpls.push(address(ethMetaVault)); } function _deployFactories() internal { @@ -111,19 +139,30 @@ contract UpgradeEthNetwork is Network { continue; } - EthVaultFactory factory = new EthVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry)); + address factory; + if (vaultId == keccak256("EthMetaVault")) { + factory = address( + new EthMetaVaultFactory( + metaVaultFactoryOwner, vaultImpl, IVaultsRegistry(deployment.vaultsRegistry) + ) + ); + vaultFactories.push(Factory({name: "MetaVaultFactory", factory: factory})); + continue; + } + + factory = address(new EthVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry))); if (vaultId == keccak256("EthVault")) { - vaultFactories.push(Factory({name: "VaultFactory", factory: address(factory)})); + vaultFactories.push(Factory({name: "VaultFactory", factory: factory})); } else if (vaultId == keccak256("EthErc20Vault")) { - vaultFactories.push(Factory({name: "Erc20VaultFactory", factory: address(factory)})); + vaultFactories.push(Factory({name: "Erc20VaultFactory", factory: factory})); } else if (vaultId == keccak256("EthBlocklistVault")) { - vaultFactories.push(Factory({name: "BlocklistVaultFactory", factory: address(factory)})); + vaultFactories.push(Factory({name: "BlocklistVaultFactory", factory: factory})); } else if (vaultId == keccak256("EthPrivVault")) { - vaultFactories.push(Factory({name: "PrivVaultFactory", factory: address(factory)})); + vaultFactories.push(Factory({name: "PrivVaultFactory", factory: factory})); } else if (vaultId == keccak256("EthBlocklistErc20Vault")) { - vaultFactories.push(Factory({name: "BlocklistErc20VaultFactory", factory: address(factory)})); + vaultFactories.push(Factory({name: "BlocklistErc20VaultFactory", factory: factory})); } else if (vaultId == keccak256("EthPrivErc20Vault")) { - vaultFactories.push(Factory({name: "PrivErc20VaultFactory", factory: address(factory)})); + vaultFactories.push(Factory({name: "PrivErc20VaultFactory", factory: factory})); } } } @@ -163,4 +202,17 @@ contract UpgradeEthNetwork is Network { exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } + + function _getEthMetaVaultConstructorArgs() internal returns (IEthMetaVault.EthMetaVaultConstructorArgs memory) { + Deployment memory deployment = getDeploymentData(); + return IEthMetaVault.EthMetaVaultConstructorArgs({ + keeper: deployment.keeper, + vaultsRegistry: deployment.vaultsRegistry, + osTokenVaultController: deployment.osTokenVaultController, + osTokenConfig: deployment.osTokenConfig, + osTokenVaultEscrow: deployment.osTokenVaultEscrow, + curatorsRegistry: curatorsRegistry, + exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } } diff --git a/script/UpgradeGnoNetwork.s.sol b/script/UpgradeGnoNetwork.s.sol index 6cfa4643..32dbcffd 100644 --- a/script/UpgradeGnoNetwork.s.sol +++ b/script/UpgradeGnoNetwork.s.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.22; import {console} from "forge-std/console.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IGnoVault} from "../contracts/interfaces/IGnoVault.sol"; import {IGnoErc20Vault} from "../contracts/interfaces/IGnoErc20Vault.sol"; import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; @@ -19,26 +20,36 @@ import {GnoBlocklistVault} from "../contracts/vaults/gnosis/GnoBlocklistVault.so import {GnoBlocklistErc20Vault} from "../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol"; import {GnoPrivVault} from "../contracts/vaults/gnosis/GnoPrivVault.sol"; import {GnoPrivErc20Vault} from "../contracts/vaults/gnosis/GnoPrivErc20Vault.sol"; +import {IGnoMetaVault, GnoMetaVault} from "../contracts/vaults/gnosis/custom/GnoMetaVault.sol"; import {GnoVaultFactory} from "../contracts/vaults/gnosis/GnoVaultFactory.sol"; +import {GnoMetaVaultFactory} from "../contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol"; +import {CuratorsRegistry, ICuratorsRegistry} from "../contracts/curators/CuratorsRegistry.sol"; +import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; import {Network} from "./Network.sol"; contract UpgradeGnoNetwork is Network { + address public metaVaultFactoryOwner; + address public consolidationsChecker; address public validatorsChecker; address public rewardSplitterFactory; address public gnoDaiDistributor; + address public curatorsRegistry; + address public balancedCurator; address[] public vaultImpls; Factory[] public vaultFactories; function run() external { + metaVaultFactoryOwner = vm.envAddress("META_VAULT_FACTORY_OWNER"); uint256 privateKey = vm.envUint("PRIVATE_KEY"); address sender = vm.addr(privateKey); console.log("Deploying from: ", sender); - vm.startBroadcast(privateKey); Deployment memory deployment = getDeploymentData(); + vm.startBroadcast(privateKey); + // Deploy common contracts consolidationsChecker = address(new ConsolidationsChecker(deployment.keeper)); validatorsChecker = address( @@ -61,6 +72,12 @@ contract UpgradeGnoNetwork is Network { ) ); + // deploy curators + curatorsRegistry = address(new CuratorsRegistry()); + balancedCurator = address(new BalancedCurator()); + ICuratorsRegistry(curatorsRegistry).addCurator(balancedCurator); + ICuratorsRegistry(curatorsRegistry).initialize(Ownable(deployment.vaultsRegistry).owner()); + _deployImplementations(); _deployFactories(); vm.stopBroadcast(); @@ -68,7 +85,13 @@ contract UpgradeGnoNetwork is Network { generateGovernorTxJson(vaultImpls, vaultFactories); generateUpgradesJson(vaultImpls); generateAddressesJson( - vaultFactories, validatorsChecker, consolidationsChecker, rewardSplitterFactory, gnoDaiDistributor + vaultFactories, + validatorsChecker, + consolidationsChecker, + rewardSplitterFactory, + curatorsRegistry, + balancedCurator, + gnoDaiDistributor ); } @@ -76,6 +99,7 @@ contract UpgradeGnoNetwork is Network { // constructors for implementations IGnoVault.GnoVaultConstructorArgs memory vaultArgs = _getGnoVaultConstructorArgs(); IGnoErc20Vault.GnoErc20VaultConstructorArgs memory erc20VaultArgs = _getGnoErc20VaultConstructorArgs(); + IGnoMetaVault.GnoMetaVaultConstructorArgs memory metaVaultArgs = _getGnoMetaVaultConstructorArgs(); Deployment memory deployment = getDeploymentData(); // update exited assets claim delay for public vaults @@ -102,6 +126,9 @@ contract UpgradeGnoNetwork is Network { GnoPrivVault gnoPrivVault = new GnoPrivVault(vaultArgs); GnoPrivErc20Vault gnoPrivErc20Vault = new GnoPrivErc20Vault(erc20VaultArgs); + // deploy MetaVault + GnoMetaVault gnoMetaVault = new GnoMetaVault(metaVaultArgs); + vaultImpls.push(address(gnoGenesisVault)); vaultImpls.push(address(gnoVault)); vaultImpls.push(address(gnoErc20Vault)); @@ -109,6 +136,7 @@ contract UpgradeGnoNetwork is Network { vaultImpls.push(address(gnoBlocklistErc20Vault)); vaultImpls.push(address(gnoPrivVault)); vaultImpls.push(address(gnoPrivErc20Vault)); + vaultImpls.push(address(gnoMetaVault)); } function _deployFactories() internal { @@ -122,8 +150,22 @@ contract UpgradeGnoNetwork is Network { continue; } - GnoVaultFactory factory = - new GnoVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry), deployment.gnoToken); + address factory; + if (vaultId == keccak256("GnoMetaVault")) { + factory = address( + new GnoMetaVaultFactory( + metaVaultFactoryOwner, + vaultImpl, + IVaultsRegistry(deployment.vaultsRegistry), + deployment.gnoToken + ) + ); + vaultFactories.push(Factory({name: "MetaVaultFactory", factory: factory})); + continue; + } + + factory = + address(new GnoVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry), deployment.gnoToken)); if (vaultId == keccak256("GnoVault")) { vaultFactories.push(Factory({name: "VaultFactory", factory: address(factory)})); } else if (vaultId == keccak256("GnoErc20Vault")) { @@ -179,4 +221,18 @@ contract UpgradeGnoNetwork is Network { exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } + + function _getGnoMetaVaultConstructorArgs() internal returns (IGnoMetaVault.GnoMetaVaultConstructorArgs memory) { + Deployment memory deployment = getDeploymentData(); + return IGnoMetaVault.GnoMetaVaultConstructorArgs({ + keeper: deployment.keeper, + vaultsRegistry: deployment.vaultsRegistry, + osTokenVaultController: deployment.osTokenVaultController, + osTokenConfig: deployment.osTokenConfig, + osTokenVaultEscrow: deployment.osTokenVaultEscrow, + curatorsRegistry: curatorsRegistry, + gnoToken: deployment.gnoToken, + exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY + }); + } } diff --git a/snapshots/ConsolidationsCheckerTest.json b/snapshots/ConsolidationsCheckerTest.json index d0c75124..973e8faf 100644 --- a/snapshots/ConsolidationsCheckerTest.json +++ b/snapshots/ConsolidationsCheckerTest.json @@ -1,12 +1,12 @@ { - "ConsolidationsCheckerTest_test_verifySignatures_differentValidatorData": "14287", - "ConsolidationsCheckerTest_test_verifySignatures_differentVault": "14178", - "ConsolidationsCheckerTest_test_verifySignatures_emptySignatures": "14926", - "ConsolidationsCheckerTest_test_verifySignatures_exactMinimumSignatures": "29006", - "ConsolidationsCheckerTest_test_verifySignatures_moreThanMinimumSignatures": "29019", - "ConsolidationsCheckerTest_test_verifySignatures_nonOracleSigner": "26426", - "ConsolidationsCheckerTest_test_verifySignatures_repeatedSigner": "23008", - "ConsolidationsCheckerTest_test_verifySignatures_success": "29008", - "ConsolidationsCheckerTest_test_verifySignatures_tooFewSignatures": "10954", - "ConsolidationsCheckerTest_test_verifySignatures_unsortedSignatures": "23004" + "ConsolidationsCheckerTest_test_verifySignatures_differentValidatorData": "23287", + "ConsolidationsCheckerTest_test_verifySignatures_differentVault": "21178", + "ConsolidationsCheckerTest_test_verifySignatures_emptySignatures": "17426", + "ConsolidationsCheckerTest_test_verifySignatures_exactMinimumSignatures": "38006", + "ConsolidationsCheckerTest_test_verifySignatures_moreThanMinimumSignatures": "38019", + "ConsolidationsCheckerTest_test_verifySignatures_nonOracleSigner": "28926", + "ConsolidationsCheckerTest_test_verifySignatures_repeatedSigner": "25508", + "ConsolidationsCheckerTest_test_verifySignatures_success": "38008", + "ConsolidationsCheckerTest_test_verifySignatures_tooFewSignatures": "13454", + "ConsolidationsCheckerTest_test_verifySignatures_unsortedSignatures": "25504" } \ No newline at end of file diff --git a/snapshots/DepositDataRegistryTest.json b/snapshots/DepositDataRegistryTest.json index 372ec10f..1b6aec12 100644 --- a/snapshots/DepositDataRegistryTest.json +++ b/snapshots/DepositDataRegistryTest.json @@ -1,9 +1,9 @@ { - "DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator": "272901", - "DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator": "295827", - "DepositDataRegistryTest_test_registerValidators_successWith0x01Validators": "314466", - "DepositDataRegistryTest_test_registerValidators_successWith0x02Validators": "338559", - "DepositDataRegistryTest_test_setDepositDataManager_succeeds": "64228", - "DepositDataRegistryTest_test_setDepositDataRoot_succeeds": "65149", - "DepositDataRegistryTest_test_updateVaultState_succeeds": "124118" + "DepositDataRegistryTest_test_registerValidator_succeedsWith0x01Validator": "272944", + "DepositDataRegistryTest_test_registerValidator_succeedsWith0x02Validator": "295870", + "DepositDataRegistryTest_test_registerValidators_successWith0x01Validators": "314505", + "DepositDataRegistryTest_test_registerValidators_successWith0x02Validators": "338614", + "DepositDataRegistryTest_test_setDepositDataManager_succeeds": "66206", + "DepositDataRegistryTest_test_setDepositDataRoot_succeeds": "65127", + "DepositDataRegistryTest_test_updateVaultState_succeeds": "128282" } \ No newline at end of file diff --git a/snapshots/EthBlocklistErc20VaultTest.json b/snapshots/EthBlocklistErc20VaultTest.json index ed706cf0..a9c24e75 100644 --- a/snapshots/EthBlocklistErc20VaultTest.json +++ b/snapshots/EthBlocklistErc20VaultTest.json @@ -1,8 +1,8 @@ { - "EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "89859", - "EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "84237", - "EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161438", - "EthBlocklistErc20VaultTest_test_deploysCorrectly": "623706", - "EthBlocklistErc20VaultTest_test_transfer": "61633", - "EthBlocklistErc20VaultTest_test_upgradesCorrectly": "73633" + "EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "89924", + "EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "84302", + "EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161501", + "EthBlocklistErc20VaultTest_test_deploysCorrectly": "624840", + "EthBlocklistErc20VaultTest_test_transfer": "61693", + "EthBlocklistErc20VaultTest_test_upgradesCorrectly": "89964" } \ No newline at end of file diff --git a/snapshots/EthBlocklistVaultTest.json b/snapshots/EthBlocklistVaultTest.json index 1d84cad3..0751aa6e 100644 --- a/snapshots/EthBlocklistVaultTest.json +++ b/snapshots/EthBlocklistVaultTest.json @@ -1,7 +1,7 @@ { - "EthBlocklistVaultTest_test_canDepositAsNonBlockedUser": "87906", - "EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "82295", - "EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161420", - "EthBlocklistVaultTest_test_deploysCorrectly": "548654", - "EthBlocklistVaultTest_test_upgradesCorrectly": "72962" + "EthBlocklistVaultTest_test_canDepositAsNonBlockedUser": "87971", + "EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "82360", + "EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161505", + "EthBlocklistVaultTest_test_deploysCorrectly": "549641", + "EthBlocklistVaultTest_test_upgradesCorrectly": "89295" } \ No newline at end of file diff --git a/snapshots/EthErc20VaultTest.json b/snapshots/EthErc20VaultTest.json index bf03275c..f9bf973f 100644 --- a/snapshots/EthErc20VaultTest.json +++ b/snapshots/EthErc20VaultTest.json @@ -1,16 +1,16 @@ { - "EthErc20VaultTest_test_canTransferFromSharesWithHighLtv": "89925", - "EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96456", - "EthErc20VaultTest_test_deploysCorrectly": "453478", - "EthErc20VaultTest_test_depositAndMintOsToken": "199052", - "EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer": "75386", - "EthErc20VaultTest_test_deposit_emitsTransfer": "78848", + "EthErc20VaultTest_test_canTransferFromSharesWithHighLtv": "90077", + "EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96608", + "EthErc20VaultTest_test_deploysCorrectly": "454568", + "EthErc20VaultTest_test_depositAndMintOsToken": "201247", + "EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer": "75451", + "EthErc20VaultTest_test_deposit_emitsTransfer": "78913", "EthErc20VaultTest_test_enterExitQueue_emitsTransfer": "89780", - "EthErc20VaultTest_test_redeem_emitsEvent": "58220", - "EthErc20VaultTest_test_updateExitQueue_emitsTransfer": "172131", - "EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken": "223176", - "EthErc20VaultTest_test_upgradesCorrectly": "73506", - "EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "74987", - "EthErc20VaultTest_test_withdrawValidator_unknown": "56828", - "EthErc20VaultTest_test_withdrawValidator_validatorsManager": "69759" + "EthErc20VaultTest_test_redeem_emitsEvent": "58285", + "EthErc20VaultTest_test_updateExitQueue_emitsTransfer": "177057", + "EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken": "227515", + "EthErc20VaultTest_test_upgradesCorrectly": "89838", + "EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "79487", + "EthErc20VaultTest_test_withdrawValidator_unknown": "61328", + "EthErc20VaultTest_test_withdrawValidator_validatorsManager": "74259" } \ No newline at end of file diff --git a/snapshots/EthFoxVaultTest.json b/snapshots/EthFoxVaultTest.json index 5e947770..911ba599 100644 --- a/snapshots/EthFoxVaultTest.json +++ b/snapshots/EthFoxVaultTest.json @@ -1,8 +1,8 @@ { - "EthFoxVaultTest_test_canDepositAsNonBlockedUser": "85500", - "EthFoxVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "79867", - "EthFoxVaultTest_test_ejectUser": "101192", - "EthFoxVaultTest_test_ejectUserWithNoShares": "58862", - "EthFoxVaultTest_test_withdrawValidator_unknown": "51498", - "EthFoxVaultTest_test_withdrawValidator_validatorsManager": "69605" + "EthFoxVaultTest_test_canDepositAsNonBlockedUser": "87565", + "EthFoxVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "81932", + "EthFoxVaultTest_test_ejectUser": "107257", + "EthFoxVaultTest_test_ejectUserWithNoShares": "62862", + "EthFoxVaultTest_test_withdrawValidator_unknown": "55998", + "EthFoxVaultTest_test_withdrawValidator_validatorsManager": "74105" } \ No newline at end of file diff --git a/snapshots/EthGenesisVaultTest.json b/snapshots/EthGenesisVaultTest.json index 80f07348..f4b2ad93 100644 --- a/snapshots/EthGenesisVaultTest.json +++ b/snapshots/EthGenesisVaultTest.json @@ -1,8 +1,8 @@ { - "EthGenesisVaultTest_test_claimsPoolEscrowAssets": "77684", + "EthGenesisVaultTest_test_claimsPoolEscrowAssets": "77662", "EthGenesisVaultTest_test_fallback_acceptsEtherFromPoolEscrow": "33277", - "EthGenesisVaultTest_test_fallback_acceptsEtherFromUser": "75475", - "EthGenesisVaultTest_test_migrate_works": "199287", - "EthGenesisVaultTest_test_upgradesCorrectly": "5106070", - "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "761161" + "EthGenesisVaultTest_test_fallback_acceptsEtherFromUser": "77540", + "EthGenesisVaultTest_test_migrate_works": "201699", + "EthGenesisVaultTest_test_upgradesCorrectly": "68918", + "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "803804" } \ No newline at end of file diff --git a/snapshots/EthMetaVaultTest.json b/snapshots/EthMetaVaultTest.json new file mode 100644 index 00000000..07bd3293 --- /dev/null +++ b/snapshots/EthMetaVaultTest.json @@ -0,0 +1,9 @@ +{ + "EthMetaVaultTest_test_deposit": "82922", + "EthMetaVaultTest_test_depositAndMintOsToken": "179830", + "EthMetaVaultTest_test_depositViaFallback": "79603", + "EthMetaVaultTest_test_isStateUpdateRequired_true": "138006", + "EthMetaVaultTest_test_updateStateAndDeposit": "172844", + "EthMetaVaultTest_test_updateStateAndDepositAndMintOsToken": "192890", + "EthMetaVaultTest_test_userClaimExitedAssets": "54314" +} \ No newline at end of file diff --git a/snapshots/EthOsTokenVaultEscrowTest.json b/snapshots/EthOsTokenVaultEscrowTest.json index 4e5ceb26..413fcbe7 100644 --- a/snapshots/EthOsTokenVaultEscrowTest.json +++ b/snapshots/EthOsTokenVaultEscrowTest.json @@ -1,35 +1,35 @@ { "EthOsTokenVaultEscrowTest_test_claimExitedAssets_insufficientShares": "66982", - "EthOsTokenVaultEscrowTest_test_claimExitedAssets_minimalAmount": "88563", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_minimalAmount": "92563", "EthOsTokenVaultEscrowTest_test_claimExitedAssets_noProcessedAssets": "91451", "EthOsTokenVaultEscrowTest_test_claimExitedAssets_nonExistentPosition": "50879", "EthOsTokenVaultEscrowTest_test_claimExitedAssets_notOwner": "65015", - "EthOsTokenVaultEscrowTest_test_claimExitedAssets_withFeeAccrual": "97458", - "EthOsTokenVaultEscrowTest_test_processExitedAssets_claimExitedAssets": "73940", - "EthOsTokenVaultEscrowTest_test_processExitedAssets_exitRequestNotProcessed": "45228", + "EthOsTokenVaultEscrowTest_test_claimExitedAssets_withFeeAccrual": "101458", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_claimExitedAssets": "77940", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_exitRequestNotProcessed": "49728", "EthOsTokenVaultEscrowTest_test_processExitedAssets_invalidPosition": "33255", - "EthOsTokenVaultEscrowTest_test_processExitedAssets_partialClaim": "89137", - "EthOsTokenVaultEscrowTest_test_processExitedAssets_success": "68617", - "EthOsTokenVaultEscrowTest_test_register_accessDenied": "29199", - "EthOsTokenVaultEscrowTest_test_register_directCall": "79100", - "EthOsTokenVaultEscrowTest_test_register_fullFlow": "163681", - "EthOsTokenVaultEscrowTest_test_register_invalidShares": "29242", - "EthOsTokenVaultEscrowTest_test_register_zeroAddress": "28886", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_partialClaim": "93137", + "EthOsTokenVaultEscrowTest_test_processExitedAssets_success": "71247", + "EthOsTokenVaultEscrowTest_test_register_accessDenied": "31199", + "EthOsTokenVaultEscrowTest_test_register_directCall": "81100", + "EthOsTokenVaultEscrowTest_test_register_fullFlow": "163659", + "EthOsTokenVaultEscrowTest_test_register_invalidShares": "31242", + "EthOsTokenVaultEscrowTest_test_register_zeroAddress": "30886", "EthOsTokenVaultEscrowTest_test_setAuthenticator_onlyOwner": "30174", - "EthOsTokenVaultEscrowTest_test_setAuthenticator_success": "31014", - "EthOsTokenVaultEscrowTest_test_setAuthenticator_valueNotChanged": "27509", + "EthOsTokenVaultEscrowTest_test_setAuthenticator_success": "33014", + "EthOsTokenVaultEscrowTest_test_setAuthenticator_valueNotChanged": "29509", "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_high": "27548", - "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_low": "25626", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidBonus_low": "27626", "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_max": "27337", - "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_zero": "25470", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_invalidThreshold_zero": "27470", "EthOsTokenVaultEscrowTest_test_updateLiqConfig_onlyOwner": "30318", - "EthOsTokenVaultEscrowTest_test_updateLiqConfig_success": "36745", - "OsTokenLiquidationTest_test_liquidateOsToken_invalidHealthFactor": "45969", + "EthOsTokenVaultEscrowTest_test_updateLiqConfig_success": "38745", + "OsTokenLiquidationTest_test_liquidateOsToken_invalidHealthFactor": "49969", "OsTokenLiquidationTest_test_liquidateOsToken_invalidPosition": "41078", "OsTokenLiquidationTest_test_liquidateOsToken_invalidReceivedAssets": "41999", - "OsTokenLiquidationTest_test_liquidateOsToken_partialLiquidation": "88124", - "OsTokenLiquidationTest_test_liquidateOsToken_success": "92795", + "OsTokenLiquidationTest_test_liquidateOsToken_partialLiquidation": "94624", + "OsTokenLiquidationTest_test_liquidateOsToken_success": "97295", "OsTokenLiquidationTest_test_liquidateOsToken_zeroAddress": "24032", "OsTokenLiquidationTest_test_redeemOsToken_notRedeemer": "27478", - "OsTokenLiquidationTest_test_redeemOsToken_success": "114222" + "OsTokenLiquidationTest_test_redeemOsToken_success": "118722" } \ No newline at end of file diff --git a/snapshots/EthPrivErc20VaultTest.json b/snapshots/EthPrivErc20VaultTest.json index 7af30373..1b23fad6 100644 --- a/snapshots/EthPrivErc20VaultTest.json +++ b/snapshots/EthPrivErc20VaultTest.json @@ -1,9 +1,9 @@ { - "EthPrivErc20VaultTest_test_canDepositAndMintOsTokenAsWhitelistedUser": "201938", - "EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "81342", - "EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "77628", - "EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161538", - "EthPrivErc20VaultTest_test_deploysCorrectly": "623640", - "EthPrivErc20VaultTest_test_transfer": "59649", - "EthPrivErc20VaultTest_test_upgradesCorrectly": "73654" + "EthPrivErc20VaultTest_test_canDepositAndMintOsTokenAsWhitelistedUser": "206655", + "EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "81407", + "EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "77693", + "EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161601", + "EthPrivErc20VaultTest_test_deploysCorrectly": "624862", + "EthPrivErc20VaultTest_test_transfer": "59709", + "EthPrivErc20VaultTest_test_upgradesCorrectly": "89984" } \ No newline at end of file diff --git a/snapshots/EthPrivVaultTest.json b/snapshots/EthPrivVaultTest.json index cfce8501..9c4cb000 100644 --- a/snapshots/EthPrivVaultTest.json +++ b/snapshots/EthPrivVaultTest.json @@ -1,11 +1,11 @@ { - "EthPrivVaultTest_test_canDepositAsWhitelistedUser": "79378", - "EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "75792", - "EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161520", - "EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser": "131935", - "EthPrivVaultTest_test_deploysCorrectly": "548676", - "EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser": "200374", + "EthPrivVaultTest_test_canDepositAsWhitelistedUser": "79443", + "EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "75857", + "EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161605", + "EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser": "138167", + "EthPrivVaultTest_test_deploysCorrectly": "549659", + "EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser": "200547", "EthPrivVaultTest_test_setWhitelister": "36458", "EthPrivVaultTest_test_updateWhitelist": "54543", - "EthPrivVaultTest_test_upgradesCorrectly": "73077" + "EthPrivVaultTest_test_upgradesCorrectly": "89410" } \ No newline at end of file diff --git a/snapshots/EthRewardSplitterTest.json b/snapshots/EthRewardSplitterTest.json index 81eec665..88016e6f 100644 --- a/snapshots/EthRewardSplitterTest.json +++ b/snapshots/EthRewardSplitterTest.json @@ -1,14 +1,14 @@ { - "EthRewardSplitter_claimExitedAssetsOnBehalf": "633820", - "EthRewardSplitter_claimVaultTokens": "664642", - "EthRewardSplitter_decreaseShares": "74619", - "EthRewardSplitter_enterExitQueue": "149228", - "EthRewardSplitter_enterExitQueueMaxWithdrawal": "126886", - "EthRewardSplitter_enterExitQueueOnBehalf": "844484", - "EthRewardSplitter_increaseShares": "73136", + "EthRewardSplitter_claimExitedAssetsOnBehalf": "749259", + "EthRewardSplitter_claimVaultTokens": "756516", + "EthRewardSplitter_decreaseShares": "87684", + "EthRewardSplitter_enterExitQueue": "166923", + "EthRewardSplitter_enterExitQueueMaxWithdrawal": "128951", + "EthRewardSplitter_enterExitQueueOnBehalf": "906700", + "EthRewardSplitter_increaseShares": "73201", "EthRewardSplitter_receiveEth": "31194", "EthRewardSplitter_setClaimOnBehalf": "65579", - "EthRewardSplitter_syncRewards": "75668", - "EthRewardSplitter_syncRewardsDetailed": "73168", - "EthRewardSplitter_updateVaultState": "130309" + "EthRewardSplitter_syncRewards": "77733", + "EthRewardSplitter_syncRewardsDetailed": "75233", + "EthRewardSplitter_updateVaultState": "132605" } \ No newline at end of file diff --git a/snapshots/EthVaultTest.json b/snapshots/EthVaultTest.json index 13232b15..83740b8e 100644 --- a/snapshots/EthVaultTest.json +++ b/snapshots/EthVaultTest.json @@ -1,11 +1,11 @@ { - "EthVaultTest_test_deploysCorrectly": "378482", - "EthVaultTest_test_depositAndMintOsToken": "197331", - "EthVaultTest_test_exitQueue_works": "94643", - "EthVaultTest_test_fallbackDeposit": "73062", - "EthVaultTest_test_updateStateAndDepositAndMintOsToken": "221431", - "EthVaultTest_test_upgradesCorrectly": "72923", - "EthVaultTest_test_withdrawValidator_osTokenRedeemer": "75020", - "EthVaultTest_test_withdrawValidator_unknown": "56861", - "EthVaultTest_test_withdrawValidator_validatorsManager": "69781" + "EthVaultTest_test_deploysCorrectly": "379445", + "EthVaultTest_test_depositAndMintOsToken": "199548", + "EthVaultTest_test_exitQueue_works": "96643", + "EthVaultTest_test_fallbackDeposit": "75127", + "EthVaultTest_test_updateStateAndDepositAndMintOsToken": "228138", + "EthVaultTest_test_upgradesCorrectly": "89254", + "EthVaultTest_test_withdrawValidator_osTokenRedeemer": "79520", + "EthVaultTest_test_withdrawValidator_unknown": "61361", + "EthVaultTest_test_withdrawValidator_validatorsManager": "74281" } \ No newline at end of file diff --git a/snapshots/GnoBlocklistErc20VaultTest.json b/snapshots/GnoBlocklistErc20VaultTest.json index 097507e6..67e57acc 100644 --- a/snapshots/GnoBlocklistErc20VaultTest.json +++ b/snapshots/GnoBlocklistErc20VaultTest.json @@ -1,7 +1,7 @@ { - "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "162425", - "GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161480", - "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "779115", - "GnoBlocklistErc20VaultTest_test_transfer": "61633", - "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "113240" + "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "162532", + "GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161610", + "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "780245", + "GnoBlocklistErc20VaultTest_test_transfer": "61693", + "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "132219" } \ No newline at end of file diff --git a/snapshots/GnoBlocklistVaultTest.json b/snapshots/GnoBlocklistVaultTest.json index bd85373a..7039dee8 100644 --- a/snapshots/GnoBlocklistVaultTest.json +++ b/snapshots/GnoBlocklistVaultTest.json @@ -1,6 +1,6 @@ { - "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "160483", - "GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161462", - "GnoBlocklistVaultTest_test_deploysCorrectly": "527708", - "GnoBlocklistVaultTest_test_upgradesCorrectly": "112603" + "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "160548", + "GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161570", + "GnoBlocklistVaultTest_test_deploysCorrectly": "528645", + "GnoBlocklistVaultTest_test_upgradesCorrectly": "131539" } \ No newline at end of file diff --git a/snapshots/GnoErc20VaultTest.json b/snapshots/GnoErc20VaultTest.json index ac838de3..2744582c 100644 --- a/snapshots/GnoErc20VaultTest.json +++ b/snapshots/GnoErc20VaultTest.json @@ -1,12 +1,12 @@ { - "GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv": "89970", - "GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96507", - "GnoErc20VaultTest_test_deploysCorrectly": "578930", - "GnoErc20VaultTest_test_deposit_emitsTransfer": "100622", + "GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv": "90100", + "GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96637", + "GnoErc20VaultTest_test_deploysCorrectly": "579952", + "GnoErc20VaultTest_test_deposit_emitsTransfer": "100687", "GnoErc20VaultTest_test_enterExitQueue_emitsTransfer": "89780", - "GnoErc20VaultTest_test_redeem_emitsEvent": "76993", - "GnoErc20VaultTest_test_upgradesCorrectly": "113185", - "VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "75009", - "VaultGnoErc20VaultTest_test_withdrawValidator_unknown": "56850", - "VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager": "69781" + "GnoErc20VaultTest_test_redeem_emitsEvent": "77058", + "GnoErc20VaultTest_test_upgradesCorrectly": "132165", + "VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "79509", + "VaultGnoErc20VaultTest_test_withdrawValidator_unknown": "61350", + "VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager": "74281" } \ No newline at end of file diff --git a/snapshots/GnoGenesisVaultTest.json b/snapshots/GnoGenesisVaultTest.json index 6a0d3126..b7f71202 100644 --- a/snapshots/GnoGenesisVaultTest.json +++ b/snapshots/GnoGenesisVaultTest.json @@ -1,5 +1,5 @@ { - "GnoGenesisVaultTest_test_migrate_works": "201750", - "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "823811", - "GnoGenesisVaultTest_test_upgradesCorrectly": "5465764" + "GnoGenesisVaultTest_test_migrate_works": "204031", + "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "873476", + "GnoGenesisVaultTest_test_upgradesCorrectly": "5544467" } \ No newline at end of file diff --git a/snapshots/GnoMetaVaultTest.json b/snapshots/GnoMetaVaultTest.json new file mode 100644 index 00000000..5264af47 --- /dev/null +++ b/snapshots/GnoMetaVaultTest.json @@ -0,0 +1,9 @@ +{ + "GnoMetaVaultTest_test_addSubVault": "148145", + "GnoMetaVaultTest_test_claimExitedAssets": "70091", + "GnoMetaVaultTest_test_deposit": "103282", + "GnoMetaVaultTest_test_depositToSubVaults": "338652", + "GnoMetaVaultTest_test_ejectSubVault": "211780", + "GnoMetaVaultTest_test_enterExitQueue": "86712", + "GnoMetaVaultTest_test_updateState": "135992" +} \ No newline at end of file diff --git a/snapshots/GnoOsTokenVaultEscrowTest.json b/snapshots/GnoOsTokenVaultEscrowTest.json index b615ecdb..4553a803 100644 --- a/snapshots/GnoOsTokenVaultEscrowTest.json +++ b/snapshots/GnoOsTokenVaultEscrowTest.json @@ -1,5 +1,5 @@ { - "GnoOsTokenVaultEscrowTest_test_transferAssets_claim": "118340", - "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "719392", + "GnoOsTokenVaultEscrowTest_test_transferAssets_claim": "140340", + "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "862217", "GnoOsTokenVaultEscrowTest_test_transferAssets_transfer": "163157" } \ No newline at end of file diff --git a/snapshots/GnoPrivErc20VaultTest.json b/snapshots/GnoPrivErc20VaultTest.json index 77ac25a4..32d99fdb 100644 --- a/snapshots/GnoPrivErc20VaultTest.json +++ b/snapshots/GnoPrivErc20VaultTest.json @@ -1,7 +1,7 @@ { - "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "158354", - "GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161413", - "GnoPrivErc20VaultTest_test_deploysCorrectly": "779049", - "GnoPrivErc20VaultTest_test_transfer": "59649", - "GnoPrivErc20VaultTest_test_upgradesCorrectly": "113200" + "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "158461", + "GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161543", + "GnoPrivErc20VaultTest_test_deploysCorrectly": "780267", + "GnoPrivErc20VaultTest_test_transfer": "59709", + "GnoPrivErc20VaultTest_test_upgradesCorrectly": "132334" } \ No newline at end of file diff --git a/snapshots/GnoPrivVaultTest.json b/snapshots/GnoPrivVaultTest.json index ea24def8..eb4eee76 100644 --- a/snapshots/GnoPrivVaultTest.json +++ b/snapshots/GnoPrivVaultTest.json @@ -1,8 +1,8 @@ { - "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "156499", - "GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161350", - "GnoPrivVaultTest_test_deploysCorrectly": "527730", + "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "156564", + "GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161480", + "GnoPrivVaultTest_test_deploysCorrectly": "528667", "GnoPrivVaultTest_test_setWhitelister": "36458", "GnoPrivVaultTest_test_updateWhitelist": "54521", - "GnoPrivVaultTest_test_upgradesCorrectly": "112717" + "GnoPrivVaultTest_test_upgradesCorrectly": "131653" } \ No newline at end of file diff --git a/snapshots/GnoRewardSplitterTest.json b/snapshots/GnoRewardSplitterTest.json index 583525c8..98be499b 100644 --- a/snapshots/GnoRewardSplitterTest.json +++ b/snapshots/GnoRewardSplitterTest.json @@ -1,14 +1,14 @@ { - "GnoRewardSplitter_claimExitedAssets": "90142", - "GnoRewardSplitter_claimExitedAssetsOnBehalf": "666102", - "GnoRewardSplitter_claimVaultTokens": "723475", - "GnoRewardSplitter_decreaseShares": "76505", - "GnoRewardSplitter_enterExitQueue": "150585", - "GnoRewardSplitter_enterExitQueueMaxWithdrawal": "126886", - "GnoRewardSplitter_enterExitQueueOnBehalf": "940186", - "GnoRewardSplitter_increaseShares": "68658", + "GnoRewardSplitter_claimExitedAssets": "92207", + "GnoRewardSplitter_claimExitedAssetsOnBehalf": "794911", + "GnoRewardSplitter_claimVaultTokens": "826245", + "GnoRewardSplitter_decreaseShares": "96070", + "GnoRewardSplitter_enterExitQueue": "184280", + "GnoRewardSplitter_enterExitQueueMaxWithdrawal": "128951", + "GnoRewardSplitter_enterExitQueueOnBehalf": "1002298", + "GnoRewardSplitter_increaseShares": "70723", "GnoRewardSplitter_setClaimOnBehalf": "65601", - "GnoRewardSplitter_syncRewards": "75668", - "GnoRewardSplitter_syncRewardsDetailed": "73168", - "GnoRewardSplitter_updateVaultState": "151524" + "GnoRewardSplitter_syncRewards": "77733", + "GnoRewardSplitter_syncRewardsDetailed": "75233", + "GnoRewardSplitter_updateVaultState": "153776" } \ No newline at end of file diff --git a/snapshots/GnoVaultExitQueueTest.json b/snapshots/GnoVaultExitQueueTest.json index a62fc779..c5c7eef9 100644 --- a/snapshots/GnoVaultExitQueueTest.json +++ b/snapshots/GnoVaultExitQueueTest.json @@ -1,7 +1,7 @@ { - "GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event": "193484", - "GnoVaultExitQueueTest_test_claim_position1_after_upgrade": "6137218", - "GnoVaultExitQueueTest_test_claim_position2_before_upgrade": "117260", - "GnoVaultExitQueueTest_test_claim_position3_after_upgrade": "89104", - "GnoVaultExitQueueTest_test_claim_position4_after_upgrade": "84291" + "GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event": "200171", + "GnoVaultExitQueueTest_test_claim_position1_after_upgrade": "6370270", + "GnoVaultExitQueueTest_test_claim_position2_before_upgrade": "123260", + "GnoVaultExitQueueTest_test_claim_position3_after_upgrade": "160234", + "GnoVaultExitQueueTest_test_claim_position4_after_upgrade": "155421" } \ No newline at end of file diff --git a/snapshots/GnoVaultTest.json b/snapshots/GnoVaultTest.json index abe09284..1686b323 100644 --- a/snapshots/GnoVaultTest.json +++ b/snapshots/GnoVaultTest.json @@ -1,8 +1,8 @@ { - "GnoVaultTest_test_deploysCorrectly": "503812", - "GnoVaultTest_test_exitQueue_works": "94643", - "GnoVaultTest_test_upgradesCorrectly": "112526", - "GnoVaultTest_test_withdrawValidator_osTokenRedeemer": "74997", - "GnoVaultTest_test_withdrawValidator_unknown": "56838", - "GnoVaultTest_test_withdrawValidator_validatorsManager": "69758" + "GnoVaultTest_test_deploysCorrectly": "504709", + "GnoVaultTest_test_exitQueue_works": "96643", + "GnoVaultTest_test_upgradesCorrectly": "131527", + "GnoVaultTest_test_withdrawValidator_osTokenRedeemer": "79497", + "GnoVaultTest_test_withdrawValidator_unknown": "61338", + "GnoVaultTest_test_withdrawValidator_validatorsManager": "74258" } \ No newline at end of file diff --git a/snapshots/KeeperOraclesTest.json b/snapshots/KeeperOraclesTest.json index 82aaff91..a1d30fcf 100644 --- a/snapshots/KeeperOraclesTest.json +++ b/snapshots/KeeperOraclesTest.json @@ -1,12 +1,12 @@ { "KeeperOraclesTest_test_addOracle_alreadyAdded": "28022", - "KeeperOraclesTest_test_addOracle_maxOraclesExceeded": "31511", + "KeeperOraclesTest_test_addOracle_maxOraclesExceeded": "33511", "KeeperOraclesTest_test_addOracle_onlyOwner": "32780", - "KeeperOraclesTest_test_addOracle_success": "53972", - "KeeperOraclesTest_test_removeOracle_alreadyRemoved": "28141", + "KeeperOraclesTest_test_addOracle_success": "55972", + "KeeperOraclesTest_test_removeOracle_alreadyRemoved": "32141", "KeeperOraclesTest_test_removeOracle_onlyOwner": "26396", - "KeeperOraclesTest_test_removeOracle_success": "32154", + "KeeperOraclesTest_test_removeOracle_success": "34154", "KeeperOraclesTest_test_updateConfig_onlyOwner": "31726", "KeeperOraclesTest_test_updateConfig_success": "32787", - "KeeperOraclesTest_test_verifySignatures_throughKeeperRewards": "208171" + "KeeperOraclesTest_test_verifySignatures_throughKeeperRewards": "234771" } \ No newline at end of file diff --git a/snapshots/KeeperRewardsTest.json b/snapshots/KeeperRewardsTest.json index d6d25f8d..2a8443d6 100644 --- a/snapshots/KeeperRewardsTest.json +++ b/snapshots/KeeperRewardsTest.json @@ -1,20 +1,20 @@ { - "KeeperRewardsTest_test_canHarvest": "4438", - "KeeperRewardsTest_test_harvest": "128681", - "KeeperRewardsTest_test_harvestWithPenalties": "88494", - "KeeperRewardsTest_test_harvest_alreadyHarvested": "45945", - "KeeperRewardsTest_test_harvest_invalidProof": "44509", - "KeeperRewardsTest_test_harvest_invalidRewardsRoot": "45084", + "KeeperRewardsTest_test_canHarvest": "12938", + "KeeperRewardsTest_test_harvest": "130823", + "KeeperRewardsTest_test_harvestWithPenalties": "92516", + "KeeperRewardsTest_test_harvest_alreadyHarvested": "47952", + "KeeperRewardsTest_test_harvest_invalidProof": "49041", + "KeeperRewardsTest_test_harvest_invalidRewardsRoot": "49601", "KeeperRewardsTest_test_harvest_nonVault": "35559", - "KeeperRewardsTest_test_isCollateralized": "1623", - "KeeperRewardsTest_test_isHarvestRequired": "2120", - "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_1": "128663", - "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_2": "495675", - "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_3": "493709", - "KeeperRewardsTest_test_setRewardsMinOracles": "33248", + "KeeperRewardsTest_test_isCollateralized": "10123", + "KeeperRewardsTest_test_isHarvestRequired": "12620", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_1": "135305", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_2": "581717", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_3": "581727", + "KeeperRewardsTest_test_setRewardsMinOracles": "35248", "KeeperRewardsTest_test_setRewardsMinOracles_tooMany": "29542", - "KeeperRewardsTest_test_setRewardsMinOracles_zero": "25531", - "KeeperRewardsTest_test_updateRewards": "96923", - "KeeperRewardsTest_test_updateRewards_invalidAvgRewardPerSecond": "28759", - "KeeperRewardsTest_test_updateRewards_tooEarly": "28750" + "KeeperRewardsTest_test_setRewardsMinOracles_zero": "27531", + "KeeperRewardsTest_test_updateRewards": "98923", + "KeeperRewardsTest_test_updateRewards_invalidAvgRewardPerSecond": "30759", + "KeeperRewardsTest_test_updateRewards_tooEarly": "30750" } \ No newline at end of file diff --git a/snapshots/KeeperValidatorsTest.json b/snapshots/KeeperValidatorsTest.json index e2349a64..14d1236d 100644 --- a/snapshots/KeeperValidatorsTest.json +++ b/snapshots/KeeperValidatorsTest.json @@ -1,12 +1,12 @@ { "KeeperValidatorsTest_test_approveValidators_accessDenied": "139566", - "KeeperValidatorsTest_test_approveValidators_invalidDeadline": "29840", - "KeeperValidatorsTest_test_approveValidators_invalidRegistry": "132477", - "KeeperValidatorsTest_test_approveValidators_success": "174557", - "KeeperValidatorsTest_test_setValidatorsMinOracles_success": "33099", + "KeeperValidatorsTest_test_approveValidators_invalidDeadline": "31828", + "KeeperValidatorsTest_test_approveValidators_invalidRegistry": "134465", + "KeeperValidatorsTest_test_approveValidators_success": "179045", + "KeeperValidatorsTest_test_setValidatorsMinOracles_success": "35099", "KeeperValidatorsTest_test_setValidatorsMinOracles_tooHigh": "29460", - "KeeperValidatorsTest_test_setValidatorsMinOracles_unauthorized": "25745", - "KeeperValidatorsTest_test_setValidatorsMinOracles_zero": "25382", + "KeeperValidatorsTest_test_setValidatorsMinOracles_unauthorized": "27745", + "KeeperValidatorsTest_test_setValidatorsMinOracles_zero": "27382", "KeeperValidatorsTest_test_updateExitSignatures_duplicateUpdate": "45635", "KeeperValidatorsTest_test_updateExitSignatures_expiredDeadline": "34338", "KeeperValidatorsTest_test_updateExitSignatures_invalidVault": "31986", diff --git a/snapshots/OsTokenConfigTest.json b/snapshots/OsTokenConfigTest.json index f9a2f768..d687b7ca 100644 --- a/snapshots/OsTokenConfigTest.json +++ b/snapshots/OsTokenConfigTest.json @@ -1,7 +1,7 @@ { - "OsTokenConfigForkTest_test_setRedeemer": "30972", - "OsTokenConfigForkTest_test_setRedeemer_notOwner": "27710", - "OsTokenConfigForkTest_test_setRedeemer_sameValue": "27381", + "OsTokenConfigForkTest_test_setRedeemer": "32972", + "OsTokenConfigForkTest_test_setRedeemer_notOwner": "29710", + "OsTokenConfigForkTest_test_setRedeemer_sameValue": "29381", "OsTokenConfigForkTest_test_updateConfig_disabledLiquidations": "56787", "OsTokenConfigForkTest_test_updateConfig_forVault": "55186", "OsTokenConfigForkTest_test_updateConfig_invalidDisabledLiquidations": "33162", @@ -11,7 +11,7 @@ "OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_tooHigh": "28640", "OsTokenConfigForkTest_test_updateConfig_invalidLiqThresholdPercent_zero": "33104", "OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_tooHigh": "28671", - "OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_zero": "28479", + "OsTokenConfigForkTest_test_updateConfig_invalidLtvPercent_zero": "30479", "OsTokenConfigForkTest_test_updateConfig_notOwner": "33393", "OsTokenConfigTest_test_updateDefaultConfig_success": "37692" } \ No newline at end of file diff --git a/snapshots/OsTokenTest.json b/snapshots/OsTokenTest.json index 491bbbd6..95b2c256 100644 --- a/snapshots/OsTokenTest.json +++ b/snapshots/OsTokenTest.json @@ -1,19 +1,19 @@ { - "OsTokenTest_test_burn": "32742", + "OsTokenTest_test_burn": "36742", "OsTokenTest_test_burn_onlyController": "27956", - "OsTokenTest_test_controllerIntegration_burn": "36343", - "OsTokenTest_test_controllerIntegration_mint": "103994", + "OsTokenTest_test_controllerIntegration_burn": "46843", + "OsTokenTest_test_controllerIntegration_mint": "105994", "OsTokenTest_test_erc20_transfer": "54454", - "OsTokenTest_test_erc20_transferFrom": "95658", - "OsTokenTest_test_fullDepositFlow": "195278", - "OsTokenTest_test_mint": "54400", + "OsTokenTest_test_erc20_transferFrom": "112658", + "OsTokenTest_test_fullDepositFlow": "197995", + "OsTokenTest_test_mint": "58400", "OsTokenTest_test_mint_onlyController": "30281", - "OsTokenTest_test_permit": "75632", + "OsTokenTest_test_permit": "77632", "OsTokenTest_test_permit_expiredDeadline": "32235", - "OsTokenTest_test_permit_invalidSignature": "51951", + "OsTokenTest_test_permit_invalidSignature": "53951", "OsTokenTest_test_permit_zeroAddress": "56033", - "OsTokenTest_test_setController_add": "51103", + "OsTokenTest_test_setController_add": "53103", "OsTokenTest_test_setController_onlyOwner": "32836", - "OsTokenTest_test_setController_remove": "30637", - "OsTokenTest_test_setController_zeroAddress": "25570" + "OsTokenTest_test_setController_remove": "39137", + "OsTokenTest_test_setController_zeroAddress": "27570" } \ No newline at end of file diff --git a/snapshots/OwnMevEscrowTest.json b/snapshots/OwnMevEscrowTest.json index f2548a9b..a96486f2 100644 --- a/snapshots/OwnMevEscrowTest.json +++ b/snapshots/OwnMevEscrowTest.json @@ -1,8 +1,8 @@ { - "OwnMevEscrowTest_test_harvest_fromNonVault": "23482", - "OwnMevEscrowTest_test_harvest_fromVault": "37691", - "OwnMevEscrowTest_test_harvest_zeroBalance": "22226", - "OwnMevEscrowTest_test_multipleHarvests": "37691", - "OwnMevEscrowTest_test_multipleSenders": "37691", - "OwnMevEscrowTest_test_receiveMev": "34061" + "OwnMevEscrowTest_test_harvest_fromNonVault": "23514", + "OwnMevEscrowTest_test_harvest_fromVault": "37701", + "OwnMevEscrowTest_test_harvest_zeroBalance": "22258", + "OwnMevEscrowTest_test_multipleHarvests": "37701", + "OwnMevEscrowTest_test_multipleSenders": "37701", + "OwnMevEscrowTest_test_receiveMev": "34093" } \ No newline at end of file diff --git a/snapshots/PriceFeedTest.json b/snapshots/PriceFeedTest.json index 7b7f2eb5..c9e0dba2 100644 --- a/snapshots/PriceFeedTest.json +++ b/snapshots/PriceFeedTest.json @@ -1,5 +1,5 @@ { - "PriceFeedTest_test_getRate_gas": "18476", - "PriceFeedTest_test_latestAnswer_gas": "18525", - "PriceFeedTest_test_latestRoundData_gas": "18996" + "PriceFeedTest_test_getRate_gas": "20976", + "PriceFeedTest_test_latestAnswer_gas": "21025", + "PriceFeedTest_test_latestRoundData_gas": "21496" } \ No newline at end of file diff --git a/snapshots/VaultAdminTest.json b/snapshots/VaultAdminTest.json index f9d9fc96..3beaf8ab 100644 --- a/snapshots/VaultAdminTest.json +++ b/snapshots/VaultAdminTest.json @@ -1,7 +1,7 @@ { "VaultAdminTest_test_checkAdmin_withOtherFunctions_admin": "43348", "VaultAdminTest_test_checkAdmin_withOtherFunctions_nonAdmin": "34790", - "VaultAdminTest_test_initialization": "377286", + "VaultAdminTest_test_initialization": "378236", "VaultAdminTest_test_setAdmin_byAdmin": "39009", "VaultAdminTest_test_setAdmin_byNonAdmin": "36858", "VaultAdminTest_test_setAdmin_toZeroAddress": "34573", diff --git a/snapshots/VaultEnterExitTest.json b/snapshots/VaultEnterExitTest.json index 4818ebb2..8bd4ba21 100644 --- a/snapshots/VaultEnterExitTest.json +++ b/snapshots/VaultEnterExitTest.json @@ -1,24 +1,24 @@ { - "VaultEnterExitTest_test_calculateExitedAssets_invalidPosition": "16077", - "VaultEnterExitTest_test_claimExitedAssets": "604600", - "VaultEnterExitTest_test_claimExitedAssets_insufficientDelay": "39366", + "VaultEnterExitTest_test_calculateExitedAssets_invalidPosition": "18577", + "VaultEnterExitTest_test_claimExitedAssets": "730303", + "VaultEnterExitTest_test_claimExitedAssets_insufficientDelay": "41431", "VaultEnterExitTest_test_claimExitedAssets_invalidCheckpoint": "36506", "VaultEnterExitTest_test_deposit_exceedingCapacity": "47943", - "VaultEnterExitTest_test_deposit_success_basic": "78595", - "VaultEnterExitTest_test_deposit_success_differentReceiver": "76498", - "VaultEnterExitTest_test_deposit_success_multipleDeposits": "57398", - "VaultEnterExitTest_test_deposit_success_receiveFunction": "75053", - "VaultEnterExitTest_test_deposit_success_withReferrer": "76720", + "VaultEnterExitTest_test_deposit_success_basic": "80660", + "VaultEnterExitTest_test_deposit_success_differentReceiver": "80563", + "VaultEnterExitTest_test_deposit_success_multipleDeposits": "57463", + "VaultEnterExitTest_test_deposit_success_receiveFunction": "77118", + "VaultEnterExitTest_test_deposit_success_withReferrer": "76785", "VaultEnterExitTest_test_deposit_zeroAddress": "49918", "VaultEnterExitTest_test_deposit_zeroAmount": "43483", - "VaultEnterExitTest_test_enterExitQueue_afterValidatorExit": "89855", - "VaultEnterExitTest_test_enterExitQueue_basicFlow": "89843", - "VaultEnterExitTest_test_enterExitQueue_directRedemption": "81841", - "VaultEnterExitTest_test_enterExitQueue_invalidParams_tooManyShares": "47257", - "VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroAddress": "32832", + "VaultEnterExitTest_test_enterExitQueue_afterValidatorExit": "91855", + "VaultEnterExitTest_test_enterExitQueue_basicFlow": "91843", + "VaultEnterExitTest_test_enterExitQueue_directRedemption": "81906", + "VaultEnterExitTest_test_enterExitQueue_invalidParams_tooManyShares": "62322", + "VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroAddress": "45832", "VaultEnterExitTest_test_enterExitQueue_invalidParams_zeroShares": "31356", - "VaultEnterExitTest_test_enterExitQueue_multiUser_sender2": "72995", - "VaultEnterExitTest_test_enterExitQueue_multiUser_user1": "89843", + "VaultEnterExitTest_test_enterExitQueue_multiUser_sender2": "74995", + "VaultEnterExitTest_test_enterExitQueue_multiUser_user1": "91843", "VaultEnterExitTest_test_enterExitQueue_multipleUpdates": "89746", - "VaultEnterExitTest_test_enterExitQueue_partialExit": "94643" + "VaultEnterExitTest_test_enterExitQueue_partialExit": "96643" } \ No newline at end of file diff --git a/snapshots/VaultEthStakingTest.json b/snapshots/VaultEthStakingTest.json index d12b65c6..5b01e9fa 100644 --- a/snapshots/VaultEthStakingTest.json +++ b/snapshots/VaultEthStakingTest.json @@ -1,18 +1,18 @@ { - "VaultEthStakingTest_test_deposit": "80760", - "VaultEthStakingTest_test_depositAndMintOsToken": "199818", - "VaultEthStakingTest_test_fundValidators_invalid": "52830", - "VaultEthStakingTest_test_fundValidators_valid": "131837", - "VaultEthStakingTest_test_harvestAssets": "128671", - "VaultEthStakingTest_test_invalidSecurityDeposit": "307071", - "VaultEthStakingTest_test_receive": "72953", - "VaultEthStakingTest_test_receiveFromMevEscrow_fail": "36592", - "VaultEthStakingTest_test_receiveFromMevEscrow_success": "37848", - "VaultEthStakingTest_test_registerValidators_01prefix": "239744", - "VaultEthStakingTest_test_registerValidators_02prefix": "421816", - "VaultEthStakingTest_test_transferVaultAssets": "49705", - "VaultEthStakingTest_test_updateStateAndDeposit": "159946", - "VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken": "251911", - "VaultEthStakingTest_test_validatorMinMaxEffectiveBalance": "195664", - "VaultEthStakingTest_test_withdrawValidator_fullFlow": "69781" + "VaultEthStakingTest_test_deposit": "82825", + "VaultEthStakingTest_test_depositAndMintOsToken": "200035", + "VaultEthStakingTest_test_fundValidators_invalid": "57366", + "VaultEthStakingTest_test_fundValidators_valid": "140938", + "VaultEthStakingTest_test_harvestAssets": "130825", + "VaultEthStakingTest_test_invalidSecurityDeposit": "307913", + "VaultEthStakingTest_test_receive": "75018", + "VaultEthStakingTest_test_receiveFromMevEscrow_fail": "36570", + "VaultEthStakingTest_test_receiveFromMevEscrow_success": "37826", + "VaultEthStakingTest_test_registerValidators_01prefix": "244309", + "VaultEthStakingTest_test_registerValidators_02prefix": "501482", + "VaultEthStakingTest_test_transferVaultAssets": "51757", + "VaultEthStakingTest_test_updateStateAndDeposit": "164153", + "VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken": "254248", + "VaultEthStakingTest_test_validatorMinMaxEffectiveBalance": "200164", + "VaultEthStakingTest_test_withdrawValidator_fullFlow": "74281" } \ No newline at end of file diff --git a/snapshots/VaultFeeTest.json b/snapshots/VaultFeeTest.json index 22bdeacd..d2f75eed 100644 --- a/snapshots/VaultFeeTest.json +++ b/snapshots/VaultFeeTest.json @@ -1,15 +1,15 @@ { - "VaultFeeTest_test_feeCollection": "115247", - "VaultFeeTest_test_feePercent_changeAffectsFutureRewards": "81049", + "VaultFeeTest_test_feeCollection": "121911", + "VaultFeeTest_test_feePercent_changeAffectsFutureRewards": "87713", "VaultFeeTest_test_setFeePercent_aboveMaximum": "40380", "VaultFeeTest_test_setFeePercent_initialZeroToOne": "42312", "VaultFeeTest_test_setFeePercent_maxIncrease": "38472", "VaultFeeTest_test_setFeePercent_notAdmin": "34556", - "VaultFeeTest_test_setFeePercent_requiresHarvest": "38001", - "VaultFeeTest_test_setFeePercent_success": "42575", + "VaultFeeTest_test_setFeePercent_requiresHarvest": "42501", + "VaultFeeTest_test_setFeePercent_success": "44575", "VaultFeeTest_test_setFeePercent_tooSoon": "38137", "VaultFeeTest_test_setFeeRecipient_notAdmin": "36854", - "VaultFeeTest_test_setFeeRecipient_requiresHarvest": "40296", + "VaultFeeTest_test_setFeeRecipient_requiresHarvest": "44796", "VaultFeeTest_test_setFeeRecipient_success": "48796", "VaultFeeTest_test_setFeeRecipient_zeroAddress": "40343" } \ No newline at end of file diff --git a/snapshots/VaultGnoStakingTest.json b/snapshots/VaultGnoStakingTest.json index 2a88ce19..a2797e68 100644 --- a/snapshots/VaultGnoStakingTest.json +++ b/snapshots/VaultGnoStakingTest.json @@ -1,14 +1,14 @@ { - "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "136579", - "VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid": "52815", - "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "170435", - "VaultGnoStakingTest_test_deposit": "101016", - "VaultGnoStakingTest_test_processTotalAssetsDelta": "219229", - "VaultGnoStakingTest_test_pullWithdrawals": "88447", + "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "140831", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid": "57291", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "179488", + "VaultGnoStakingTest_test_deposit": "101081", + "VaultGnoStakingTest_test_processTotalAssetsDelta": "225851", + "VaultGnoStakingTest_test_pullWithdrawals": "92512", "VaultGnoStakingTest_test_receive_xDai": "33415", - "VaultGnoStakingTest_test_transferVaultAssets": "85372", - "VaultGnoStakingTest_test_vaultGnoStaking_init": "503857", - "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "69758", - "test_registerValidators_succeeds_0x01": "283609", - "test_registerValidators_succeeds_0x02": "545373" + "VaultGnoStakingTest_test_transferVaultAssets": "87437", + "VaultGnoStakingTest_test_vaultGnoStaking_init": "504708", + "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "74246", + "test_registerValidators_succeeds_0x01": "288174", + "test_registerValidators_succeeds_0x02": "632039" } \ No newline at end of file diff --git a/snapshots/VaultOsTokenTest.json b/snapshots/VaultOsTokenTest.json index a0a4878c..ef5355b9 100644 --- a/snapshots/VaultOsTokenTest.json +++ b/snapshots/VaultOsTokenTest.json @@ -1,48 +1,48 @@ { - "VaultOsTokenTest_test_burnOsToken_afterFeeSync": "71424", - "VaultOsTokenTest_test_burnOsToken_allShares": "66187", - "VaultOsTokenTest_test_burnOsToken_basic": "70987", + "VaultOsTokenTest_test_burnOsToken_afterFeeSync": "73489", + "VaultOsTokenTest_test_burnOsToken_allShares": "68187", + "VaultOsTokenTest_test_burnOsToken_basic": "72987", "VaultOsTokenTest_test_burnOsToken_exceedingShares": "48701", "VaultOsTokenTest_test_burnOsToken_improvesLTV": "70999", "VaultOsTokenTest_test_burnOsToken_invalidPosition": "66210", - "VaultOsTokenTest_test_burnOsToken_multipleBurns": "70987", + "VaultOsTokenTest_test_burnOsToken_multipleBurns": "72987", "VaultOsTokenTest_test_burnOsToken_zeroShares": "37846", - "VaultOsTokenTest_test_enterExitQueue_ltvViolation": "118185", - "VaultOsTokenTest_test_liquidateOsToken_basic": "120072", - "VaultOsTokenTest_test_liquidateOsToken_bonus": "120072", - "VaultOsTokenTest_test_liquidateOsToken_invalidReceivedAssets": "73028", - "VaultOsTokenTest_test_liquidateOsToken_liquidationDisabled": "68988", - "VaultOsTokenTest_test_liquidateOsToken_partialLiquidation": "120072", - "VaultOsTokenTest_test_mintOsToken_basic": "157446", - "VaultOsTokenTest_test_mintOsToken_feeSync": "103337", - "VaultOsTokenTest_test_mintOsToken_ltvValidation": "140319", - "VaultOsTokenTest_test_mintOsToken_maxAmount": "157827", - "VaultOsTokenTest_test_mintOsToken_multipleReceivers": "119813", - "VaultOsTokenTest_test_mintOsToken_notCollateralized": "39431", - "VaultOsTokenTest_test_mintOsToken_notHarvested": "45593", - "VaultOsTokenTest_test_mintOsToken_repeatedMinting": "105518", - "VaultOsTokenTest_test_mintOsToken_zeroAddressReceiver": "86660", - "VaultOsTokenTest_test_mintOsToken_zeroShares": "88940", - "VaultOsTokenTest_test_redeemOsToken_afterFeeSync": "129608", - "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail": "44527", - "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success": "263310", - "VaultOsTokenTest_test_redeemOsToken_basic": "129171", - "VaultOsTokenTest_test_redeemOsToken_fullPosition": "129171", - "VaultOsTokenTest_test_redeemOsToken_goodHealthFactor": "129254", - "VaultOsTokenTest_test_redeemOsToken_insufficientShares": "106195", - "VaultOsTokenTest_test_redeemOsToken_nonExistentPosition": "87096", - "VaultOsTokenTest_test_redeemOsToken_onlyRedeemer": "36448", - "VaultOsTokenTest_test_redeemOsToken_zeroAddressReceiver": "34261", - "VaultOsTokenTest_test_redeemOsToken_zeroShares": "83797", - "VaultOsTokenTest_test_redeemVsLiquidate": "129254", - "VaultOsTokenTest_test_test_liquidateOsToken_notHarvested": "41526", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_basic": "163167", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_claim": "99265", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_maxAmount": "163179", + "VaultOsTokenTest_test_enterExitQueue_ltvViolation": "118315", + "VaultOsTokenTest_test_liquidateOsToken_basic": "120484", + "VaultOsTokenTest_test_liquidateOsToken_bonus": "124984", + "VaultOsTokenTest_test_liquidateOsToken_invalidReceivedAssets": "75310", + "VaultOsTokenTest_test_liquidateOsToken_liquidationDisabled": "69205", + "VaultOsTokenTest_test_liquidateOsToken_partialLiquidation": "122484", + "VaultOsTokenTest_test_mintOsToken_basic": "162098", + "VaultOsTokenTest_test_mintOsToken_feeSync": "105554", + "VaultOsTokenTest_test_mintOsToken_ltvValidation": "144971", + "VaultOsTokenTest_test_mintOsToken_maxAmount": "159979", + "VaultOsTokenTest_test_mintOsToken_multipleReceivers": "119965", + "VaultOsTokenTest_test_mintOsToken_notCollateralized": "41953", + "VaultOsTokenTest_test_mintOsToken_notHarvested": "47615", + "VaultOsTokenTest_test_mintOsToken_repeatedMinting": "105670", + "VaultOsTokenTest_test_mintOsToken_zeroAddressReceiver": "86812", + "VaultOsTokenTest_test_mintOsToken_zeroShares": "89092", + "VaultOsTokenTest_test_redeemOsToken_afterFeeSync": "134280", + "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail": "50939", + "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success": "265646", + "VaultOsTokenTest_test_redeemOsToken_basic": "133778", + "VaultOsTokenTest_test_redeemOsToken_fullPosition": "133778", + "VaultOsTokenTest_test_redeemOsToken_goodHealthFactor": "133861", + "VaultOsTokenTest_test_redeemOsToken_insufficientShares": "112737", + "VaultOsTokenTest_test_redeemOsToken_nonExistentPosition": "87008", + "VaultOsTokenTest_test_redeemOsToken_onlyRedeemer": "36360", + "VaultOsTokenTest_test_redeemOsToken_zeroAddressReceiver": "40673", + "VaultOsTokenTest_test_redeemOsToken_zeroShares": "90339", + "VaultOsTokenTest_test_redeemVsLiquidate": "133861", + "VaultOsTokenTest_test_test_liquidateOsToken_notHarvested": "43548", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_basic": "165145", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_claim": "107765", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_maxAmount": "165157", "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_moreThanOwned": "44795", "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_noPosition": "43502", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested": "36830", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer": "173165", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process": "625682", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares": "47480" + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested": "41330", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer": "173208", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process": "721121", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares": "47545" } \ No newline at end of file diff --git a/snapshots/VaultSubVaultsTest.json b/snapshots/VaultSubVaultsTest.json new file mode 100644 index 00000000..522adca2 --- /dev/null +++ b/snapshots/VaultSubVaultsTest.json @@ -0,0 +1,15 @@ +{ + "VaultSubVaultsTest_test_addSubVault_success": "120061", + "VaultSubVaultsTest_test_claimSubVaultsExitedAssets_ejectionConsumesShares": "455722", + "VaultSubVaultsTest_test_claimSubVaultsExitedAssets_partiallyClaimsExitedAssets": "116953", + "VaultSubVaultsTest_test_depositToSubVaults_maxVaults": "3870764", + "VaultSubVaultsTest_test_depositToSubVaults_multipleSubVaults": "312999", + "VaultSubVaultsTest_test_depositToSubVaults_singleSubVault": "161162", + "VaultSubVaultsTest_test_setSubVaultsCurator_success": "51061", + "VaultSubVaultsTest_test_updateState_enterExitQueueMaxVaults": "6752771", + "test_depositToSubVaults_ejectingSubVault": "151563", + "test_ejectSubVault_emptySubVault": "61797", + "test_ejectSubVault_subVaultWithShares": "202076", + "test_updateState_newTotalAssets": "194165", + "test_updateState_unprocessedSubVaultExit": "167082" +} \ No newline at end of file diff --git a/snapshots/VaultTokenTest.json b/snapshots/VaultTokenTest.json index 358f0d78..efe7613f 100644 --- a/snapshots/VaultTokenTest.json +++ b/snapshots/VaultTokenTest.json @@ -1,22 +1,22 @@ { - "VaultTokenTest_test_approve": "52346", + "VaultTokenTest_test_approve": "56346", "VaultTokenTest_test_approveZeroAddress": "33703", - "VaultTokenTest_test_depositEmitsTransferEvent": "78928", + "VaultTokenTest_test_depositEmitsTransferEvent": "80993", "VaultTokenTest_test_enterExitQueueEmitsTransferEvent": "94566", - "VaultTokenTest_test_invalidTokenMetaNameTooLong": "476767", - "VaultTokenTest_test_invalidTokenMetaSymbolTooLong": "309835", - "VaultTokenTest_test_permit": "82702", - "VaultTokenTest_test_permitExpiredDeadline": "30817", - "VaultTokenTest_test_permitInvalidSigner": "59070", - "VaultTokenTest_test_permitZeroAddressSpender": "30363", - "VaultTokenTest_test_transfer": "59941", - "VaultTokenTest_test_transferFrom": "61179", - "VaultTokenTest_test_transferFromMoreThanAllowance": "32458", - "VaultTokenTest_test_transferFromMoreThanBalance": "37906", - "VaultTokenTest_test_transferFromZeroAddress": "38513", - "VaultTokenTest_test_transferMoreThanBalance": "33862", - "VaultTokenTest_test_transferToZeroAddress": "29234", - "VaultTokenTest_test_transferWithOsTokenPosition": "91954", - "VaultTokenTest_test_unlimitedAllowance": "62839", - "VaultTokenTest_test_updateExitQueueBurnsShares": "142163" + "VaultTokenTest_test_invalidTokenMetaNameTooLong": "477587", + "VaultTokenTest_test_invalidTokenMetaSymbolTooLong": "310655", + "VaultTokenTest_test_permit": "84690", + "VaultTokenTest_test_permitExpiredDeadline": "32817", + "VaultTokenTest_test_permitInvalidSigner": "61070", + "VaultTokenTest_test_permitZeroAddressSpender": "32351", + "VaultTokenTest_test_transfer": "63941", + "VaultTokenTest_test_transferFrom": "65201", + "VaultTokenTest_test_transferFromMoreThanAllowance": "32480", + "VaultTokenTest_test_transferFromMoreThanBalance": "37928", + "VaultTokenTest_test_transferFromZeroAddress": "38535", + "VaultTokenTest_test_transferMoreThanBalance": "35862", + "VaultTokenTest_test_transferToZeroAddress": "31234", + "VaultTokenTest_test_transferWithOsTokenPosition": "94084", + "VaultTokenTest_test_unlimitedAllowance": "66861", + "VaultTokenTest_test_updateExitQueueBurnsShares": "146959" } \ No newline at end of file diff --git a/snapshots/VaultValidatorsTest.json b/snapshots/VaultValidatorsTest.json index 6128d3d7..634eeaed 100644 --- a/snapshots/VaultValidatorsTest.json +++ b/snapshots/VaultValidatorsTest.json @@ -1,43 +1,43 @@ { - "VaultValidatorsTest_test_consolidateValidators_byManager": "74807", - "VaultValidatorsTest_test_consolidateValidators_feeHandling": "81808", - "VaultValidatorsTest_test_consolidateValidators_invalidSignature": "67704", - "VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty": "51204", + "VaultValidatorsTest_test_consolidateValidators_byManager": "79319", + "VaultValidatorsTest_test_consolidateValidators_feeHandling": "86320", + "VaultValidatorsTest_test_consolidateValidators_invalidSignature": "69716", + "VaultValidatorsTest_test_consolidateValidators_invalidValidatorsEmpty": "55704", "VaultValidatorsTest_test_consolidateValidators_invalidValidatorsLength": "57426", - "VaultValidatorsTest_test_consolidateValidators_multipleValidators": "94995", - "VaultValidatorsTest_test_consolidateValidators_notManager": "52834", - "VaultValidatorsTest_test_consolidateValidators_untrackedDestination": "74303", - "VaultValidatorsTest_test_consolidateValidators_withOracleSignatures": "111382", - "VaultValidatorsTest_test_consolidateValidators_withSignature": "107300", - "VaultValidatorsTest_test_fundValidators_byManager": "101092", - "VaultValidatorsTest_test_fundValidators_insufficientAssets": "101419", - "VaultValidatorsTest_test_fundValidators_invalidSignature": "59249", - "VaultValidatorsTest_test_fundValidators_invalidValidators": "41331", - "VaultValidatorsTest_test_fundValidators_multipleValidators": "143741", - "VaultValidatorsTest_test_fundValidators_nonExistingValidator": "52854", - "VaultValidatorsTest_test_fundValidators_notHarvested": "39858", - "VaultValidatorsTest_test_fundValidators_notManager": "44366", - "VaultValidatorsTest_test_fundValidators_v1Validators": "48296", - "VaultValidatorsTest_test_fundValidators_withSignature": "133557", - "VaultValidatorsTest_test_registerValidators_byManager": "265170", - "VaultValidatorsTest_test_registerValidators_insufficientAssets": "39964", - "VaultValidatorsTest_test_registerValidators_invalidSignature": "206586", - "VaultValidatorsTest_test_registerValidators_invalidValidatorLength": "194492", - "VaultValidatorsTest_test_registerValidators_invalidValidators": "188557", - "VaultValidatorsTest_test_registerValidators_multipleValidators": "299669", - "VaultValidatorsTest_test_registerValidators_nonceIncrement": "143933", - "VaultValidatorsTest_test_registerValidators_notHarvested": "166243", - "VaultValidatorsTest_test_registerValidators_notManager": "191735", - "VaultValidatorsTest_test_registerValidators_v1Validators": "239739", - "VaultValidatorsTest_test_registerValidators_v2Validators": "262670", - "VaultValidatorsTest_test_registerValidators_withSignature": "299634", - "VaultValidatorsTest_test_withdrawValidators_byManager": "69769", - "VaultValidatorsTest_test_withdrawValidators_byRedeemer": "75008", - "VaultValidatorsTest_test_withdrawValidators_feeHandling": "76770", - "VaultValidatorsTest_test_withdrawValidators_invalidSignature": "71746", - "VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty": "55970", + "VaultValidatorsTest_test_consolidateValidators_multipleValidators": "99507", + "VaultValidatorsTest_test_consolidateValidators_notManager": "57346", + "VaultValidatorsTest_test_consolidateValidators_untrackedDestination": "76315", + "VaultValidatorsTest_test_consolidateValidators_withOracleSignatures": "113394", + "VaultValidatorsTest_test_consolidateValidators_withSignature": "109300", + "VaultValidatorsTest_test_fundValidators_byManager": "105693", + "VaultValidatorsTest_test_fundValidators_insufficientAssets": "103520", + "VaultValidatorsTest_test_fundValidators_invalidSignature": "61297", + "VaultValidatorsTest_test_fundValidators_invalidValidators": "45831", + "VaultValidatorsTest_test_fundValidators_multipleValidators": "148330", + "VaultValidatorsTest_test_fundValidators_nonExistingValidator": "57354", + "VaultValidatorsTest_test_fundValidators_notHarvested": "44394", + "VaultValidatorsTest_test_fundValidators_notManager": "48902", + "VaultValidatorsTest_test_fundValidators_v1Validators": "52808", + "VaultValidatorsTest_test_fundValidators_withSignature": "135658", + "VaultValidatorsTest_test_registerValidators_byManager": "267223", + "VaultValidatorsTest_test_registerValidators_insufficientAssets": "41952", + "VaultValidatorsTest_test_registerValidators_invalidSignature": "206562", + "VaultValidatorsTest_test_registerValidators_invalidValidatorLength": "194504", + "VaultValidatorsTest_test_registerValidators_invalidValidators": "188569", + "VaultValidatorsTest_test_registerValidators_multipleValidators": "304210", + "VaultValidatorsTest_test_registerValidators_nonceIncrement": "145921", + "VaultValidatorsTest_test_registerValidators_notHarvested": "170731", + "VaultValidatorsTest_test_registerValidators_notManager": "193723", + "VaultValidatorsTest_test_registerValidators_v1Validators": "241804", + "VaultValidatorsTest_test_registerValidators_v2Validators": "264723", + "VaultValidatorsTest_test_registerValidators_withSignature": "299687", + "VaultValidatorsTest_test_withdrawValidators_byManager": "74269", + "VaultValidatorsTest_test_withdrawValidators_byRedeemer": "79508", + "VaultValidatorsTest_test_withdrawValidators_feeHandling": "81270", + "VaultValidatorsTest_test_withdrawValidators_invalidSignature": "73746", + "VaultValidatorsTest_test_withdrawValidators_invalidValidatorsEmpty": "60470", "VaultValidatorsTest_test_withdrawValidators_invalidValidatorsLength": "56660", - "VaultValidatorsTest_test_withdrawValidators_multipleValidators": "85451", - "VaultValidatorsTest_test_withdrawValidators_notAuthorized": "56912", - "VaultValidatorsTest_test_withdrawValidators_withSignature": "102206" + "VaultValidatorsTest_test_withdrawValidators_multipleValidators": "89963", + "VaultValidatorsTest_test_withdrawValidators_notAuthorized": "61412", + "VaultValidatorsTest_test_withdrawValidators_withSignature": "104206" } \ No newline at end of file diff --git a/snapshots/VaultVersionTest.json b/snapshots/VaultVersionTest.json index 9ccbb283..9fcd9c3d 100644 --- a/snapshots/VaultVersionTest.json +++ b/snapshots/VaultVersionTest.json @@ -1,12 +1,12 @@ { - "VaultVersionTest_test_reinitializeFails": "30868", - "VaultVersionTest_test_upgradeMultipleSteps": "56466", - "VaultVersionTest_test_upgradeNonAdminFails": "38894", - "VaultVersionTest_test_upgradeToDifferentVaultIdFails": "42341", - "VaultVersionTest_test_upgradeToNextVersion": "83648", - "VaultVersionTest_test_upgradeToSameVersionFails": "32627", - "VaultVersionTest_test_upgradeToSkipVersionFails": "43084", - "VaultVersionTest_test_upgradeToUnapprovedImplementationFails": "46393", - "VaultVersionTest_test_upgradeToZeroAddressFails": "36662", - "VaultVersionTest_test_upgradeWithInvalidCallDataFails": "60697" + "VaultVersionTest_test_reinitializeFails": "30923", + "VaultVersionTest_test_upgradeMultipleSteps": "58533", + "VaultVersionTest_test_upgradeNonAdminFails": "38860", + "VaultVersionTest_test_upgradeToDifferentVaultIdFails": "42364", + "VaultVersionTest_test_upgradeToNextVersion": "83669", + "VaultVersionTest_test_upgradeToSameVersionFails": "34605", + "VaultVersionTest_test_upgradeToSkipVersionFails": "43074", + "VaultVersionTest_test_upgradeToUnapprovedImplementationFails": "46371", + "VaultVersionTest_test_upgradeToZeroAddressFails": "36640", + "VaultVersionTest_test_upgradeWithInvalidCallDataFails": "60718" } \ No newline at end of file diff --git a/snapshots/VaultsRegistryTest.json b/snapshots/VaultsRegistryTest.json index 5456d7ba..1e58d9a1 100644 --- a/snapshots/VaultsRegistryTest.json +++ b/snapshots/VaultsRegistryTest.json @@ -11,10 +11,10 @@ "VaultsRegistryTest_test_initialize": "53876", "VaultsRegistryTest_test_initialize_alreadyInitialized": "27356", "VaultsRegistryTest_test_initialize_zeroAddress": "24983", - "VaultsRegistryTest_test_removeFactory": "28212", + "VaultsRegistryTest_test_removeFactory": "32212", "VaultsRegistryTest_test_removeFactory_alreadyRemoved": "34077", "VaultsRegistryTest_test_removeFactory_notOwner": "25794", - "VaultsRegistryTest_test_removeVaultImpl": "28163", + "VaultsRegistryTest_test_removeVaultImpl": "32163", "VaultsRegistryTest_test_removeVaultImpl_alreadyRemoved": "34044", "VaultsRegistryTest_test_removeVaultImpl_notOwner": "25750" } \ No newline at end of file diff --git a/test/BalancedCurator.t.sol b/test/BalancedCurator.t.sol new file mode 100644 index 00000000..c4ab689d --- /dev/null +++ b/test/BalancedCurator.t.sol @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from "forge-std/Test.sol"; +import {ISubVaultsCurator} from "../contracts/interfaces/ISubVaultsCurator.sol"; +import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; + +contract BalancedCuratorTest is Test { + BalancedCurator public curator; + + // Test addresses for vaults + address[] public subVaults; + address public ejectingVault; + + function setUp() public { + // Deploy the BalancedCurator + curator = new BalancedCurator(); + + // Set up test vault addresses + subVaults = new address[](5); + for (uint256 i = 0; i < 5; i++) { + subVaults[i] = address(uint160(0x1000 + i)); + } + + // Set up an ejecting vault (will be one of the subVaults in some tests) + ejectingVault = address(uint160(0x2000)); + } + + function test_getDeposits_normalDistribution() public view { + // 100 ETH to distribute across 5 vaults + uint256 assetsToDeposit = 100 ether; + address[] memory vaults = subVaults; + + // No ejecting vault + ISubVaultsCurator.Deposit[] memory deposits = curator.getDeposits(assetsToDeposit, vaults, address(0)); + + // Verify deposits + assertEq(deposits.length, 5, "Should return 5 deposit structs"); + + // Each vault should get an equal amount + uint256 expectedPerVault = 20 ether; // 100 ETH / 5 vaults + + for (uint256 i = 0; i < deposits.length; i++) { + assertEq(deposits[i].vault, vaults[i], "Vault address mismatch"); + assertEq(deposits[i].assets, expectedPerVault, "Assets not evenly distributed"); + } + } + + function test_getDeposits_withEjectingVault() public view { + // 100 ETH to distribute across 5 vaults, but one is ejecting + uint256 assetsToDeposit = 100 ether; + address[] memory vaults = subVaults; + address ejecting = vaults[2]; // The third vault is ejecting + + ISubVaultsCurator.Deposit[] memory deposits = curator.getDeposits(assetsToDeposit, vaults, ejecting); + + // Verify deposits + assertEq(deposits.length, 5, "Should return 5 deposit structs"); + + // Each vault except the ejecting one should get an equal amount + uint256 expectedPerVault = 25 ether; // 100 ETH / 4 vaults + + for (uint256 i = 0; i < deposits.length; i++) { + assertEq(deposits[i].vault, vaults[i], "Vault address mismatch"); + if (vaults[i] == ejecting) { + assertEq(deposits[i].assets, 0, "Ejecting vault should receive 0 assets"); + } else { + assertEq(deposits[i].assets, expectedPerVault, "Assets not correctly distributed"); + } + } + } + + function test_getDeposits_smallAmount() public view { + // 5 ETH to distribute across 5 vaults + uint256 assetsToDeposit = 5 ether; + address[] memory vaults = subVaults; + + ISubVaultsCurator.Deposit[] memory deposits = curator.getDeposits(assetsToDeposit, vaults, address(0)); + + // Verify deposits + assertEq(deposits.length, 5, "Should return 5 deposit structs"); + + // Each vault should get an equal amount + uint256 expectedPerVault = 1 ether; // 5 ETH / 5 vaults + + for (uint256 i = 0; i < deposits.length; i++) { + assertEq(deposits[i].vault, vaults[i], "Vault address mismatch"); + assertEq(deposits[i].assets, expectedPerVault, "Assets not evenly distributed"); + } + } + + function test_getDeposits_unevenDivision() public view { + // 103 ETH to distribute across 5 vaults + uint256 assetsToDeposit = 103 ether; + address[] memory vaults = subVaults; + + ISubVaultsCurator.Deposit[] memory deposits = curator.getDeposits(assetsToDeposit, vaults, address(0)); + + // Verify deposits + assertEq(deposits.length, 5, "Should return 5 deposit structs"); + + // Each vault should get an equal amount + uint256 expectedPerVault = 20.6 ether; // 103 ETH / 5 vaults = 20.6 ETH + uint256 totalDistributed = 0; + + for (uint256 i = 0; i < deposits.length; i++) { + assertEq(deposits[i].vault, vaults[i], "Vault address mismatch"); + assertEq(deposits[i].assets, expectedPerVault, "Assets not evenly distributed"); + totalDistributed += deposits[i].assets; + } + + // Total distributed should be 103 ETH + assertEq(totalDistributed, 103 ether, "Total distributed amount incorrect"); + } + + function test_getDeposits_emptyVaults() public { + // 100 ETH to distribute, but no vaults + uint256 assetsToDeposit = 100 ether; + address[] memory vaults = new address[](0); + + // Should revert with EmptySubVaults error + vm.expectRevert(Errors.EmptySubVaults.selector); + curator.getDeposits(assetsToDeposit, vaults, address(0)); + } + + function test_getDeposits_allVaultsEjecting() public { + // Setup: Only one vault and it's ejecting + uint256 assetsToDeposit = 100 ether; + address[] memory vaults = new address[](1); + vaults[0] = address(uint160(0x1000)); + + // Should revert with EmptySubVaults error because all vaults are ejecting + vm.expectRevert(Errors.EmptySubVaults.selector); + curator.getDeposits(assetsToDeposit, vaults, vaults[0]); + } + + function test_getDeposits_zeroAssetsToDeposit() public view { + // 0 ETH to exit from 5 vaults + uint256 assetsToDeposit = 0; + address[] memory vaults = subVaults; + + ISubVaultsCurator.Deposit[] memory deposits = curator.getDeposits(assetsToDeposit, vaults, address(0)); + + // Verify exit requests + assertEq(deposits.length, 0, "Should return 0 deposit structs"); + } + + function test_getExitRequests_normalDistribution() public view { + // 100 ETH to exit from 5 vaults + uint256 assetsToExit = 100 ether; + address[] memory vaults = subVaults; + + // Set up balances: each vault has 30 ETH + uint256[] memory balances = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + balances[i] = 30 ether; + } + + ISubVaultsCurator.ExitRequest[] memory exitRequests = + curator.getExitRequests(assetsToExit, vaults, balances, address(0)); + + // Verify exit requests + assertEq(exitRequests.length, 5, "Should return 5 exit structs"); + + // Each vault should exit an equal amount + uint256 expectedPerVault = 20 ether; // 100 ETH / 5 vaults + uint256 totalExited = 0; + + for (uint256 i = 0; i < exitRequests.length; i++) { + assertEq(exitRequests[i].vault, vaults[i], "Vault address mismatch"); + assertEq(exitRequests[i].assets, expectedPerVault, "Assets not evenly distributed"); + totalExited += exitRequests[i].assets; + } + + assertEq(totalExited, assetsToExit, "Total exited amount incorrect"); + } + + function test_getExitRequests_withEjectingVault() public view { + // 100 ETH to exit from 5 vaults, but one is ejecting + uint256 assetsToExit = 100 ether; + address[] memory vaults = subVaults; + address ejecting = subVaults[2]; + + // Set up balances: each vault has 30 ETH + uint256[] memory balances = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + balances[i] = 30 ether; + } + + ISubVaultsCurator.ExitRequest[] memory exitRequests = + curator.getExitRequests(assetsToExit, vaults, balances, ejecting); + + // Verify exit requests + assertEq(exitRequests.length, 5, "Should return 5 exit structs"); + + // Each vault should exit an equal amount + uint256 expectedPerVault = 25 ether; // 100 ETH / 4 vaults + uint256 totalExited = 0; + + for (uint256 i = 0; i < exitRequests.length; i++) { + assertEq(exitRequests[i].vault, vaults[i], "Vault address mismatch"); + if (vaults[i] == ejecting) { + assertEq(exitRequests[i].assets, 0, "Ejecting vault should receive 0 assets"); + continue; + } + assertEq(exitRequests[i].assets, expectedPerVault, "Assets not correctly distributed"); + totalExited += exitRequests[i].assets; + } + + assertEq(totalExited, assetsToExit, "Total exited amount incorrect"); + } + + function test_getExitRequests_unevenBalances() public view { + // 100 ETH to exit from 5 vaults with different balances + uint256 assetsToExit = 100 ether; + address[] memory vaults = subVaults; + + // Set up balances: vaults have different balances + uint256[] memory balances = new uint256[](5); + balances[0] = 10 ether; + balances[1] = 20 ether; + balances[2] = 30 ether; + balances[3] = 40 ether; + balances[4] = 50 ether; + + ISubVaultsCurator.ExitRequest[] memory exitRequests = + curator.getExitRequests(assetsToExit, vaults, balances, address(0)); + + // Verify exit requests + assertEq(exitRequests.length, 5, "Should return 5 exit structs"); + + // Initial distribution would be 20 ETH per vault, but some vaults don't have enough + // So we need to redistribute to vaults with more balance + uint256 totalExited = 0; + + // First vault should exit all of its 10 ETH + assertEq(exitRequests[0].vault, vaults[0], "Vault address mismatch"); + assertEq(exitRequests[0].assets, 10 ether, "Vault 0 should exit all of its balance"); + totalExited += exitRequests[0].assets; + + // Second vault should exit all of its 20 ETH + assertEq(exitRequests[1].vault, vaults[1], "Vault address mismatch"); + assertEq(exitRequests[1].assets, 20 ether, "Vault 1 should exit all of its balance"); + totalExited += exitRequests[1].assets; + + // Other vaults should exit the remaining amount divided equally among them + // 70 ETH remaining / 3 vaults = 23.33 ETH per vault, but rounded down + + for (uint256 i = 2; i < exitRequests.length; i++) { + assertEq(exitRequests[i].vault, vaults[i], "Vault address mismatch"); + assertLe(exitRequests[i].assets, balances[i], "Cannot exit more than balance"); + totalExited += exitRequests[i].assets; + } + + assertEq(totalExited, assetsToExit, "Total exited amount incorrect"); + } + + function test_getExitRequests_insufficientTotalBalance() public view { + // 50 ETH to exit, with varying balances + uint256 assetsToExit = 50 ether; + address[] memory vaults = subVaults; + + // Set up balances: varying amounts, total is 50 ETH + uint256[] memory balances = new uint256[](5); + balances[0] = 5 ether; + balances[1] = 10 ether; + balances[2] = 15 ether; + balances[3] = 10 ether; + balances[4] = 10 ether; + + ISubVaultsCurator.ExitRequest[] memory exitRequests = + curator.getExitRequests(assetsToExit, vaults, balances, address(0)); + + // Verify exit requests + assertEq(exitRequests.length, 5, "Should return 5 exit structs"); + + // Validate each vault's exit amount doesn't exceed its balance + uint256 totalExited = 0; + + for (uint256 i = 0; i < exitRequests.length; i++) { + assertEq(exitRequests[i].vault, vaults[i], "Vault address mismatch"); + assertLe(exitRequests[i].assets, balances[i], "Cannot exit more than balance"); + totalExited += exitRequests[i].assets; + } + + // Total exited should be close to 50 ETH (the total requested) + assertEq(totalExited, assetsToExit, "Total exited amount should match requested amount"); + } + + function test_getExitRequests_emptyVaults() public { + // 100 ETH to exit, but no vaults + uint256 assetsToExit = 100 ether; + address[] memory vaults = new address[](0); + uint256[] memory balances = new uint256[](0); + + // Should revert with EmptySubVaults error + vm.expectRevert(Errors.EmptySubVaults.selector); + curator.getExitRequests(assetsToExit, vaults, balances, address(0)); + } + + function test_getExitRequests_allVaultsEjecting() public { + // Setup: Only one vault and it's ejecting + uint256 assetsToExit = 100 ether; + address[] memory vaults = new address[](1); + vaults[0] = address(uint160(0x1000)); + uint256[] memory balances = new uint256[](1); + balances[0] = 100 ether; + + // Should revert with EmptySubVaults error because all vaults are ejecting + vm.expectRevert(Errors.EmptySubVaults.selector); + curator.getExitRequests(assetsToExit, vaults, balances, vaults[0]); + } + + function test_getExitRequests_zeroAssetsToExit() public view { + // 0 ETH to exit from 5 vaults + uint256 assetsToExit = 0; + address[] memory vaults = subVaults; + + // Set up balances: each vault has 30 ETH + uint256[] memory balances = new uint256[](5); + for (uint256 i = 0; i < 5; i++) { + balances[i] = 30 ether; + } + + ISubVaultsCurator.ExitRequest[] memory exitRequests = + curator.getExitRequests(assetsToExit, vaults, balances, address(0)); + + // Verify exit requests + assertEq(exitRequests.length, 0, "Should return 0 exit structs"); + } +} diff --git a/test/CuratorsRegistry.t.sol b/test/CuratorsRegistry.t.sol new file mode 100644 index 00000000..94cb0835 --- /dev/null +++ b/test/CuratorsRegistry.t.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from "forge-std/Test.sol"; +import {CuratorsRegistry, ICuratorsRegistry} from "../contracts/curators/CuratorsRegistry.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; + +contract CuratorsRegistryTest is Test { + CuratorsRegistry public registry; + address public owner; + address public newOwner; + address public curator; + address public nonOwner; + + function setUp() public { + // Create accounts + owner = makeAddr("owner"); + newOwner = makeAddr("newOwner"); + curator = makeAddr("curator"); + nonOwner = makeAddr("nonOwner"); + + // Deploy registry with owner as the deployer + vm.prank(owner); + registry = new CuratorsRegistry(); + } + + function test_constructor() public view { + // Verify owner is set correctly + assertEq(registry.owner(), owner, "Owner should be set to deployer"); + } + + function test_initialize() public { + // Initialize with new owner + vm.prank(owner); + registry.initialize(newOwner); + + // Check ownership transferred + assertEq(registry.owner(), newOwner, "Ownership should be transferred to new owner"); + } + + function test_initialize_zeroAddress() public { + // Try to initialize with zero address + vm.prank(owner); + vm.expectRevert(Errors.ZeroAddress.selector); + registry.initialize(address(0)); + } + + function test_initialize_alreadyInitialized() public { + // Initialize once + vm.prank(owner); + registry.initialize(newOwner); + + // Try to initialize again + vm.prank(newOwner); + vm.expectRevert(Errors.AccessDenied.selector); + registry.initialize(owner); + } + + function test_initialize_notOwner() public { + // Try to initialize as non-owner + vm.prank(nonOwner); + // The error is now a custom error in the newer Ownable version + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.initialize(newOwner); + } + + function test_addCurator() public { + vm.startPrank(owner); + + // Expect the CuratorAdded event + vm.expectEmit(true, true, false, true); + emit ICuratorsRegistry.CuratorAdded(owner, curator); + + // Add a curator + registry.addCurator(curator); + vm.stopPrank(); + + // Check curator was added + assertTrue(registry.curators(curator), "Curator should be added"); + } + + function test_addCurator_notOwner() public { + // Try to add curator as non-owner + vm.prank(nonOwner); + // The error is now a custom error in the newer Ownable version + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.addCurator(curator); + + // Verify curator was not added + assertFalse(registry.curators(curator), "Curator should not be added"); + } + + function test_removeCurator() public { + // First add a curator + vm.prank(owner); + registry.addCurator(curator); + assertTrue(registry.curators(curator), "Curator should be added"); + + vm.startPrank(owner); + + // Expect the CuratorRemoved event + vm.expectEmit(true, true, false, true); + emit ICuratorsRegistry.CuratorRemoved(owner, curator); + + // Then remove the curator + registry.removeCurator(curator); + vm.stopPrank(); + + assertFalse(registry.curators(curator), "Curator should be removed"); + } + + function test_removeCurator_notOwner() public { + // First add a curator + vm.prank(owner); + registry.addCurator(curator); + + // Try to remove curator as non-owner + vm.prank(nonOwner); + // The error is now a custom error in the newer Ownable version + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", nonOwner)); + registry.removeCurator(curator); + + // Verify curator was not removed + assertTrue(registry.curators(curator), "Curator should still be added"); + } +} diff --git a/test/EthGenesisVault.t.sol b/test/EthGenesisVault.t.sol index 0328d848..f9f0ab5b 100644 --- a/test/EthGenesisVault.t.sol +++ b/test/EthGenesisVault.t.sol @@ -92,8 +92,12 @@ contract EthGenesisVaultTest is Test, EthHelpers { assertEq(existingVault.vaultId(), keccak256("EthGenesisVault")); assertEq(existingVault.version(), 4); + address newImpl = _getOrCreateVaultImpl(VaultType.EthGenesisVault); + vm.deal(adminBefore, admin.balance + 1 ether); + _startSnapshotGas("EthGenesisVaultTest_test_upgradesCorrectly"); - _upgradeVault(VaultType.EthGenesisVault, address(existingVault)); + vm.prank(adminBefore); + existingVault.upgradeToAndCall(newImpl, "0x"); _stopSnapshotGas(); (uint128 queuedSharesAfter,,, uint128 totalExitingAssetsAfter,) = existingVault.getExitQueueData(); diff --git a/test/EthMetaVault.t.sol b/test/EthMetaVault.t.sol new file mode 100644 index 00000000..cdbdd0d5 --- /dev/null +++ b/test/EthMetaVault.t.sol @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test, stdStorage, StdStorage, console} from "forge-std/Test.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {IEthMetaVault} from "../contracts/interfaces/IEthMetaVault.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {IVaultSubVaults} from "../contracts/interfaces/IVaultSubVaults.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthMetaVault} from "../contracts/vaults/ethereum/custom/EthMetaVault.sol"; +import {EthMetaVaultFactory} from "../contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol"; +import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; +import {CuratorsRegistry} from "../contracts/curators/CuratorsRegistry.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; + +contract EthMetaVaultTest is Test, EthHelpers { + using stdStorage for StdStorage; + + ForkContracts public contracts; + EthMetaVault public metaVault; + + address public admin; + address public curator; + address public sender; + address public receiver; + address public referrer; + + // Sub vaults + address[] public subVaults; + + function setUp() public { + // Activate Ethereum fork and get the contracts + contracts = _activateEthereumFork(); + + // Set up test accounts + admin = makeAddr("admin"); + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + referrer = makeAddr("referrer"); + + // Deal ETH to accounts + vm.deal(admin, 100 ether); + vm.deal(sender, 100 ether); + + // Create a curator + curator = address(new BalancedCurator()); + + // Register the curator in the registry + vm.prank(CuratorsRegistry(_curatorsRegistry).owner()); + CuratorsRegistry(_curatorsRegistry).addCurator(curator); + + // Deploy meta vault + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + metaVault = EthMetaVault(payable(_getOrCreateVault(VaultType.EthMetaVault, admin, initParams, false))); + + // Deploy and add sub vaults + for (uint256 i = 0; i < 3; i++) { + address subVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), subVault); + subVaults.push(subVault); + + vm.prank(admin); + metaVault.addSubVault(subVault); + } + } + + function _createSubVault(address _admin) internal returns (address) { + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 5, // 5% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + return _createVault(VaultType.EthVault, _admin, initParams, false); + } + + function test_deployWithZeroAdmin() public { + // Attempt to deploy a meta vault with zero admin + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + EthMetaVaultFactory factory = _getOrCreateMetaFactory(VaultType.EthMetaVault); + vm.deal(address(this), address(this).balance + _securityDeposit); + vm.expectRevert(Errors.ZeroAddress.selector); + factory.createVault{value: _securityDeposit}(address(0), initParams); + } + + function test_deployment() public view { + // Verify the vault was deployed correctly + assertEq(metaVault.vaultId(), keccak256("EthMetaVault"), "Incorrect vault ID"); + assertEq(metaVault.version(), 5, "Incorrect version"); + assertEq(metaVault.admin(), admin, "Incorrect admin"); + assertEq(metaVault.subVaultsCurator(), curator, "Incorrect curator"); + assertEq(metaVault.capacity(), 1000 ether, "Incorrect capacity"); + assertEq(metaVault.feePercent(), 1000, "Incorrect fee percent"); + assertEq(metaVault.feeRecipient(), admin, "Incorrect fee recipient"); + + // Verify sub vaults + address[] memory storedSubVaults = metaVault.getSubVaults(); + assertEq(storedSubVaults.length, 3, "Incorrect number of sub vaults"); + for (uint256 i = 0; i < 3; i++) { + assertEq(storedSubVaults[i], subVaults[i], "Incorrect sub vault address"); + } + } + + function test_deposit() public { + uint256 depositAmount = 10 ether; + uint256 expectedShares = metaVault.convertToShares(depositAmount); + + vm.prank(sender); + _startSnapshotGas("EthMetaVaultTest_test_deposit"); + uint256 shares = metaVault.deposit{value: depositAmount}(receiver, referrer); + _stopSnapshotGas(); + + // Verify shares were minted to the receiver + assertApproxEqAbs(shares, expectedShares, 1, "Incorrect shares minted"); + assertEq(metaVault.getShares(receiver), expectedShares, "Receiver did not receive shares"); + + // Verify total assets and shares + assertApproxEqAbs(metaVault.totalAssets(), depositAmount + _securityDeposit, 1, "Incorrect total assets"); + assertApproxEqAbs(metaVault.totalShares(), expectedShares + _securityDeposit, 1, "Incorrect total shares"); + } + + function test_depositViaFallback() public { + vm.deal(address(this), 100 ether); + uint256 depositAmount = 5 ether; + uint256 expectedShares = metaVault.convertToShares(depositAmount); + + _startSnapshotGas("EthMetaVaultTest_test_depositViaFallback"); + Address.sendValue(payable(address(metaVault)), depositAmount); + _stopSnapshotGas(); + + // Verify shares were minted to the sender + assertApproxEqAbs(metaVault.getShares(address(this)), expectedShares, 1, "Sender did not receive shares"); + } + + function test_updateStateAndDeposit() public { + // First deposit to meta vault and sub vaults to establish initial state + uint256 initialDeposit = 5 ether; + vm.prank(sender); + metaVault.deposit{value: initialDeposit}(sender, address(0)); + metaVault.depositToSubVaults(); + + // Set up a new deposit + uint256 depositAmount = 10 ether; + + // Update nonces for sub vaults to prepare for state update + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Remember state before the update + uint256 totalAssetsBefore = metaVault.totalAssets(); + uint256 totalSharesBefore = metaVault.totalShares(); + uint256 receiverSharesBefore = metaVault.getShares(receiver); + + // Create harvest params + IKeeperRewards.HarvestParams memory harvestParams = _getEmptyHarvestParams(); + + // Call updateStateAndDeposit + vm.prank(sender); + _startSnapshotGas("EthMetaVaultTest_test_updateStateAndDeposit"); + uint256 shares = metaVault.updateStateAndDeposit{value: depositAmount}(receiver, referrer, harvestParams); + _stopSnapshotGas(); + + // Verify state was updated + uint256 expectedShares = metaVault.convertToShares(depositAmount); + assertEq(shares, expectedShares, "Incorrect number of shares returned"); + + // Verify deposit was processed + uint256 receiverSharesAfter = metaVault.getShares(receiver); + assertEq( + receiverSharesAfter, + receiverSharesBefore + expectedShares, + "Receiver did not receive correct number of shares" + ); + + // Verify total assets and shares were updated + uint256 totalAssetsAfter = metaVault.totalAssets(); + uint256 totalSharesAfter = metaVault.totalShares(); + assertEq(totalAssetsAfter, totalAssetsBefore + depositAmount, "Total assets not updated correctly"); + assertEq(totalSharesAfter, totalSharesBefore + expectedShares, "Total shares not updated correctly"); + + // Verify withdrawable assets + assertEq(metaVault.withdrawableAssets(), depositAmount, "Withdrawable assets incorrect after deposit"); + } + + function test_depositAndMintOsToken() public { + // First collateralize the meta vault + uint256 depositAmount = 10 ether; + vm.prank(sender); + metaVault.deposit{value: depositAmount}(sender, referrer); + metaVault.depositToSubVaults(); + + // Mint osTokens + uint256 osTokenShares = depositAmount / 2; // 50% of deposit + + vm.prank(sender); + _startSnapshotGas("EthMetaVaultTest_test_depositAndMintOsToken"); + uint256 mintedAssets = metaVault.depositAndMintOsToken{value: depositAmount}(sender, osTokenShares, referrer); + _stopSnapshotGas(); + + // Verify sender received osTokens + uint128 senderOsTokenShares = metaVault.osTokenPositions(sender); + assertEq(senderOsTokenShares, osTokenShares, "Incorrect osToken shares"); + assertGt(mintedAssets, 0, "No osToken assets minted"); + } + + function test_updateStateAndDepositAndMintOsToken() public { + // First collateralize the meta vault + uint256 depositAmount = 10 ether; + vm.prank(sender); + metaVault.deposit{value: depositAmount}(sender, referrer); + metaVault.depositToSubVaults(); + + // Set up harvest params + IKeeperRewards.HarvestParams memory harvestParams = _getEmptyHarvestParams(); + + // Mint osTokens with state update + uint256 osTokenShares = depositAmount / 2; // 50% of deposit + + vm.prank(sender); + _startSnapshotGas("EthMetaVaultTest_test_updateStateAndDepositAndMintOsToken"); + uint256 mintedAssets = metaVault.updateStateAndDepositAndMintOsToken{value: depositAmount}( + sender, osTokenShares, referrer, harvestParams + ); + _stopSnapshotGas(); + + // Verify sender received osTokens + uint128 senderOsTokenShares = metaVault.osTokenPositions(sender); + assertEq(senderOsTokenShares, osTokenShares, "Incorrect osToken shares"); + assertGt(mintedAssets, 0, "No osToken assets minted"); + } + + function test_isStateUpdateRequired() public { + // First deposit to meta vault and establish the initial state + uint256 depositAmount = 10 ether; + vm.prank(sender); + metaVault.deposit{value: depositAmount}(sender, referrer); + + // Verify initial state - should not require update + assertFalse(metaVault.isStateUpdateRequired(), "Should not require state update initially"); + + // Get current nonce + uint64 initialNonce = contracts.keeper.rewardsNonce(); + + // Increase keeper nonce by 1 - still should not require update + _setKeeperRewardsNonce(initialNonce + 1); + assertFalse(metaVault.isStateUpdateRequired(), "Should not require state update when nonce is only 1 higher"); + + // Increase keeper nonce by 1 more - now should require update + _startSnapshotGas("EthMetaVaultTest_test_isStateUpdateRequired_true"); + _setKeeperRewardsNonce(initialNonce + 2); + bool required = metaVault.isStateUpdateRequired(); + _stopSnapshotGas(); + + assertTrue(required, "Should require state update when nonce is 2 higher"); + + // Update nonces for sub vaults to match keeper + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], initialNonce + 2); + } + + // Update state + metaVault.updateState(_getEmptyHarvestParams()); + + // Verify no update required after state update + assertFalse(metaVault.isStateUpdateRequired(), "Should not require state update after updating"); + + // Test with empty sub vaults + // Create a new meta vault without sub vaults + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + EthMetaVault emptyMetaVault = + EthMetaVault(payable(_getOrCreateVault(VaultType.EthMetaVault, admin, initParams, false))); + + // Verify empty vault behavior + assertFalse(emptyMetaVault.isStateUpdateRequired(), "Empty vault should not require state update"); + + // Test when keeper nonce is less than meta vault nonce (this shouldn't happen in practice) + // First update meta vault state + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], initialNonce + 3); + } + _setKeeperRewardsNonce(initialNonce + 3); + metaVault.updateState(_getEmptyHarvestParams()); + + // Now set keeper nonce to lower value + _setKeeperRewardsNonce(initialNonce + 2); + + // Verify behavior + assertFalse(metaVault.isStateUpdateRequired(), "Should not require update when keeper nonce is lower"); + } + + function test_userClaimExitedAssets() public { + // First deposit to meta vault + uint256 depositAmount = 10 ether; + vm.prank(sender); + metaVault.deposit{value: depositAmount}(sender, referrer); + + // Deposit to sub vaults + metaVault.depositToSubVaults(); + + // Enter exit queue with all shares + uint256 senderShares = metaVault.getShares(sender); + vm.prank(sender); + uint256 positionTicket = metaVault.enterExitQueue(senderShares, sender); + uint64 exitTimestamp = uint64(vm.getBlockTimestamp()); + + // Update nonces for sub vaults to process exit queue + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Update state to process the exit queue + metaVault.updateState(_getEmptyHarvestParams()); + + // Process exits in sub vaults + for (uint256 i = 0; i < subVaults.length; i++) { + // Ensure sub vaults have enough ETH to process exits + vm.deal(subVaults[i], 5 ether); + + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(subVaults[i], 0, 0); + IVaultState(subVaults[i]).updateState(harvestParams); + } + + // Prepare exit requests for claiming from sub vaults to meta vault + IVaultSubVaults.SubVaultExitRequest[] memory exitRequests = + new IVaultSubVaults.SubVaultExitRequest[](subVaults.length); + for (uint256 i = 0; i < subVaults.length; i++) { + exitRequests[i] = IVaultSubVaults.SubVaultExitRequest({ + vault: subVaults[i], + exitQueueIndex: uint256(IVaultEnterExit(subVaults[i]).getExitQueueIndex(0)), + timestamp: exitTimestamp + }); + } + + // Fast-forward time to allow claiming from sub vaults + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Claim exited assets from sub vaults to meta vault + metaVault.claimSubVaultsExitedAssets(exitRequests); + + // Update nonces for sub vaults to process exit queue + newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Update state to process the exit queue + metaVault.updateState(_getEmptyHarvestParams()); + + // Get exit queue index in meta vault + int256 exitQueueIndex = metaVault.getExitQueueIndex(positionTicket); + require(exitQueueIndex >= 0, "Exit queue position not found"); + + // Check sender's ETH balance before claim + uint256 senderBalanceBefore = sender.balance; + + // Have the user claim their exited assets + vm.prank(sender); + _startSnapshotGas("EthMetaVaultTest_test_userClaimExitedAssets"); + metaVault.claimExitedAssets(positionTicket, exitTimestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Check sender's ETH balance after claim + uint256 senderBalanceAfter = sender.balance; + + // Verify sender received their ETH (approximately the original deposit minus fees) + // The exact amount might be slightly less due to fees and rounding + uint256 amountReceived = senderBalanceAfter - senderBalanceBefore; + assertEq(amountReceived, depositAmount, "User received significantly less than expected"); + + // Verify exit queue data updated + (, uint128 unclaimedAssets,,,) = metaVault.getExitQueueData(); + assertLt(unclaimedAssets, depositAmount, "Unclaimed assets not reduced after claim"); + + // Verify user can't claim again (should revert) + vm.prank(sender); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + metaVault.claimExitedAssets(positionTicket, exitTimestamp, uint256(exitQueueIndex)); + } + + function test_donateAssets_basic() public { + uint256 donationAmount = 1 ether; + + // Get vault state before donation + uint256 vaultBalanceBefore = address(metaVault).balance; + uint256 totalAssetsBefore = metaVault.totalAssets(); + + // Approve GNO token for donation + vm.startPrank(sender); + + // Check event emission + vm.expectEmit(true, true, false, true); + emit IVaultState.AssetsDonated(sender, donationAmount); + + // Make donation + metaVault.donateAssets{value: donationAmount}(); + vm.stopPrank(); + + // Verify donation was received + assertEq(address(metaVault).balance, vaultBalanceBefore + donationAmount, "Meta vault ETH balance increased"); + assertEq(metaVault.totalAssets(), totalAssetsBefore, "Meta vault total assets didn't increase"); + + // Process donation by updating state + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + metaVault.updateState(_getEmptyHarvestParams()); + + assertEq(address(metaVault).balance, vaultBalanceBefore + donationAmount, "Meta vault ETH balance increased"); + assertEq(metaVault.totalAssets(), totalAssetsBefore + donationAmount, "Meta vault total assets increased"); + } + + function test_donateAssets_zeroValue() public { + // Trying to donate 0 ETH should revert + vm.prank(sender); + vm.expectRevert(Errors.InvalidAssets.selector); + metaVault.donateAssets{value: 0}(); + } + + function _getEmptyHarvestParams() internal pure returns (IKeeperRewards.HarvestParams memory) { + bytes32[] memory emptyProof; + return + IKeeperRewards.HarvestParams({rewardsRoot: bytes32(0), proof: emptyProof, reward: 0, unlockedMevReward: 0}); + } + + function _setVaultRewardsNonce(address vault, uint64 rewardsNonce) internal { + stdstore.enable_packed_slots().target(address(contracts.keeper)).sig("rewards(address)").with_key(vault).depth( + 1 + ).checked_write(rewardsNonce); + } + + function _setKeeperRewardsNonce(uint64 rewardsNonce) internal { + stdstore.enable_packed_slots().target(address(contracts.keeper)).sig("rewardsNonce()").checked_write( + rewardsNonce + ); + } +} diff --git a/test/VaultEthStaking.t.sol b/test/VaultEthStaking.t.sol index 27c4bd98..d255faa1 100644 --- a/test/VaultEthStaking.t.sol +++ b/test/VaultEthStaking.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.22; import {Test} from "forge-std/Test.sol"; import {IKeeperValidators} from "../contracts/interfaces/IKeeperValidators.sol"; import {IVaultValidators} from "../contracts/interfaces/IVaultValidators.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; import {EthHelpers} from "./helpers/EthHelpers.sol"; import {Errors} from "../contracts/libraries/Errors.sol"; @@ -480,4 +481,44 @@ contract VaultEthStakingTest is Test, EthHelpers { // Clean up _stopOracleImpersonate(address(contracts.keeper)); } + + function test_donateAssets_basic() public { + uint256 donationAmount = 1 ether; + + // Get vault state before donation + uint256 totalAssetsBefore = vault.totalAssets(); + uint256 vaultBalanceBefore = address(vault).balance; + + // Check event emission + vm.expectEmit(true, true, false, true); + emit IVaultState.AssetsDonated(sender, donationAmount); + + // Make donation + vm.prank(sender); + vault.donateAssets{value: donationAmount}(); + + // Verify donation was received + assertEq(address(vault).balance, vaultBalanceBefore + donationAmount, "Vault balance didn't increase"); + + // Donate assets aren't immediately reflected in totalAssets until state update + assertEq(vault.totalAssets(), totalAssetsBefore, "Total assets shouldn't change before state update"); + + // Update state to process donation + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Now the vault's total assets should increase + assertEq( + vault.totalAssets(), + totalAssetsBefore + donationAmount, + "Total assets should include donation after state update" + ); + } + + function test_donateAssets_zeroValue() public { + // Trying to donate 0 ETH should revert + vm.prank(sender); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.donateAssets{value: 0}(); + } } diff --git a/test/VaultSubVaults.t.sol b/test/VaultSubVaults.t.sol new file mode 100644 index 00000000..574016c7 --- /dev/null +++ b/test/VaultSubVaults.t.sol @@ -0,0 +1,1397 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test, stdStorage, StdStorage, console} from "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {IEthVault} from "../contracts/interfaces/IEthVault.sol"; +import {IEthMetaVault} from "../contracts/interfaces/IEthMetaVault.sol"; +import {IVaultSubVaults} from "../contracts/interfaces/IVaultSubVaults.sol"; +import {IKeeperRewards} from "../contracts/interfaces/IKeeperRewards.sol"; +import {IVaultState} from "../contracts/interfaces/IVaultState.sol"; +import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; +import {IVaultEnterExit} from "../contracts/interfaces/IVaultEnterExit.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthMetaVault} from "../contracts/vaults/ethereum/custom/EthMetaVault.sol"; +import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; +import {CuratorsRegistry} from "../contracts/curators/CuratorsRegistry.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; + +contract VaultSubVaultsTest is Test, EthHelpers { + using stdStorage for StdStorage; + + bytes32 private constant exitQueueEnteredTopic = keccak256("ExitQueueEntered(address,address,uint256,uint256)"); + + struct ExitRequest { + address vault; + uint256 positionTicket; + uint64 timestamp; + } + + ForkContracts public contracts; + EthMetaVault public metaVault; + address public admin; + address public curator; + + // Sub vaults + address[] public subVaults; + + function setUp() public { + // Activate fork and get contracts + contracts = _activateEthereumFork(); + + // Set up accounts + admin = makeAddr("admin"); + vm.deal(admin, 100 ether); + + // Create a curator + curator = address(new BalancedCurator()); + + vm.prank(CuratorsRegistry(_curatorsRegistry).owner()); + CuratorsRegistry(_curatorsRegistry).addCurator(curator); + + // Deploy meta vault + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + metaVault = EthMetaVault(payable(_getOrCreateVault(VaultType.EthMetaVault, admin, initParams, false))); + + // Deploy and add sub vaults + for (uint256 i = 0; i < 3; i++) { + address subVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), subVault); + subVaults.push(subVault); + + vm.prank(admin); + metaVault.addSubVault(subVault); + } + + // Deposit funds to meta vault + vm.deal(address(this), 10 ether); + metaVault.deposit{value: 10 ether}(address(this), address(0)); + } + + function test_setSubVaultsCurator_notAdmin() public { + // Setup + address nonAdmin = makeAddr("nonAdmin"); + address newCurator = makeAddr("newCurator"); + + // Register the new curator in the curators registry + vm.prank(CuratorsRegistry(_curatorsRegistry).owner()); + CuratorsRegistry(_curatorsRegistry).addCurator(newCurator); + + // Action & Assert: Expect revert when a non-admin tries to set the curator + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + metaVault.setSubVaultsCurator(newCurator); + } + + function test_setSubVaultsCurator_zeroAddress() public { + // Action & Assert: Expect revert when trying to set the curator to the zero address + vm.prank(admin); + vm.expectRevert(Errors.ZeroAddress.selector); + metaVault.setSubVaultsCurator(address(0)); + } + + function test_setSubVaultsCurator_sameValue() public { + // Setup: Get the current curator + address currentCurator = metaVault.subVaultsCurator(); + + // Action & Assert: Expect revert when trying to set the curator to the current value + vm.prank(admin); + vm.expectRevert(Errors.ValueNotChanged.selector); + metaVault.setSubVaultsCurator(currentCurator); + } + + function test_setSubVaultsCurator_notRegisteredCurator() public { + // Setup: Create a new curator address that is not registered + address unregisteredCurator = makeAddr("unregisteredCurator"); + + // Action & Assert: Expect revert when trying to set an unregistered curator + vm.prank(admin); + vm.expectRevert(Errors.InvalidCurator.selector); + metaVault.setSubVaultsCurator(unregisteredCurator); + } + + function test_setSubVaultsCurator_success() public { + // Setup: Create and register a new curator + address newCurator = makeAddr("newCurator"); + vm.prank(CuratorsRegistry(_curatorsRegistry).owner()); + CuratorsRegistry(_curatorsRegistry).addCurator(newCurator); + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_setSubVaultsCurator_success"); + + // Expect the SubVaultsCuratorUpdated event + vm.expectEmit(true, false, false, true); + emit IVaultSubVaults.SubVaultsCuratorUpdated(admin, newCurator); + + // Action: Set the new curator + vm.prank(admin); + metaVault.setSubVaultsCurator(newCurator); + + // Stop gas measurement + _stopSnapshotGas(); + + // Assert: Verify the curator was updated + assertEq(metaVault.subVaultsCurator(), newCurator); + } + + function test_addSubVault_notAdmin() public { + // Setup: Create a new sub vault + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + // Setup: Create a non-admin user + address nonAdmin = makeAddr("nonAdmin"); + + // Action & Assert: Non-admin cannot add a sub vault + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + metaVault.addSubVault(newSubVault); + } + + function test_addSubVault_zeroAddress() public { + // Action & Assert: Cannot add zero address as sub vault + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + metaVault.addSubVault(address(0)); + } + + function test_addSubVault_sameVaultAddress() public { + // Action & Assert: Cannot add meta vault itself as a sub vault + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + metaVault.addSubVault(address(metaVault)); + } + + function test_addSubVault_notRegisteredVault() public { + // Setup: Create an address that's not registered as a vault + address fakeVault = makeAddr("fakeVault"); + + // Action & Assert: Cannot add non-registered vault + vm.prank(admin); + vm.expectRevert(Errors.InvalidVault.selector); + metaVault.addSubVault(fakeVault); + } + + function test_addSubVault_alreadyAddedSubVault() public { + // Setup: Get an existing sub vault + address existingSubVault = subVaults[0]; + + // Action & Assert: Cannot add already added sub vault + vm.prank(admin); + vm.expectRevert(Errors.AlreadyAdded.selector); + metaVault.addSubVault(existingSubVault); + } + + function test_addSubVault_moreThanMaxSubVaults() public { + // We already have 3 sub vaults from setUp, so we need to add 47 more to reach the max of 50 + for (uint256 i = 0; i < 47; i++) { + // Create and collateralize a new sub vault + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + // Add the sub vault + vm.prank(admin); + metaVault.addSubVault(newSubVault); + } + + // Verify we now have exactly 50 sub vaults + assertEq(metaVault.getSubVaults().length, 50, "Should have 50 sub vaults"); + + // Try to add one more (the 51st) + address oneMoreVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), oneMoreVault); + + // This should revert with CapacityExceeded + vm.prank(admin); + vm.expectRevert(Errors.CapacityExceeded.selector); + metaVault.addSubVault(oneMoreVault); + + // Verify the number of sub vaults remains at 50 + assertEq(metaVault.getSubVaults().length, 50, "Should still have 50 sub vaults"); + } + + function test_addSubVault_notCollateralized() public { + // Setup: Create a new sub vault but don't collateralize it + address newSubVault = _createSubVault(admin); + + // Action & Assert: Cannot add non-collateralized vault + vm.prank(admin); + vm.expectRevert(Errors.NotCollateralized.selector); + metaVault.addSubVault(newSubVault); + } + + function test_addSubVault_unprocessedLegacyExitQueueTickets() public { + // 1. Create a new sub vault + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + // 3. Mock getExitQueueData to simulate unprocessed legacy exit queue tickets + bytes memory getExitQueueDataSelector = abi.encodeWithSignature("getExitQueueData()"); + bytes memory mockReturnData = abi.encode( + uint128(0), // queuedShares + uint128(0), // unclaimedAssets + uint128(100), // totalExitingTickets - NON-ZERO! + uint128(10 ether), // totalExitingAssets - NON-ZERO! + uint256(0) // totalTickets + ); + vm.mockCall(newSubVault, getExitQueueDataSelector, mockReturnData); + + // 4. Verify the mock is working + (,, uint128 totalExitingTickets, uint128 totalExitingAssets,) = IVaultState(newSubVault).getExitQueueData(); + assertTrue( + totalExitingTickets > 0 && totalExitingAssets > 0, "Mock should return unprocessed exit queue tickets" + ); + + // 5. Try to add the vault to the meta vault + vm.prank(admin); + vm.expectRevert(Errors.ExitRequestNotProcessed.selector); + metaVault.addSubVault(newSubVault); + + // 6. Verify the vault wasn't added + address[] memory subVaultsAfter = metaVault.getSubVaults(); + bool found = false; + for (uint256 i = 0; i < subVaultsAfter.length; i++) { + if (subVaultsAfter[i] == newSubVault) { + found = true; + break; + } + } + assertFalse(found, "Vault with unprocessed exit queue tickets should not be added"); + + // 7. Clear the mock after the test + vm.clearMockedCalls(); + } + + function test_addSubVault_notHarvested() public { + // Setup: Create and collateralize a new sub vault + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + // Setup: Set different rewards nonce for the new vault + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(newSubVault, 1 ether, 0); + IVaultState(newSubVault).updateState(harvestParams); + + // Action & Assert: Cannot add vault with different rewards nonce + vm.prank(admin); + vm.expectRevert(Errors.NotHarvested.selector); + metaVault.addSubVault(newSubVault); + } + + function test_addSubVault_firstSubVault() internal { + // create new meta vault + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + EthMetaVault newMetaVault = + EthMetaVault(payable(_getOrCreateVault(VaultType.EthMetaVault, admin, initParams, false))); + + // create new sub vault + address subVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), subVault); + + // check nonce increased for sub vault + (, uint256 nonce) = contracts.keeper.rewards(subVault); + assertGt(nonce, 0, "Nonce should be greater than 0"); + + // Expect the RewardsNonceUpdated event + vm.expectEmit(true, true, true, true); + emit IVaultSubVaults.RewardsNonceUpdated(nonce); + + // Start gas measurement + _startSnapshotGas("test_addSubVault_firstSubVault"); + + // Action: Add the new sub vault + vm.prank(admin); + newMetaVault.addSubVault(subVault); + + // Stop gas measurement + _stopSnapshotGas(); + + // Assert: Verify the sub vault was added + address[] memory subVaultsAfter = newMetaVault.getSubVaults(); + assertEq(subVaultsAfter.length, 1, "Sub vaults length should be 1"); + assertEq(subVaultsAfter[0], subVault, "Sub vault address mismatch"); + } + + function test_addSubVault_success() public { + // Setup: Create and collateralize a new sub vault + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_addSubVault_success"); + + // Expect the SubVaultAdded event + vm.expectEmit(true, true, false, true); + emit IVaultSubVaults.SubVaultAdded(admin, newSubVault); + + // Action: Add the new sub vault + vm.prank(admin); + metaVault.addSubVault(newSubVault); + + // Stop gas measurement + _stopSnapshotGas(); + + // Assert: Verify the sub vault was added + address[] memory subVaultsAfter = metaVault.getSubVaults(); + bool found = false; + for (uint256 i = 0; i < subVaultsAfter.length; i++) { + if (subVaultsAfter[i] == newSubVault) { + found = true; + break; + } + } + assertTrue(found, "Sub vault was not added correctly"); + } + + function test_ejectSubVault_notAdmin() public { + // Setup: Get a sub vault to eject + address subVaultToEject = subVaults[0]; + + // Setup: Create a non-admin user + address nonAdmin = makeAddr("nonAdmin"); + + // Action & Assert: Non-admin cannot eject a sub vault + vm.prank(nonAdmin); + vm.expectRevert(Errors.AccessDenied.selector); + metaVault.ejectSubVault(subVaultToEject); + } + + function test_ejectSubVault_alreadyEjecting() public { + // Setup: Get sub vaults to eject + address firstSubVault = subVaults[0]; + address secondSubVault = subVaults[1]; + + // Deposit to sub vaults first to ensure they have staked shares + vm.prank(admin); + metaVault.depositToSubVaults(); + + // Eject the first sub vault + vm.prank(admin); + metaVault.ejectSubVault(firstSubVault); + + // Action & Assert: Cannot eject another sub vault while one is already being ejected + vm.prank(admin); + vm.expectRevert(Errors.EjectingVault.selector); + metaVault.ejectSubVault(secondSubVault); + } + + function test_ejectSubVault_singleSubVaultLeft() public { + // eject all the vaults until the last one + for (uint256 i = 0; i < 2; i++) { + vm.prank(admin); + metaVault.ejectSubVault(subVaults[i]); + } + subVaults = metaVault.getSubVaults(); + assertEq(subVaults.length, 1, "Should have 1 sub vault left"); + + // Action & Assert: Cannot eject the last sub vault + vm.prank(admin); + vm.expectRevert(Errors.EmptySubVaults.selector); + metaVault.ejectSubVault(subVaults[0]); + } + + function test_ejectSubVault_notInSubVaults() public { + // Setup: Create a vault that's not a sub vault + address nonSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), nonSubVault); + + // Action & Assert: Cannot eject a vault that's not in sub vaults + vm.prank(admin); + vm.expectRevert(Errors.AlreadyRemoved.selector); + metaVault.ejectSubVault(nonSubVault); + } + + function test_ejectSubVault_emptySubVault() public { + // Setup: Get a sub vaults to eject + address subVault1ToEject = subVaults[0]; + address subVault2ToEject = subVaults[1]; + + // Get sub vault count before ejection + uint256 subVaultsCountBefore = metaVault.getSubVaults().length; + + // Start gas measurement + _startSnapshotGas("test_ejectSubVault_emptySubVault"); + + // Expect SubVaultEjected event + vm.expectEmit(true, true, false, false); + emit IVaultSubVaults.SubVaultEjected(admin, subVault1ToEject); + + // Action: Eject the sub vault + vm.prank(admin); + metaVault.ejectSubVault(subVault1ToEject); + + // Stop gas measurement + _stopSnapshotGas(); + + // Assert: Verify the sub vault was removed from the list + address[] memory subVaultsAfter = metaVault.getSubVaults(); + assertEq(subVaultsAfter.length, subVaultsCountBefore - 1, "Sub vault should be removed"); + + // Expect SubVaultEjected event + vm.expectEmit(true, true, false, false); + emit IVaultSubVaults.SubVaultEjected(admin, subVault2ToEject); + + // Can remove another sub vault + vm.prank(admin); + metaVault.ejectSubVault(subVault2ToEject); + + // Assert: Verify the sub vault was removed from the list + subVaultsAfter = metaVault.getSubVaults(); + assertEq(subVaultsAfter.length, subVaultsCountBefore - 2, "Sub vault should be removed"); + } + + function test_ejectSubVault_subVaultWithShares() public { + // Setup: Get a sub vault to eject + address subVaultToEject = subVaults[0]; + + // Deposit to sub vaults to get collateralized state + vm.prank(admin); + metaVault.depositToSubVaults(); + + // Start gas measurement + _startSnapshotGas("test_ejectSubVault_subVaultWithShares"); + + // Expect the ExitQueueEntered event + vm.expectEmit(true, true, false, false, subVaultToEject); + emit IVaultEnterExit.ExitQueueEntered(address(metaVault), address(metaVault), 0, 0); + + // Action: Eject the sub vault + vm.prank(admin); + metaVault.ejectSubVault(subVaultToEject); + + // Stop gas measurement + _stopSnapshotGas(); + + assertEq(metaVault.ejectingSubVault(), subVaultToEject); + + // And verify it's in the list + bool found = false; + address[] memory subVaultsAfter = metaVault.getSubVaults(); + for (uint256 i = 0; i < subVaultsAfter.length; i++) { + if (subVaultsAfter[i] == subVaultToEject) { + found = true; + break; + } + } + assertTrue(found, "Ejected sub vault should be in the list"); + } + + function test_ejectSubVault_subVaultsWithQueuedShares() public { + // Setup: Get a sub vault to eject + address subVaultToEject = subVaults[0]; + + // Deposit to sub vaults to get collateralized state + metaVault.depositToSubVaults(); + + // user enters exit queue + metaVault.enterExitQueue(metaVault.getShares(address(this)) / 2, address(this)); + + // Update state for the sub vaults + _setEthVaultReward(address(subVaultToEject), 0, 0); + uint64 currentNonce = contracts.keeper.rewardsNonce(); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], currentNonce); + } + + // Expect the ExitQueueEntered event + vm.expectEmit(true, true, false, false, subVaultToEject); + emit IVaultEnterExit.ExitQueueEntered(address(metaVault), address(metaVault), 0, 0); + + metaVault.updateState(_getEmptyHarvestParams()); + + IVaultSubVaults.SubVaultState memory stateBefore = metaVault.subVaultsStates(subVaultToEject); + assertGt(stateBefore.queuedShares, 0, "Queued shares should be greater than 0"); + assertGt(stateBefore.stakedShares, 0, "Staked shares should be greater than 0"); + + // Action: Eject the sub vault + vm.prank(admin); + metaVault.ejectSubVault(subVaultToEject); + IVaultSubVaults.SubVaultState memory stateAfter = metaVault.subVaultsStates(subVaultToEject); + assertEq( + stateBefore.queuedShares + stateBefore.stakedShares, + stateAfter.queuedShares, + "Queued shares should be equal" + ); + assertEq(stateAfter.stakedShares, 0, "Staked shares should be 0"); + } + + function test_depositToSubVaults_notHarvested() public { + // Setup: Make the meta vault appear not harvested + _setEthVaultReward(subVaults[0], 0, 0); + _setEthVaultReward(subVaults[0], 0, 0); + + // Action & Assert: Expect revert when trying to deposit when not harvested + vm.expectRevert(Errors.NotHarvested.selector); + metaVault.depositToSubVaults(); + } + + function test_depositToSubVaults_emptySubVaults() public { + // Setup: Create a new meta vault + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + EthMetaVault newMetaVault = + EthMetaVault(payable(_getOrCreateVault(VaultType.EthMetaVault, admin, initParams, false))); + + // Action & Assert: Expect revert when trying to deposit to empty sub vaults + vm.prank(admin); + vm.expectRevert(Errors.EmptySubVaults.selector); + newMetaVault.depositToSubVaults(); + } + + function test_depositToSubVaults_noAvailableAssets() public { + vm.deal(address(metaVault), 0); + vm.expectRevert(Errors.InvalidAssets.selector); + metaVault.depositToSubVaults(); + } + + function test_depositToSubVaults_singleSubVault() public { + // Setup: Remove all but one sub vault + for (uint256 i = 1; i < subVaults.length; i++) { + vm.prank(admin); + metaVault.ejectSubVault(subVaults[i]); + } + + // Verify there's only one sub vault left + address[] memory remainingSubVaults = metaVault.getSubVaults(); + assertEq(remainingSubVaults.length, 1, "Should have only one sub vault"); + + // Get initial state of the remaining sub vault + address depositSubVault = remainingSubVaults[0]; + IVaultSubVaults.SubVaultState memory initialState = metaVault.subVaultsStates(depositSubVault); + + uint256 availableAssets = metaVault.withdrawableAssets(); + uint256 newShares = IEthVault(depositSubVault).convertToShares(availableAssets); + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_depositToSubVaults_singleSubVault"); + + // Expect the Deposited event + vm.expectEmit(true, true, true, true, depositSubVault); + emit IVaultEnterExit.Deposited(address(metaVault), address(metaVault), availableAssets, newShares, address(0)); + + // Action: Deposit to sub vaults + metaVault.depositToSubVaults(); + + // check withdrawable assets empty + assertApproxEqAbs(metaVault.withdrawableAssets(), 0, 2, "Withdrawable assets should be 0"); + + // Stop gas measurement + _stopSnapshotGas(); + + // Assert: Verify the sub vault received staked shares + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(remainingSubVaults[0]); + assertEq( + finalState.stakedShares, + initialState.stakedShares + newShares, + "Sub vault should have received staked shares" + ); + } + + function test_depositToSubVaults_multipleSubVaults() public { + // Setup: Get initial state of all sub vaults + uint256 subVaultCount = subVaults.length; + IVaultSubVaults.SubVaultState[] memory initialStates = new IVaultSubVaults.SubVaultState[](subVaultCount); + for (uint256 i = 0; i < subVaultCount; i++) { + initialStates[i] = metaVault.subVaultsStates(subVaults[i]); + } + + // Calculate available assets and expected distribution + uint256 availableAssets = metaVault.withdrawableAssets(); + uint256 assetsPerVault = availableAssets / subVaultCount; + + // Calculate expected new shares for each vault + uint256[] memory expectedNewShares = new uint256[](subVaultCount); + for (uint256 i = 0; i < subVaultCount; i++) { + expectedNewShares[i] = IEthVault(subVaults[i]).convertToShares(assetsPerVault); + } + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_depositToSubVaults_multipleSubVaults"); + + // Expect Deposited events for each sub vault + for (uint256 i = 0; i < subVaultCount; i++) { + vm.expectEmit(true, true, true, true, subVaults[i]); + emit IVaultEnterExit.Deposited( + address(metaVault), address(metaVault), assetsPerVault, expectedNewShares[i], address(0) + ); + } + + // Action: Deposit to sub vaults + metaVault.depositToSubVaults(); + + // Stop gas measurement + _stopSnapshotGas(); + + // check withdrawable assets empty + assertApproxEqAbs(metaVault.withdrawableAssets(), 0, 2, "Withdrawable assets should be 0"); + + // Assert: Verify all sub vaults received the expected staked shares + for (uint256 i = 0; i < subVaultCount; i++) { + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(subVaults[i]); + assertEq( + finalState.stakedShares, + initialStates[i].stakedShares + expectedNewShares[i], + "Sub vault should have received expected staked shares" + ); + } + } + + function test_depositToSubVaults_ejectingSubVault() public { + metaVault.depositToSubVaults(); + + // Deposit funds to meta vault + vm.deal(address(this), 10 ether); + metaVault.deposit{value: 10 ether}(address(this), address(0)); + + address ejectingSubVault = subVaults[2]; + vm.prank(metaVault.admin()); + metaVault.ejectSubVault(ejectingSubVault); + + // Setup: Get initial state of all sub vaults + uint256 subVaultCount = subVaults.length; + IVaultSubVaults.SubVaultState[] memory initialStates = new IVaultSubVaults.SubVaultState[](subVaultCount); + for (uint256 i = 0; i < subVaultCount; i++) { + initialStates[i] = metaVault.subVaultsStates(subVaults[i]); + } + + // Calculate available assets and expected distribution + uint256 availableAssets = metaVault.withdrawableAssets(); + uint256 assetsPerVault = availableAssets / (subVaultCount - 1); + + // Calculate expected new shares for each vault + uint256[] memory expectedNewShares = new uint256[](subVaultCount); + for (uint256 i = 0; i < subVaultCount; i++) { + if (ejectingSubVault == subVaults[i]) { + expectedNewShares[i] = 0; + } else { + expectedNewShares[i] = IEthVault(subVaults[i]).convertToShares(assetsPerVault); + } + } + + // Expect Deposited events for each sub vault + for (uint256 i = 0; i < subVaultCount; i++) { + if (ejectingSubVault == subVaults[i]) { + continue; + } + vm.expectEmit(true, true, true, true, subVaults[i]); + emit IVaultEnterExit.Deposited( + address(metaVault), address(metaVault), assetsPerVault, expectedNewShares[i], address(0) + ); + } + + _startSnapshotGas("test_depositToSubVaults_ejectingSubVault"); + + // Action: Deposit to sub vaults + metaVault.depositToSubVaults(); + + _stopSnapshotGas(); + + // check withdrawable assets empty + assertApproxEqAbs(metaVault.withdrawableAssets(), 0, 2, "Withdrawable assets should be 0"); + + // Assert: Verify all sub vaults received the expected staked shares + for (uint256 i = 0; i < subVaultCount; i++) { + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(subVaults[i]); + assertEq( + finalState.stakedShares, + initialStates[i].stakedShares + expectedNewShares[i], + "Sub vault should have received expected staked shares" + ); + } + } + + function test_depositToSubVaults_maxVaults() public { + // Create and add the maximum number of sub vaults (50) + address[] memory maxSubVaults = new address[](50); + maxSubVaults[0] = subVaults[0]; + maxSubVaults[1] = subVaults[1]; + maxSubVaults[2] = subVaults[2]; + for (uint256 i = 3; i < 50; i++) { + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + vm.prank(admin); + metaVault.addSubVault(newSubVault); + maxSubVaults[i] = newSubVault; + } + + // Verify we have exactly 50 sub vaults + address[] memory currentSubVaults = metaVault.getSubVaults(); + assertEq(currentSubVaults.length, 50, "Should have exactly 50 sub vaults"); + + // Get initial state of all sub vaults + IVaultSubVaults.SubVaultState[] memory initialStates = new IVaultSubVaults.SubVaultState[](50); + for (uint256 i = 0; i < 50; i++) { + initialStates[i] = metaVault.subVaultsStates(maxSubVaults[i]); + } + + // Calculate available assets and expected distribution + uint256 availableAssets = metaVault.withdrawableAssets(); + uint256 assetsPerVault = availableAssets / 50; + + // Calculate expected new shares for each vault + uint256[] memory expectedNewShares = new uint256[](50); + for (uint256 i = 0; i < 50; i++) { + expectedNewShares[i] = IEthVault(maxSubVaults[i]).convertToShares(assetsPerVault); + } + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_depositToSubVaults_maxVaults"); + + // Action: Deposit to all 50 sub vaults + metaVault.depositToSubVaults(); + + // Stop gas measurement + _stopSnapshotGas(); + + // Assert: Verify each sub vault received its portion of assets + uint256 totalStakedShares = 0; + for (uint256 i = 0; i < 50; i++) { + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(maxSubVaults[i]); + uint256 newShares = finalState.stakedShares - initialStates[i].stakedShares; + + // We want to be a bit flexible with the exact share calculation due to rounding + assertApproxEqRel( + newShares, + expectedNewShares[i], + 1e16, // 1% tolerance + string.concat("Sub vault ", vm.toString(i), " did not receive expected shares") + ); + + totalStakedShares += newShares; + } + + // Make sure total shares is approximately what we expect + uint256 totalExpectedShares = 0; + for (uint256 i = 0; i < 50; i++) { + totalExpectedShares += expectedNewShares[i]; + } + + assertApproxEqRel( + totalStakedShares, + totalExpectedShares, + 1e16, // 1% tolerance + "Total staked shares does not match expected total" + ); + } + + function test_updateState_noSubVaults() public { + // Create a new meta vault without any sub vaults + bytes memory initParams = abi.encode( + IEthMetaVault.EthMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + EthMetaVault newMetaVault = + EthMetaVault(payable(_getOrCreateVault(VaultType.EthMetaVault, admin, initParams, false))); + + // Expect revert when trying to update state with no sub vaults + vm.expectRevert(Errors.EmptySubVaults.selector); + newMetaVault.updateState(_getEmptyHarvestParams()); + } + + function test_updateState_notHarvestedFirstSubVault() public { + // Get a reference to the first sub vault + address subVault = subVaults[0]; + + // Mock the first sub vault to appear not harvested + uint64 outdatedNonce = contracts.keeper.rewardsNonce() - 2; + _setVaultRewardsNonce(subVault, outdatedNonce); + + // Expect revert when trying to update state with non-harvested sub vault + vm.expectRevert(Errors.NotHarvested.selector); + metaVault.updateState(_getEmptyHarvestParams()); + } + + function test_updateState_metaVaultHigherNonce() public { + // Set meta vault's rewards nonce higher than sub vaults + uint64 currentNonce = contracts.keeper.rewardsNonce(); + + // Set meta vault's stored nonce higher than current nonce + metaVault.updateState(_getEmptyHarvestParams()); + + // Set all sub vaults to current nonce (lower than meta vault) + uint64 lowerNonce = currentNonce - 1; + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], lowerNonce); + } + + // Expect revert when trying to update state with meta vault higher nonce + vm.expectRevert(Errors.RewardsNonceIsHigher.selector); + metaVault.updateState(_getEmptyHarvestParams()); + } + + function test_updateState_sameNonce() public { + // Set up current nonce + uint64 currentNonce = contracts.keeper.rewardsNonce(); + + // Set meta vault's stored nonce to current nonce + metaVault.updateState(_getEmptyHarvestParams()); + + // Set all sub vaults to current nonce + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], currentNonce); + } + + vm.recordLogs(); + metaVault.updateState(_getEmptyHarvestParams()); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 0); + } + + function test_updateState_notHarvestedSomeOfSubVaults() public { + // Set up different nonces for sub vaults + uint64 currentNonce = contracts.keeper.rewardsNonce(); + + metaVault.updateState(_getEmptyHarvestParams()); + _setVaultRewardsNonce(subVaults[0], currentNonce + 1); + + // Set other sub vaults to different nonce + for (uint256 i = 1; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], currentNonce - 1); + } + + // Expect revert when trying to update state with inconsistent sub vault nonces + vm.expectRevert(Errors.NotHarvested.selector); + metaVault.updateState(_getEmptyHarvestParams()); + } + + function test_updateState_unprocessedSubVaultExit() public { + metaVault.depositToSubVaults(); + + // user enters exit queue + metaVault.enterExitQueue(metaVault.getShares(address(this)), address(this)); + + // update nonce for sub vaults to trigger enter exit queue + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // update nonce for meta vault and trigger enter exit queue + uint64 timestamp = uint64(vm.getBlockTimestamp()); + metaVault.updateState(_getEmptyHarvestParams()); + + // process exits for sub vaults + IKeeperRewards.HarvestParams memory harvestParams; + for (uint256 i = 0; i < subVaults.length; i++) { + harvestParams = _setEthVaultReward(subVaults[i], 0, 0); + IVaultState(subVaults[i]).updateState(harvestParams); + } + + // set up exit requests for sub vaults + IVaultSubVaults.SubVaultExitRequest[] memory exitRequests = + new IVaultSubVaults.SubVaultExitRequest[](subVaults.length); + for (uint256 i = 0; i < subVaults.length; i++) { + exitRequests[i] = IVaultSubVaults.SubVaultExitRequest({ + vault: subVaults[i], + exitQueueIndex: uint256(IVaultEnterExit(subVaults[i]).getExitQueueIndex(0)), + timestamp: timestamp + }); + } + + // update nonce for sub vaults + newNonce += 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // try to update meta vault state with unclaimed exit positions + vm.expectRevert(Errors.UnclaimedAssets.selector); + metaVault.updateState(_getEmptyHarvestParams()); + + // claim exited assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + metaVault.claimSubVaultsExitedAssets(exitRequests); + + // succeeds + uint256 feeRecipientShares = metaVault.getShares(metaVault.feeRecipient()); + uint256 securityDepositShares = metaVault.getShares(address(metaVault)); + uint256 reservedShares = feeRecipientShares + securityDepositShares; + uint256 reservedAssets = metaVault.convertToAssets(reservedShares); + + _startSnapshotGas("test_updateState_unprocessedSubVaultExit"); + metaVault.updateState(_getEmptyHarvestParams()); + _stopSnapshotGas(); + + assertApproxEqAbs(metaVault.totalAssets(), reservedAssets, 2, "Total assets should be equal"); + assertApproxEqAbs(metaVault.totalShares(), reservedShares, 2, "Total shares should be equal"); + } + + function test_updateState_newTotalAssets() public { + metaVault.depositToSubVaults(); + + // enter exit queue for 1/3 of all user's shares + uint256 sharesToExit = metaVault.getShares(address(this)) / 3; + metaVault.enterExitQueue(sharesToExit, address(this)); + + uint256 totalAssetsBefore = metaVault.totalAssets(); + + // set equal nonce for all the sub vaults and keeper + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // update nonce for meta vault and trigger enter exit queue + vm.recordLogs(); + metaVault.updateState(_getEmptyHarvestParams()); + ExitRequest[] memory exitRequests1 = + _extractExitPositions(subVaults, vm.getRecordedLogs(), uint64(vm.getBlockTimestamp())); + assertApproxEqAbs(metaVault.totalAssets(), totalAssetsBefore, 2, "Total assets should be equal before rewards"); + + // all vaults earn 1 eth rewards + uint256 vaultReward = 1 ether; + IKeeperRewards.HarvestParams memory harvestParams; + for (uint256 i = 0; i < subVaults.length; i++) { + vm.deal(subVaults[i], 0); + harvestParams = _setEthVaultReward(subVaults[i], int160(int256(vaultReward)), 0); + IVaultState(subVaults[i]).updateState(harvestParams); + } + + // set equal nonce for all the sub vaults + newNonce += 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // check total assets updated + uint256 expectedTotalAssets = totalAssetsBefore + (vaultReward * subVaults.length); + expectedTotalAssets -= + (vaultReward * subVaults.length) * (_securityDeposit * subVaults.length) / totalAssetsBefore; + + // Expect the SubVaultsHarvested event + vm.expectEmit(false, false, false, false); + emit IVaultSubVaults.SubVaultsHarvested(int256(expectedTotalAssets - totalAssetsBefore)); + + _startSnapshotGas("test_updateState_newTotalAssets"); + metaVault.updateState(_getEmptyHarvestParams()); + _stopSnapshotGas(); + + assertApproxEqAbs(metaVault.totalAssets(), expectedTotalAssets, 3, "Total assets should have been changed"); + expectedTotalAssets = metaVault.totalAssets(); + + // enter exit queue for all user's shares + metaVault.enterExitQueue(metaVault.getShares(address(this)), address(this)); + + // set equal nonce for all the sub vaults + newNonce += 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // update nonce for meta vault and trigger enter exit queue + vm.recordLogs(); + metaVault.updateState(_getEmptyHarvestParams()); + ExitRequest[] memory exitRequests2 = + _extractExitPositions(subVaults, vm.getRecordedLogs(), uint64(vm.getBlockTimestamp())); + assertApproxEqAbs( + metaVault.totalAssets(), expectedTotalAssets, 2, "Total assets should be equal before rewards" + ); + + // all queued assets are processed for the vaults + for (uint256 i = 0; i < subVaults.length; i++) { + vm.deal(subVaults[i], 12 ether); + harvestParams = _setEthVaultReward(subVaults[i], int160(int256(vaultReward)), 0); + IVaultState(subVaults[i]).updateState(harvestParams); + } + assertEq( + metaVault.totalAssets(), expectedTotalAssets, "Total assets should not change after queued assets processed" + ); + + // set equal nonce for all the sub vaults + newNonce += 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // must fail + vm.expectRevert(Errors.UnclaimedAssets.selector); + metaVault.updateState(_getEmptyHarvestParams()); + + // claim exited assets + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + IVaultSubVaults.SubVaultExitRequest[] memory claims1 = + new IVaultSubVaults.SubVaultExitRequest[](exitRequests1.length); + for (uint256 i = 0; i < exitRequests1.length; i++) { + claims1[i] = IVaultSubVaults.SubVaultExitRequest({ + vault: exitRequests1[i].vault, + exitQueueIndex: uint256( + IVaultEnterExit(exitRequests1[i].vault).getExitQueueIndex(exitRequests1[i].positionTicket) + ), + timestamp: exitRequests1[i].timestamp + }); + } + metaVault.claimSubVaultsExitedAssets(claims1); + assertEq( + metaVault.totalAssets(), + expectedTotalAssets, + "Total assets should not change after first batch exited assets claimed" + ); + + // update state fails as half of exit requests are still not processed + vm.expectRevert(Errors.UnclaimedAssets.selector); + metaVault.updateState(_getEmptyHarvestParams()); + + IVaultSubVaults.SubVaultExitRequest[] memory claims2 = + new IVaultSubVaults.SubVaultExitRequest[](exitRequests2.length); + for (uint256 i = 0; i < exitRequests2.length; i++) { + claims2[i] = IVaultSubVaults.SubVaultExitRequest({ + vault: exitRequests2[i].vault, + exitQueueIndex: uint256( + IVaultEnterExit(exitRequests2[i].vault).getExitQueueIndex(exitRequests2[i].positionTicket) + ), + timestamp: exitRequests2[i].timestamp + }); + } + + metaVault.claimSubVaultsExitedAssets(claims2); + assertEq( + metaVault.totalAssets(), + expectedTotalAssets, + "Total assets should not change after second batch exited assets claimed" + ); + + // update state goes through + metaVault.updateState(_getEmptyHarvestParams()); + + // check all the assets processed + uint256 feeRecipientShares = metaVault.getShares(metaVault.feeRecipient()); + uint256 securityDepositShares = metaVault.getShares(address(metaVault)); + uint256 reservedShares = feeRecipientShares + securityDepositShares; + uint256 reservedAssets = metaVault.convertToAssets(reservedShares); + assertApproxEqAbs( + metaVault.totalAssets(), reservedAssets, 2, "Total assets should not change after all assets processed" + ); + assertApproxEqAbs(metaVault.totalShares(), reservedShares, 1, "Total shares should be equal to reserved shares"); + } + + function test_updateState_enterExitQueueMaxVaults() public { + // Create and add the maximum number of sub vaults (50) + address[] memory maxSubVaults = new address[](50); + maxSubVaults[0] = subVaults[0]; + maxSubVaults[1] = subVaults[1]; + maxSubVaults[2] = subVaults[2]; + for (uint256 i = 3; i < 50; i++) { + address newSubVault = _createSubVault(admin); + _collateralizeVault(address(contracts.keeper), address(contracts.validatorsRegistry), newSubVault); + + vm.prank(admin); + metaVault.addSubVault(newSubVault); + maxSubVaults[i] = newSubVault; + } + + // Verify we have exactly 50 sub vaults + address[] memory currentSubVaults = metaVault.getSubVaults(); + assertEq(currentSubVaults.length, 50, "Should have exactly 50 sub vaults"); + + // Deposit assets to all sub vaults + metaVault.depositToSubVaults(); + + // Get initial state of all sub vaults + IVaultSubVaults.SubVaultState[] memory initialStates = new IVaultSubVaults.SubVaultState[](50); + for (uint256 i = 0; i < 50; i++) { + initialStates[i] = metaVault.subVaultsStates(maxSubVaults[i]); + assertGt(initialStates[i].stakedShares, 0, "Sub vault should have staked shares after deposit"); + } + + // Have users enter the exit queue with all their shares + uint256 userShares = metaVault.getShares(address(this)); + metaVault.enterExitQueue(userShares, address(this)); + + // Update nonces for all sub vaults to the same value to allow updateState to work + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < 50; i++) { + _setVaultRewardsNonce(maxSubVaults[i], newNonce); + } + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_updateState_enterExitQueueMaxVaults"); + + // Run updateState to process the exit queue with 50 sub vaults + vm.recordLogs(); // Record logs to extract exit events + metaVault.updateState(_getEmptyHarvestParams()); + + // Stop gas measurement + _stopSnapshotGas(); + + // Extract exit positions from logs + Vm.Log[] memory logs = vm.getRecordedLogs(); + ExitRequest[] memory exitRequests = _extractExitPositions(maxSubVaults, logs, uint64(vm.getBlockTimestamp())); + + // Verify the correct number of exit requests were created + assertGt(exitRequests.length, 0, "Should have created exit requests"); + + // Check that exit requests are well-distributed + uint256 totalQueuedShares = 0; + uint256 totalStakedSharesChange = 0; + uint256 vaultsWithExits = 0; + + for (uint256 i = 0; i < 50; i++) { + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(maxSubVaults[i]); + uint256 queuedSharesDelta = finalState.queuedShares - initialStates[i].queuedShares; + uint256 stakedSharesDelta = initialStates[i].stakedShares - finalState.stakedShares; + + // These should be equal for each sub vault (shares moved from staked to queued) + assertEq(queuedSharesDelta, stakedSharesDelta, "Queued shares delta should equal staked shares delta"); + + totalQueuedShares += queuedSharesDelta; + totalStakedSharesChange += stakedSharesDelta; + + if (queuedSharesDelta > 0) { + vaultsWithExits++; + } + } + + // Verify that all sub vaults participate equally (or close to equally) + // The number of vaults with exits should be substantial + assertGt(vaultsWithExits, 10, "At least 10 sub vaults should participate in the exit"); + + // Total shares that moved from staked to queued should be significant + assertGt(totalQueuedShares, 0, "Total queued shares should be greater than zero"); + assertEq( + totalQueuedShares, + totalStakedSharesChange, + "Total queued shares delta should equal total staked shares change" + ); + + // Compare with user shares that were exited + uint256 assetsExited = metaVault.convertToAssets(userShares); + uint256 assetsMoved = 0; + + for (uint256 i = 0; i < 50; i++) { + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(maxSubVaults[i]); + uint256 queuedSharesDelta = finalState.queuedShares - initialStates[i].queuedShares; + if (queuedSharesDelta > 0) { + assetsMoved += IVaultState(maxSubVaults[i]).convertToAssets(queuedSharesDelta); + } + } + + // Assets moved should be approximately equal to assets exited + assertApproxEqRel(assetsMoved, assetsExited, 1e16, "Assets moved should approximately equal assets exited"); + } + + function test_claimSubVaultsExitedAssets_partiallyClaimsExitedAssets() public { + // Deposit to sub vaults first + metaVault.depositToSubVaults(); + + // Get a reference to a single sub vault we'll use for the test + address testSubVault = subVaults[0]; + + // User enters exit queue with all their shares + metaVault.enterExitQueue(metaVault.getShares(address(this)), address(this)); + + // Update nonces for sub vaults to trigger exit queue processing + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Update state to process the exit queue + metaVault.updateState(_getEmptyHarvestParams()); + uint64 timestamp = uint64(vm.getBlockTimestamp()); + + IVaultSubVaults.SubVaultState memory stateBefore = metaVault.subVaultsStates(testSubVault); + + // Process the exit request but only provide small amount of funds + uint256 processedAssets = 0.1 ether; + vm.deal(testSubVault, processedAssets); + + // Now update the sub vault to process the exit + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(testSubVault, 0, 0); + IVaultState(testSubVault).updateState(harvestParams); + + // Fast-forward time to allow claiming + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Create a single exit request to claim + IVaultSubVaults.SubVaultExitRequest[] memory singleExitRequest = new IVaultSubVaults.SubVaultExitRequest[](1); + + singleExitRequest[0] = IVaultSubVaults.SubVaultExitRequest({ + vault: testSubVault, + exitQueueIndex: uint256(metaVault.getExitQueueIndex(0)), + timestamp: timestamp + }); + + uint256 metaVaultBalanceBefore = address(metaVault).balance; + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_claimSubVaultsExitedAssets_partiallyClaimsExitedAssets"); + + // Claim the exited assets + metaVault.claimSubVaultsExitedAssets(singleExitRequest); + + // Stop gas measurement + _stopSnapshotGas(); + + // Verify balance after claiming + uint256 metaVaultBalanceAfter = address(metaVault).balance; + + // The meta vault should have received the assets + assertGt(metaVaultBalanceAfter, metaVaultBalanceBefore, "Meta vault balance should increase"); + + // Check how much we actually received + uint256 claimedAssets = metaVaultBalanceAfter - metaVaultBalanceBefore; + + // Should be approximately half of the total needed assets + assertEq(claimedAssets, processedAssets, "Claimed assets should be equal to processed assets"); + + // The sub vault's queued shares should decrease but not to zero + IVaultSubVaults.SubVaultState memory stateAfter = metaVault.subVaultsStates(testSubVault); + assertLt(stateAfter.queuedShares, stateBefore.queuedShares, "Queued shares should decrease"); + assertGt(stateAfter.queuedShares, 0, "Queued shares should not be zero - only half was processed"); + } + + function test_claimSubVaultsExitedAssets_ejectingSubVault() public { + // Deposit to sub vaults first + metaVault.depositToSubVaults(); + + // Choose a sub vault to eject + address ejectingSubVault = subVaults[0]; + + // Eject the sub vault + vm.prank(admin); + metaVault.ejectSubVault(ejectingSubVault); + + // Verify the ejecting sub vault is set correctly + assertEq(metaVault.ejectingSubVault(), ejectingSubVault, "Ejecting sub vault should be set"); + + // Verify the vault has moved from staked to queued shares + IVaultSubVaults.SubVaultState memory state = metaVault.subVaultsStates(ejectingSubVault); + assertEq(state.stakedShares, 0, "Staked shares should be zero after ejection"); + assertGt(state.queuedShares, 0, "Queued shares should be positive after ejection"); + + // Now have a user enter the exit queue with all of their shares + metaVault.enterExitQueue(metaVault.getShares(address(this)), address(this)); + + // Update nonces to process exit queue + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Start gas measurement + _startSnapshotGas("VaultSubVaultsTest_test_claimSubVaultsExitedAssets_ejectionConsumesShares"); + + // Update state which should process the user's exit and consume ejecting vault's shares + metaVault.updateState(_getEmptyHarvestParams()); + uint64 timestamp = uint64(vm.getBlockTimestamp()); + + // Stop gas measurement + _stopSnapshotGas(); + + // Process the exit for sub vaults + for (uint256 i = 0; i < subVaults.length; i++) { + IKeeperRewards.HarvestParams memory harvestParams = _setEthVaultReward(subVaults[i], 0, 0); + IVaultState(subVaults[i]).updateState(harvestParams); + } + + // Fast-forward time to allow claiming + vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); + + // Create exit requests for claiming + IVaultSubVaults.SubVaultExitRequest[] memory claimRequests = new IVaultSubVaults.SubVaultExitRequest[](1); + claimRequests[0] = IVaultSubVaults.SubVaultExitRequest({ + vault: ejectingSubVault, + exitQueueIndex: uint256(IVaultEnterExit(ejectingSubVault).getExitQueueIndex(0)), + timestamp: timestamp + }); + + // Claim exited assets + metaVault.claimSubVaultsExitedAssets(claimRequests); + + // Verify the ejecting sub vault is removed from the state + assertEq(metaVault.ejectingSubVault(), address(0), "Ejecting sub vault should be removed"); + assertEq( + metaVault.subVaultsStates(ejectingSubVault).stakedShares, + 0, + "Ejecting sub vault should have zero staked shares after claim" + ); + assertEq( + metaVault.subVaultsStates(ejectingSubVault).queuedShares, + 0, + "Ejecting sub vault should have zero queued shares after claim" + ); + } + + function _createSubVault(address _admin) internal returns (address) { + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 0, // 0% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + return _createVault(VaultType.EthVault, _admin, initParams, false); + } + + function _setVaultRewardsNonce(address vault, uint64 rewardsNonce) internal { + stdstore.enable_packed_slots().target(address(contracts.keeper)).sig("rewards(address)").with_key(vault).depth( + 1 + ).checked_write(rewardsNonce); + } + + function _setKeeperRewardsNonce(uint64 rewardsNonce) internal { + stdstore.enable_packed_slots().target(address(contracts.keeper)).sig("rewardsNonce()").checked_write( + rewardsNonce + ); + } + + function _getEmptyHarvestParams() internal pure returns (IKeeperRewards.HarvestParams memory) { + bytes32[] memory emptyProof; + return + IKeeperRewards.HarvestParams({rewardsRoot: bytes32(0), proof: emptyProof, reward: 0, unlockedMevReward: 0}); + } + + function _extractExitPositions(address[] memory _subVaults, Vm.Log[] memory logs, uint64 timestamp) + internal + view + returns (ExitRequest[] memory exitRequests) + { + uint256 subVaultsCount = _subVaults.length; + uint256 exitSubVaultsCount = metaVault.ejectingSubVault() != address(0) ? subVaultsCount - 1 : subVaultsCount; + exitRequests = new ExitRequest[](exitSubVaultsCount); + uint256 subVaultIndex = 0; + for (uint256 i = 0; i < logs.length; i++) { + if (logs[i].topics[0] != exitQueueEnteredTopic) { + continue; + } + (uint256 positionTicket,) = abi.decode(logs[i].data, (uint256, uint256)); + exitRequests[subVaultIndex] = + ExitRequest({vault: logs[i].emitter, positionTicket: positionTicket, timestamp: timestamp}); + subVaultIndex++; + } + } +} diff --git a/test/gnosis/GnoMetaVault.t.sol b/test/gnosis/GnoMetaVault.t.sol new file mode 100644 index 00000000..a9145d47 --- /dev/null +++ b/test/gnosis/GnoMetaVault.t.sol @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test, stdStorage, StdStorage, console} from "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IGnoMetaVault} from "../../contracts/interfaces/IGnoMetaVault.sol"; +import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; +import {IVaultSubVaults} from "../../contracts/interfaces/IVaultSubVaults.sol"; +import {IVaultEnterExit} from "../../contracts/interfaces/IVaultEnterExit.sol"; +import {Errors} from "../../contracts/libraries/Errors.sol"; +import {GnoMetaVault} from "../../contracts/vaults/gnosis/custom/GnoMetaVault.sol"; +import {GnoMetaVaultFactory} from "../../contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol"; +import {BalancedCurator} from "../../contracts/curators/BalancedCurator.sol"; +import {CuratorsRegistry} from "../../contracts/curators/CuratorsRegistry.sol"; +import {GnoHelpers} from "../helpers/GnoHelpers.sol"; +import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; + +contract GnoMetaVaultTest is Test, GnoHelpers { + using stdStorage for StdStorage; + + ForkContracts public contracts; + GnoMetaVault public metaVault; + + address public admin; + address public curator; + address public sender; + address public receiver; + address public referrer; + + // Sub vaults + address[] public subVaults; + + // Test constants + uint256 constant GNO_AMOUNT = 10 ether; + + function setUp() public { + // Activate Gnosis fork and get contracts + contracts = _activateGnosisFork(); + + // Set up test accounts + admin = makeAddr("admin"); + sender = makeAddr("sender"); + receiver = makeAddr("receiver"); + referrer = makeAddr("referrer"); + + // Mint GNO tokens to accounts + _mintGnoToken(admin, 100 ether); + _mintGnoToken(sender, 100 ether); + _mintGnoToken(address(this), 100 ether); + + // Create a curator + curator = address(new BalancedCurator()); + + // Register the curator in the registry + vm.prank(CuratorsRegistry(_curatorsRegistry).owner()); + CuratorsRegistry(_curatorsRegistry).addCurator(curator); + + // Deploy meta vault + bytes memory initParams = abi.encode( + IGnoMetaVault.GnoMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + metaVault = GnoMetaVault(payable(_getOrCreateVault(VaultType.GnoMetaVault, admin, initParams, false))); + + // Deploy and add sub vaults + for (uint256 i = 0; i < 3; i++) { + address subVault = _createSubVault(admin); + _collateralizeGnoVault(subVault); + subVaults.push(subVault); + + vm.prank(admin); + metaVault.addSubVault(subVault); + } + } + + function _createSubVault(address _admin) internal returns (address) { + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 5, // 5% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + return _createVault(VaultType.GnoVault, _admin, initParams, false); + } + + function test_deployWithZeroAdmin() public { + // Attempt to deploy with zero admin + bytes memory initParams = abi.encode( + IGnoMetaVault.GnoMetaVaultInitParams({ + subVaultsCurator: curator, + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + + GnoMetaVaultFactory factory = _getOrCreateMetaFactory(VaultType.GnoMetaVault); + contracts.gnoToken.approve(address(factory), _securityDeposit); + vm.expectRevert(abi.encodeWithSelector(Errors.ZeroAddress.selector)); + factory.createVault(address(0), initParams); + } + + function test_deployment() public view { + // Verify the vault was deployed correctly + assertEq(metaVault.vaultId(), keccak256("GnoMetaVault"), "Incorrect vault ID"); + assertEq(metaVault.version(), 3, "Incorrect version"); + assertEq(metaVault.admin(), admin, "Incorrect admin"); + assertEq(metaVault.subVaultsCurator(), curator, "Incorrect curator"); + assertEq(metaVault.capacity(), 1000 ether, "Incorrect capacity"); + assertEq(metaVault.feePercent(), 1000, "Incorrect fee percent"); + assertEq(metaVault.feeRecipient(), admin, "Incorrect fee recipient"); + + // Verify sub vaults + address[] memory storedSubVaults = metaVault.getSubVaults(); + assertEq(storedSubVaults.length, 3, "Incorrect number of sub vaults"); + for (uint256 i = 0; i < 3; i++) { + assertEq(storedSubVaults[i], subVaults[i], "Incorrect sub vault address"); + } + } + + function test_deposit() public { + uint256 depositAmount = GNO_AMOUNT; + uint256 expectedShares = metaVault.convertToShares(depositAmount); + + // Approve tokens for deposit + vm.startPrank(sender); + IERC20(address(contracts.gnoToken)).approve(address(metaVault), depositAmount); + + _startSnapshotGas("GnoMetaVaultTest_test_deposit"); + uint256 shares = metaVault.deposit(depositAmount, receiver, referrer); + _stopSnapshotGas(); + + vm.stopPrank(); + + // Verify shares were minted to the receiver + assertEq(shares, expectedShares, "Incorrect shares minted"); + assertEq(metaVault.getShares(receiver), expectedShares, "Receiver did not receive shares"); + + // Verify total assets and shares + assertEq(metaVault.totalAssets(), depositAmount + _securityDeposit, "Incorrect total assets"); + assertEq(metaVault.totalShares(), expectedShares + _securityDeposit, "Incorrect total shares"); + } + + function test_depositToSubVaults() public { + // First deposit to meta vault + uint256 depositAmount = GNO_AMOUNT; + + vm.startPrank(sender); + IERC20(address(contracts.gnoToken)).approve(address(metaVault), depositAmount); + metaVault.deposit(depositAmount, sender, referrer); + vm.stopPrank(); + assertGt(metaVault.withdrawableAssets(), 0, "Withdrawable assets should be greater than 0"); + + // Get sub vault states before deposit + IVaultSubVaults.SubVaultState[] memory initialStates = new IVaultSubVaults.SubVaultState[](subVaults.length); + for (uint256 i = 0; i < subVaults.length; i++) { + initialStates[i] = metaVault.subVaultsStates(subVaults[i]); + } + + // Call depositToSubVaults + _startSnapshotGas("GnoMetaVaultTest_test_depositToSubVaults"); + metaVault.depositToSubVaults(); + _stopSnapshotGas(); + + // Verify withdrawable assets are empty + assertApproxEqAbs(metaVault.withdrawableAssets(), 0, 2, "Withdrawable assets should be 0"); + + // Verify sub vault balances increased + for (uint256 i = 0; i < subVaults.length; i++) { + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(subVaults[i]); + assertGt(finalState.stakedShares, initialStates[i].stakedShares, "Sub vault staked shares should increase"); + } + } + + function test_addSubVault() public { + // Create a new sub vault + address newSubVault = _createSubVault(admin); + _collateralizeGnoVault(newSubVault); + + // Get sub vault count before adding + uint256 subVaultsCountBefore = metaVault.getSubVaults().length; + + // Add the new sub vault + vm.prank(admin); + _startSnapshotGas("GnoMetaVaultTest_test_addSubVault"); + metaVault.addSubVault(newSubVault); + _stopSnapshotGas(); + + // Verify sub vault was added + address[] memory storedSubVaults = metaVault.getSubVaults(); + assertEq(storedSubVaults.length, subVaultsCountBefore + 1, "Sub vault not added"); + + // Verify approval for GNO token transfer + uint256 allowance = IERC20(address(contracts.gnoToken)).allowance(address(metaVault), newSubVault); + assertEq(allowance, type(uint256).max, "GNO token allowance not set correctly"); + } + + function test_ejectSubVault() public { + // Deposit to sub vaults first + uint256 depositAmount = GNO_AMOUNT; + + vm.startPrank(sender); + IERC20(address(contracts.gnoToken)).approve(address(metaVault), depositAmount); + metaVault.deposit(depositAmount, sender, referrer); + vm.stopPrank(); + + metaVault.depositToSubVaults(); + + // Get a sub vault to eject + address subVaultToEject = subVaults[0]; + + // Get initial state + IVaultSubVaults.SubVaultState memory initialState = metaVault.subVaultsStates(subVaultToEject); + require(initialState.stakedShares > 0, "Sub vault should have staked shares"); + + // Eject the sub vault + vm.prank(admin); + _startSnapshotGas("GnoMetaVaultTest_test_ejectSubVault"); + metaVault.ejectSubVault(subVaultToEject); + _stopSnapshotGas(); + + // Verify ejecting sub vault is set + assertEq(metaVault.ejectingSubVault(), subVaultToEject, "Ejecting sub vault not set correctly"); + + // Verify state changes + IVaultSubVaults.SubVaultState memory finalState = metaVault.subVaultsStates(subVaultToEject); + assertEq(finalState.stakedShares, 0, "Staked shares should be zero"); + assertEq(finalState.queuedShares, initialState.stakedShares, "Queued shares should equal initial staked shares"); + + // Verify GNO token allowance was revoked + uint256 allowance = IERC20(address(contracts.gnoToken)).allowance(address(metaVault), subVaultToEject); + assertEq(allowance, 0, "GNO token allowance not revoked"); + } + + function test_updateState() public { + // First deposit to meta vault and sub vaults + uint256 depositAmount = GNO_AMOUNT; + + vm.startPrank(sender); + IERC20(address(contracts.gnoToken)).approve(address(metaVault), depositAmount); + metaVault.deposit(depositAmount, sender, referrer); + vm.stopPrank(); + + metaVault.depositToSubVaults(); + + // Update nonces for sub vaults + uint64 newNonce = contracts.keeper.rewardsNonce() + 2; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + bool updateRequiredAfter = metaVault.isStateUpdateRequired(); + assertTrue(updateRequiredAfter, "State update should be required"); + + // Create harvest params + IKeeperRewards.HarvestParams memory harvestParams = _getEmptyHarvestParams(); + + // Record events to check for RewardsNonceUpdated + vm.recordLogs(); + + // Call updateState + _startSnapshotGas("GnoMetaVaultTest_test_updateState"); + metaVault.updateState(harvestParams); + _stopSnapshotGas(); + + // Check logs for RewardsNonceUpdated event + Vm.Log[] memory logs = vm.getRecordedLogs(); + bool foundEvent = false; + bytes32 rewardsNonceUpdatedTopic = keccak256("RewardsNonceUpdated(uint256)"); + + for (uint256 i = 0; i < logs.length; i++) { + if (logs[i].topics[0] == rewardsNonceUpdatedTopic) { + foundEvent = true; + uint256 eventNonce = abi.decode(logs[i].data, (uint256)); + assertEq(eventNonce, newNonce, "Event emitted with incorrect nonce"); + break; + } + } + + assertTrue(foundEvent, "RewardsNonceUpdated event was not emitted"); + + // Verify state update is no longer required + updateRequiredAfter = metaVault.isStateUpdateRequired(); + assertFalse(updateRequiredAfter, "State update should no longer be required"); + } + + function test_enterExitQueue() public { + // First deposit to meta vault + uint256 depositAmount = GNO_AMOUNT; + + vm.startPrank(sender); + IERC20(address(contracts.gnoToken)).approve(address(metaVault), depositAmount); + metaVault.deposit(depositAmount, sender, referrer); + vm.stopPrank(); + + // Get shares of sender + uint256 senderShares = metaVault.getShares(sender); + + // Enter exit queue + vm.prank(sender); + _startSnapshotGas("GnoMetaVaultTest_test_enterExitQueue"); + metaVault.enterExitQueue(senderShares, sender); + _stopSnapshotGas(); + + // Verify exit queue data + ( + uint128 queuedShares, + uint128 unclaimedAssets, + uint128 totalExitingTickets, + uint128 totalExitingAssets, + uint256 totalTickets + ) = metaVault.getExitQueueData(); + + assertEq(queuedShares, senderShares, "Queued shares incorrect"); + assertEq(unclaimedAssets, 0, "Unclaimed assets should be 0"); + assertEq(totalExitingTickets, 0, "Total exiting tickets should be 0"); + assertEq(totalExitingAssets, 0, "Total exiting assets should be 0"); + assertEq(totalTickets, 0, "Total tickets should be 0"); + } + + function test_claimExitedAssets() public { + // First deposit to meta vault + uint256 depositAmount = GNO_AMOUNT; + + vm.startPrank(sender); + IERC20(address(contracts.gnoToken)).approve(address(metaVault), depositAmount); + metaVault.deposit(depositAmount, sender, referrer); + vm.stopPrank(); + + // Deposit to sub vaults + metaVault.depositToSubVaults(); + + // Enter exit queue with all shares + uint256 senderShares = metaVault.getShares(sender); + vm.prank(sender); + uint256 positionTicket = metaVault.enterExitQueue(senderShares, sender); + uint64 exitTimestamp = uint64(block.timestamp); + + // Update nonces for sub vaults to process exit queue + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Update state to process the exit queue + IKeeperRewards.HarvestParams memory harvestParams = _getEmptyHarvestParams(); + metaVault.updateState(harvestParams); + + // Process exits in sub vaults + for (uint256 i = 0; i < subVaults.length; i++) { + // Make GNO tokens available for withdrawal from sub vaults + _setGnoWithdrawals(subVaults[i], GNO_AMOUNT / 3); + + harvestParams = _setGnoVaultReward(subVaults[i], 0, 0); + IVaultState(subVaults[i]).updateState(harvestParams); + } + + // Prepare exit requests for claiming from sub vaults to meta vault + IVaultSubVaults.SubVaultExitRequest[] memory exitRequests = + new IVaultSubVaults.SubVaultExitRequest[](subVaults.length); + for (uint256 i = 0; i < subVaults.length; i++) { + exitRequests[i] = IVaultSubVaults.SubVaultExitRequest({ + vault: subVaults[i], + exitQueueIndex: uint256(IVaultEnterExit(subVaults[i]).getExitQueueIndex(0)), + timestamp: exitTimestamp + }); + } + + // Fast-forward time to allow claiming from sub vaults + vm.warp(block.timestamp + _exitingAssetsClaimDelay + 1); + + // Claim exited assets from sub vaults to meta vault + metaVault.claimSubVaultsExitedAssets(exitRequests); + + // Update nonces for sub vaults to process exit queue + newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + // Update state to process the exit queue + metaVault.updateState(harvestParams); + + // Get exit queue index in meta vault + int256 exitQueueIndex = metaVault.getExitQueueIndex(positionTicket); + require(exitQueueIndex >= 0, "Exit queue position not found"); + + // Check sender's GNO balance before claim + uint256 senderBalanceBefore = IERC20(address(contracts.gnoToken)).balanceOf(sender); + + // Have the user claim their exited assets + vm.prank(sender); + _startSnapshotGas("GnoMetaVaultTest_test_claimExitedAssets"); + metaVault.claimExitedAssets(positionTicket, exitTimestamp, uint256(exitQueueIndex)); + _stopSnapshotGas(); + + // Check sender's GNO balance after claim + uint256 senderBalanceAfter = IERC20(address(contracts.gnoToken)).balanceOf(sender); + + // Verify sender received their GNO tokens (approximately the original deposit minus fees) + uint256 amountReceived = senderBalanceAfter - senderBalanceBefore; + assertApproxEqRel(amountReceived, depositAmount, 0.1e18, "User received significantly less than expected"); + + // Verify exit queue data updated + (, uint128 unclaimedAssets,,,) = metaVault.getExitQueueData(); + assertLt(unclaimedAssets, depositAmount, "Unclaimed assets not reduced after claim"); + } + + function test_donateAssets_basic() public { + uint256 donationAmount = 1 ether; + + // Get vault state before donation + uint256 vaultBalanceBefore = contracts.gnoToken.balanceOf(address(metaVault)); + uint256 totalAssetsBefore = metaVault.totalAssets(); + + // Approve GNO token for donation + vm.startPrank(sender); + contracts.gnoToken.approve(address(metaVault), donationAmount); + + // Check event emission + vm.expectEmit(true, true, false, true); + emit IVaultState.AssetsDonated(sender, donationAmount); + + // Make donation + metaVault.donateAssets(donationAmount); + vm.stopPrank(); + + // Verify donation was received + assertEq( + contracts.gnoToken.balanceOf(address(metaVault)), + vaultBalanceBefore + donationAmount, + "Meta vault GNO balance increased" + ); + assertEq(metaVault.totalAssets(), totalAssetsBefore, "Meta vault total assets didn't increase"); + + // Process donation by updating state + uint64 newNonce = contracts.keeper.rewardsNonce() + 1; + _setKeeperRewardsNonce(newNonce); + for (uint256 i = 0; i < subVaults.length; i++) { + _setVaultRewardsNonce(subVaults[i], newNonce); + } + + metaVault.updateState(_getEmptyHarvestParams()); + + assertEq( + contracts.gnoToken.balanceOf(address(metaVault)), + vaultBalanceBefore + donationAmount, + "Meta vault GNO balance increased" + ); + assertEq(metaVault.totalAssets(), totalAssetsBefore + donationAmount, "Meta vault total assets increased"); + } + + function test_donateAssets_zeroValue() public { + // Trying to donate 0 GNO should revert + vm.prank(sender); + vm.expectRevert(Errors.InvalidAssets.selector); + metaVault.donateAssets(0); + } + + function _getEmptyHarvestParams() internal pure returns (IKeeperRewards.HarvestParams memory) { + bytes32[] memory emptyProof; + return + IKeeperRewards.HarvestParams({rewardsRoot: bytes32(0), proof: emptyProof, reward: 0, unlockedMevReward: 0}); + } + + function _setVaultRewardsNonce(address vault, uint64 rewardsNonce) internal { + stdstore.enable_packed_slots().target(address(contracts.keeper)).sig("rewards(address)").with_key(vault).depth( + 1 + ).checked_write(rewardsNonce); + } + + function _setKeeperRewardsNonce(uint64 rewardsNonce) internal { + stdstore.enable_packed_slots().target(address(contracts.keeper)).sig("rewardsNonce()").checked_write( + rewardsNonce + ); + } +} diff --git a/test/gnosis/VaultGnoStaking.t.sol b/test/gnosis/VaultGnoStaking.t.sol index 2a8cfe7a..68e8000e 100644 --- a/test/gnosis/VaultGnoStaking.t.sol +++ b/test/gnosis/VaultGnoStaking.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.22; import {Test} from "forge-std/Test.sol"; import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; import {IVaultValidators} from "../../contracts/interfaces/IVaultValidators.sol"; +import {IVaultState} from "../../contracts/interfaces/IVaultValidators.sol"; import {IGnoVault} from "../../contracts/interfaces/IGnoVault.sol"; import {GnoHelpers} from "../helpers/GnoHelpers.sol"; import {Errors} from "../../contracts/libraries/Errors.sol"; @@ -486,6 +487,54 @@ contract VaultGnoStakingTest is Test, GnoHelpers { assertEq(contracts.gnoToken.balanceOf(address(newVault)), securityDeposit, "Incorrect security deposit"); } + function test_donateAssets_basic() public { + uint256 donationAmount = 1 ether; + + // Get vault state before donation + uint256 vaultAssetsBefore = vault.totalAssets(); + uint256 vaultGnoBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); + + // Approve GNO token for donation + vm.startPrank(sender); + contracts.gnoToken.approve(address(vault), donationAmount); + + // Check event emission + vm.expectEmit(true, true, false, true); + emit IVaultState.AssetsDonated(sender, donationAmount); + + // Make donation + vault.donateAssets(donationAmount); + vm.stopPrank(); + + // Verify donation was received + assertEq( + contracts.gnoToken.balanceOf(address(vault)), + vaultGnoBalanceBefore + donationAmount, + "Vault GNO balance didn't increase" + ); + + // Donate assets aren't immediately reflected in totalAssets until state update + assertEq(vault.totalAssets(), vaultAssetsBefore, "Total assets shouldn't change before state update"); + + // Update state to process donation + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); + vault.updateState(harvestParams); + + // Now the vault's total assets should increase + assertEq( + vault.totalAssets(), + vaultAssetsBefore + donationAmount, + "Total assets should include donation after state update" + ); + } + + function test_gnoVault_donateAssets_zeroValue() public { + // Trying to donate 0 GNO should revert + vm.prank(sender); + vm.expectRevert(Errors.InvalidAssets.selector); + vault.donateAssets(0); + } + // Helper functions function _depositGno(uint256 amount, address from, address to) internal { _depositToVault(address(vault), amount, from, to); diff --git a/test/helpers/EthHelpers.sol b/test/helpers/EthHelpers.sol index 0cbf5ca3..0da4a2fc 100644 --- a/test/helpers/EthHelpers.sol +++ b/test/helpers/EthHelpers.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.22; import {Test} from "forge-std/Test.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; import {IOsTokenConfig} from "../../contracts/interfaces/IOsTokenConfig.sol"; import {IOsTokenVaultController} from "../../contracts/interfaces/IOsTokenVaultController.sol"; @@ -21,12 +22,15 @@ import {EthPrivErc20Vault} from "../../contracts/vaults/ethereum/EthPrivErc20Vau import {EthPrivVault} from "../../contracts/vaults/ethereum/EthPrivVault.sol"; import {EthVault, IEthVault} from "../../contracts/vaults/ethereum/EthVault.sol"; import {EthVaultFactory} from "../../contracts/vaults/ethereum/EthVaultFactory.sol"; -import {EthFoxVault} from "../../contracts/vaults/ethereum/custom/EthFoxVault.sol"; +import {IEthFoxVault, EthFoxVault} from "../../contracts/vaults/ethereum/custom/EthFoxVault.sol"; +import {IEthMetaVault, EthMetaVault} from "../../contracts/vaults/ethereum/custom/EthMetaVault.sol"; +import {EthMetaVaultFactory} from "../../contracts/vaults/ethereum/custom/EthMetaVaultFactory.sol"; import {Keeper} from "../../contracts/keeper/Keeper.sol"; import {ValidatorsConsolidationsMock} from "../../contracts/mocks/ValidatorsConsolidationsMock.sol"; import {ValidatorsHelpers} from "./ValidatorsHelpers.sol"; import {ValidatorsWithdrawalsMock} from "../../contracts/mocks/ValidatorsWithdrawalsMock.sol"; import {VaultsRegistry, IVaultsRegistry} from "../../contracts/vaults/VaultsRegistry.sol"; +import {CuratorsRegistry} from "../../contracts/curators/CuratorsRegistry.sol"; abstract contract EthHelpers is Test, ValidatorsHelpers { uint256 internal constant forkBlockNumber = 22100000; @@ -53,7 +57,8 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { EthErc20Vault, EthBlocklistErc20Vault, EthPrivErc20Vault, - EthFoxVault + EthFoxVault, + EthMetaVault } struct ForkContracts { @@ -74,6 +79,7 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { address internal _consolidationsChecker; address internal _validatorsWithdrawals; address internal _validatorsConsolidations; + address internal _curatorsRegistry; function _activateEthereumFork() internal returns (ForkContracts memory) { vm.createSelectFork(vm.envString("MAINNET_RPC_URL"), forkBlockNumber); @@ -81,6 +87,7 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); + _curatorsRegistry = address(new CuratorsRegistry()); return ForkContracts({ keeper: Keeper(_keeper), @@ -132,6 +139,22 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { return factory; } + function _getOrCreateMetaFactory(VaultType _vaultType) internal returns (EthMetaVaultFactory) { + if (_vaultFactories[_vaultType] != address(0)) { + return EthMetaVaultFactory(_vaultFactories[_vaultType]); + } + + address impl = _getOrCreateVaultImpl(_vaultType); + EthMetaVaultFactory factory = new EthMetaVaultFactory(address(this), impl, IVaultsRegistry(_vaultsRegistry)); + + _vaultFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; + } + function _getPrevVersionVaultFactory(VaultType _vaultType) internal returns (EthVaultFactory) { if (_vaultPrevFactories[_vaultType] != address(0)) { return EthVaultFactory(_vaultPrevFactories[_vaultType]); @@ -278,11 +301,27 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { internal returns (address) { - EthVaultFactory factory = _getOrCreateFactory(vaultType); + if (vaultType == VaultType.EthFoxVault) { + address vaultImpl = _getOrCreateVaultImpl(vaultType); + address vault = address(new ERC1967Proxy(vaultImpl, "")); + vm.deal(address(this), 1 ether); + IEthVault(vault).initialize{value: _securityDeposit}(initParams); + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addVault(vault); + return vault; + } - vm.deal(admin, admin.balance + _securityDeposit); - vm.prank(admin); - address vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + address vaultAddress; + if (vaultType == VaultType.EthMetaVault) { + EthMetaVaultFactory factory = _getOrCreateMetaFactory(vaultType); + vm.deal(address(this), address(this).balance + _securityDeposit); + vaultAddress = factory.createVault{value: _securityDeposit}(admin, initParams); + } else { + EthVaultFactory factory = _getOrCreateFactory(vaultType); + vm.deal(admin, admin.balance + _securityDeposit); + vm.prank(admin); + vaultAddress = factory.createVault{value: _securityDeposit}(initParams, isOwnMevEscrow); + } return vaultAddress; } @@ -386,19 +425,30 @@ abstract contract EthHelpers is Test, ValidatorsHelpers { } else if (_vaultType == VaultType.EthPrivErc20Vault) { impl = address(new EthPrivErc20Vault(ethErc20Args)); } else if (_vaultType == VaultType.EthFoxVault) { - impl = address( - new EthFoxVault( - _keeper, - _vaultsRegistry, - _validatorsRegistry, - _validatorsWithdrawals, - _validatorsConsolidations, - _consolidationsChecker, - _sharedMevEscrow, - _depositDataRegistry, - _exitingAssetsClaimDelay - ) + IEthFoxVault.EthFoxVaultConstructorArgs memory ethFoxVaultArgs = IEthFoxVault.EthFoxVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _validatorsRegistry, + _validatorsWithdrawals, + _validatorsConsolidations, + _consolidationsChecker, + _sharedMevEscrow, + _depositDataRegistry, + uint64(_exitingAssetsClaimDelay) + ); + impl = address(new EthFoxVault(ethFoxVaultArgs)); + } else if (_vaultType == VaultType.EthMetaVault) { + IEthMetaVault.EthMetaVaultConstructorArgs memory ethMetaVaultArgs = IEthMetaVault + .EthMetaVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _curatorsRegistry, + uint64(_exitingAssetsClaimDelay) ); + impl = address(new EthMetaVault(ethMetaVaultArgs)); } _vaultImplementations[_vaultType] = impl; diff --git a/test/helpers/GnoHelpers.sol b/test/helpers/GnoHelpers.sol index e9890943..ee54324e 100644 --- a/test/helpers/GnoHelpers.sol +++ b/test/helpers/GnoHelpers.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.22; import {Test} from "forge-std/Test.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {IKeeperValidators} from "../../contracts/interfaces/IKeeperValidators.sol"; import {IOsTokenConfig} from "../../contracts/interfaces/IOsTokenConfig.sol"; import {IOsTokenVaultController} from "../../contracts/interfaces/IOsTokenVaultController.sol"; @@ -23,12 +24,15 @@ import {GnoGenesisVault} from "../../contracts/vaults/gnosis/GnoGenesisVault.sol import {GnoPrivErc20Vault} from "../../contracts/vaults/gnosis/GnoPrivErc20Vault.sol"; import {GnoPrivVault} from "../../contracts/vaults/gnosis/GnoPrivVault.sol"; import {GnoVault, IGnoVault} from "../../contracts/vaults/gnosis/GnoVault.sol"; +import {IGnoMetaVault, GnoMetaVault} from "../../contracts/vaults/gnosis/custom/GnoMetaVault.sol"; +import {GnoMetaVaultFactory} from "../../contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol"; import {GnoVaultFactory} from "../../contracts/vaults/gnosis/GnoVaultFactory.sol"; import {Keeper} from "../../contracts/keeper/Keeper.sol"; import {ValidatorsConsolidationsMock} from "../../contracts/mocks/ValidatorsConsolidationsMock.sol"; -import {ValidatorsHelpers} from "./ValidatorsHelpers.sol"; import {ValidatorsWithdrawalsMock} from "../../contracts/mocks/ValidatorsWithdrawalsMock.sol"; import {VaultsRegistry, IVaultsRegistry} from "../../contracts/vaults/VaultsRegistry.sol"; +import {CuratorsRegistry} from "../../contracts/curators/CuratorsRegistry.sol"; +import {ValidatorsHelpers} from "./ValidatorsHelpers.sol"; interface IGnoToken { function mint(address _to, uint256 _amount) external returns (bool); @@ -61,7 +65,8 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { GnoGenesisVault, GnoErc20Vault, GnoBlocklistErc20Vault, - GnoPrivErc20Vault + GnoPrivErc20Vault, + GnoMetaVault } struct ForkContracts { @@ -86,6 +91,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { address private _consolidationsChecker; address private _validatorsWithdrawals; address private _validatorsConsolidations; + address internal _curatorsRegistry; function _activateGnosisFork() internal returns (ForkContracts memory) { vm.createSelectFork(vm.envString("GNOSIS_RPC_URL"), forkBlockNumber); @@ -95,6 +101,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); + _curatorsRegistry = address(new CuratorsRegistry()); vm.prank(IMerkleDistributor(_merkleDistributor).owner()); IMerkleDistributor(_merkleDistributor).setDistributor(_gnoDaiDistributor, true); @@ -202,6 +209,23 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { return factory; } + function _getOrCreateMetaFactory(VaultType _vaultType) internal returns (GnoMetaVaultFactory) { + if (_vaultFactories[_vaultType] != address(0)) { + return GnoMetaVaultFactory(_vaultFactories[_vaultType]); + } + + address impl = _getOrCreateVaultImpl(_vaultType); + GnoMetaVaultFactory factory = + new GnoMetaVaultFactory(address(this), impl, IVaultsRegistry(_vaultsRegistry), _gnoToken); + + _vaultFactories[_vaultType] = address(factory); + + vm.prank(VaultsRegistry(_vaultsRegistry).owner()); + VaultsRegistry(_vaultsRegistry).addFactory(address(factory)); + + return factory; + } + function _getPrevVersionVaultFactory(VaultType _vaultType) internal pure returns (GnoVaultFactory) { if (_vaultType == VaultType.GnoVault) { return GnoVaultFactory(0xC2ecc7620416bd65bfab7010B0db955a0e49579a); @@ -312,12 +336,18 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { internal returns (address) { - GnoVaultFactory factory = _getOrCreateFactory(vaultType); - - vm.startPrank(admin); - IERC20(_gnoToken).approve(address(factory), _securityDeposit); - address vaultAddress = factory.createVault(initParams, isOwnMevEscrow); - vm.stopPrank(); + address vaultAddress; + if (vaultType == VaultType.GnoMetaVault) { + GnoMetaVaultFactory factory = _getOrCreateMetaFactory(vaultType); + IERC20(_gnoToken).approve(address(factory), _securityDeposit); + vaultAddress = factory.createVault(admin, initParams); + } else { + GnoVaultFactory factory = _getOrCreateFactory(vaultType); + vm.startPrank(admin); + IERC20(_gnoToken).approve(address(factory), _securityDeposit); + vaultAddress = factory.createVault(initParams, isOwnMevEscrow); + vm.stopPrank(); + } return vaultAddress; } @@ -405,6 +435,19 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { impl = address(new GnoBlocklistErc20Vault(gnoErc20Args)); } else if (_vaultType == VaultType.GnoPrivErc20Vault) { impl = address(new GnoPrivErc20Vault(gnoErc20Args)); + } else if (_vaultType == VaultType.GnoMetaVault) { + IGnoMetaVault.GnoMetaVaultConstructorArgs memory gnoMetaVaultArgs = IGnoMetaVault + .GnoMetaVaultConstructorArgs( + _keeper, + _vaultsRegistry, + _osTokenVaultController, + _osTokenConfig, + _osTokenVaultEscrow, + _curatorsRegistry, + _gnoToken, + uint64(_exitingAssetsClaimDelay) + ); + impl = address(new GnoMetaVault(gnoMetaVaultArgs)); } _vaultImplementations[_vaultType] = impl; From e9abc8ac516a77e472b314194930710feaf40030 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Mon, 19 May 2025 21:15:45 +0300 Subject: [PATCH 14/15] Tokens converter (#114) * Replace xdai tokens distributor with converter for Gnosis * Update snapshots * Fix fork tests * Fix snapshots --- contracts/interfaces/IGnoDaiDistributor.sol | 22 ---- contracts/interfaces/IGnoErc20Vault.sol | 4 +- contracts/interfaces/IGnoTokensConverter.sol | 21 ++++ contracts/interfaces/IGnoVault.sol | 4 +- .../interfaces/ITokensConverterFactory.sol | 24 ++++ contracts/misc/GnoDaiDistributor.sol | 55 --------- .../vaults/gnosis/GnoBlocklistErc20Vault.sol | 4 +- contracts/vaults/gnosis/GnoErc20Vault.sol | 14 ++- contracts/vaults/gnosis/GnoPrivErc20Vault.sol | 4 +- contracts/vaults/gnosis/GnoVault.sol | 13 +- contracts/vaults/modules/VaultGnoStaking.sol | 50 ++++---- contracts/vaults/modules/VaultMev.sol | 8 +- contracts/vaults/modules/VaultState.sol | 15 ++- contracts/vaults/modules/VaultValidators.sol | 20 ++-- script/Network.sol | 8 +- script/UpgradeEthNetwork.s.sol | 3 +- script/UpgradeGnoNetwork.s.sol | 19 +-- snapshots/DepositDataRegistryTest.json | 2 +- snapshots/EthBlocklistErc20VaultTest.json | 4 +- snapshots/EthBlocklistVaultTest.json | 4 +- snapshots/EthErc20VaultTest.json | 8 +- snapshots/EthGenesisVaultTest.json | 2 +- snapshots/EthPrivErc20VaultTest.json | 4 +- snapshots/EthPrivVaultTest.json | 6 +- snapshots/EthRewardSplitterTest.json | 8 +- snapshots/EthVaultTest.json | 6 +- snapshots/GnoBlocklistErc20VaultTest.json | 6 +- snapshots/GnoBlocklistVaultTest.json | 6 +- snapshots/GnoErc20VaultTest.json | 8 +- snapshots/GnoGenesisVaultTest.json | 4 +- snapshots/GnoMetaVaultTest.json | 2 +- snapshots/GnoOsTokenVaultEscrowTest.json | 2 +- snapshots/GnoPrivErc20VaultTest.json | 6 +- snapshots/GnoPrivVaultTest.json | 6 +- snapshots/GnoRewardSplitterTest.json | 8 +- snapshots/GnoVaultExitQueueTest.json | 6 +- snapshots/GnoVaultTest.json | 4 +- snapshots/KeeperRewardsTest.json | 12 +- snapshots/VaultAdminTest.json | 2 +- snapshots/VaultEnterExitTest.json | 2 +- snapshots/VaultEthStakingTest.json | 8 +- snapshots/VaultFeeTest.json | 4 +- snapshots/VaultGnoStakingTest.json | 20 ++-- snapshots/VaultOsTokenTest.json | 4 +- snapshots/VaultTokenTest.json | 6 +- test/gnosis/VaultGnoStaking.t.sol | 113 ++++++++++++------ test/helpers/GnoHelpers.sol | 42 +++---- 47 files changed, 301 insertions(+), 302 deletions(-) delete mode 100644 contracts/interfaces/IGnoDaiDistributor.sol create mode 100644 contracts/interfaces/IGnoTokensConverter.sol create mode 100644 contracts/interfaces/ITokensConverterFactory.sol delete mode 100644 contracts/misc/GnoDaiDistributor.sol diff --git a/contracts/interfaces/IGnoDaiDistributor.sol b/contracts/interfaces/IGnoDaiDistributor.sol deleted file mode 100644 index ac950d72..00000000 --- a/contracts/interfaces/IGnoDaiDistributor.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -/** - * @title IGnoDaiDistributor - * @author StakeWise - * @notice Defines the interface for the GnoDaiDistributor - */ -interface IGnoDaiDistributor { - /** - * @notice Event emitted when sDAI is distributed to the users - * @param vault The address of the vault - * @param amount The amount of sDAI distributed - */ - event SDaiDistributed(address indexed vault, uint256 amount); - - /** - * @notice Distribute sDAI to the users. Can be called only by the vaults. Must transfer xDAI together with the call. - */ - function distributeSDai() external payable; -} diff --git a/contracts/interfaces/IGnoErc20Vault.sol b/contracts/interfaces/IGnoErc20Vault.sol index 4d3527bf..46f0bda3 100644 --- a/contracts/interfaces/IGnoErc20Vault.sol +++ b/contracts/interfaces/IGnoErc20Vault.sol @@ -46,7 +46,7 @@ interface IGnoErc20Vault is * @param sharedMevEscrow The address of the shared MEV escrow * @param depositDataRegistry The address of the DepositDataRegistry contract * @param gnoToken The address of the GNO token - * @param gnoDaiDistributor The address of the GnoDaiDistributor contract + * @param tokensConverterFactory The address of the TokensConverterFactory contract * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking */ struct GnoErc20VaultConstructorArgs { @@ -62,7 +62,7 @@ interface IGnoErc20Vault is address sharedMevEscrow; address depositDataRegistry; address gnoToken; - address gnoDaiDistributor; + address tokensConverterFactory; uint256 exitingAssetsClaimDelay; } diff --git a/contracts/interfaces/IGnoTokensConverter.sol b/contracts/interfaces/IGnoTokensConverter.sol new file mode 100644 index 00000000..ba86d627 --- /dev/null +++ b/contracts/interfaces/IGnoTokensConverter.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IGnoTokensConverter + * @author StakeWise + * @notice Defines the interface for the GnoTokensConverter contract + */ +interface IGnoTokensConverter { + /** + * @notice Function for creating swap orders with xDAI + * @dev This function is used to convert xDAI to sDAI and create a swap order + */ + function createXDaiSwapOrder() external payable; + + /** + * @notice Transfer accumulated assets to the Vault + */ + function transferAssets() external; +} diff --git a/contracts/interfaces/IGnoVault.sol b/contracts/interfaces/IGnoVault.sol index 3333aae7..60899a8e 100644 --- a/contracts/interfaces/IGnoVault.sol +++ b/contracts/interfaces/IGnoVault.sol @@ -44,7 +44,7 @@ interface IGnoVault is * @param sharedMevEscrow The address of the shared MEV escrow * @param depositDataRegistry The address of the DepositDataRegistry contract * @param gnoToken The address of the GNO token - * @param gnoDaiDistributor The address of the GnoDaiDistributor contract + * @param tokensConverterFactory The address of the TokensConverterFactory contract * @param exitingAssetsClaimDelay The delay after which the assets can be claimed after exiting from staking */ struct GnoVaultConstructorArgs { @@ -60,7 +60,7 @@ interface IGnoVault is address sharedMevEscrow; address depositDataRegistry; address gnoToken; - address gnoDaiDistributor; + address tokensConverterFactory; uint256 exitingAssetsClaimDelay; } diff --git a/contracts/interfaces/ITokensConverterFactory.sol b/contracts/interfaces/ITokensConverterFactory.sol new file mode 100644 index 00000000..69f344fd --- /dev/null +++ b/contracts/interfaces/ITokensConverterFactory.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title ITokensConverterFactory + * @author StakeWise + * @notice Defines the interface for the TokensConverterFactory contract + */ +interface ITokensConverterFactory { + /** + * @notice Create a new tokens converter for a given vault + * @param vault The address of the vault + * @return converter The address of the tokens converter + */ + function createConverter(address vault) external returns (address converter); + + /** + * @notice Get the address of the tokens converter for a given vault + * @param vault The address of the vault + * @return converter The address of the tokens converter + */ + function getTokensConverter(address vault) external view returns (address converter); +} diff --git a/contracts/misc/GnoDaiDistributor.sol b/contracts/misc/GnoDaiDistributor.sol deleted file mode 100644 index 196cdb87..00000000 --- a/contracts/misc/GnoDaiDistributor.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.22; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; -import {IGnoDaiDistributor} from "../interfaces/IGnoDaiDistributor.sol"; -import {IMerkleDistributor} from "../interfaces/IMerkleDistributor.sol"; -import {ISavingsXDaiAdapter} from "../interfaces/ISavingsXDaiAdapter.sol"; -import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; -import {Errors} from "../libraries/Errors.sol"; - -/** - * @title GnoDaiDistributor - * @author StakeWise - * @notice Converts xDAI to sDAI and distributes it to the users using Merkle Distributor on Gnosis chain - */ -contract GnoDaiDistributor is ReentrancyGuard, IGnoDaiDistributor { - address private immutable _sDaiToken; - IVaultsRegistry private immutable _vaultsRegistry; - ISavingsXDaiAdapter private immutable _savingsXDaiAdapter; - IMerkleDistributor private immutable _merkleDistributor; - - /** - * @dev Constructor - * @param sDaiToken The address of the sDaiToken contract - * @param vaultsRegistry The address of the VaultsRegistry contract - * @param savingsXDaiAdapter The address of the SavingsXDaiAdapter contract - */ - constructor(address sDaiToken, address vaultsRegistry, address savingsXDaiAdapter, address merkleDistributor) - ReentrancyGuard() - { - _sDaiToken = sDaiToken; - _vaultsRegistry = IVaultsRegistry(vaultsRegistry); - _savingsXDaiAdapter = ISavingsXDaiAdapter(savingsXDaiAdapter); - _merkleDistributor = IMerkleDistributor(merkleDistributor); - IERC20(sDaiToken).approve(merkleDistributor, type(uint256).max); - } - - /// @inheritdoc IGnoDaiDistributor - function distributeSDai() external payable nonReentrant { - // can be called only by vaults - if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); - - // convert xDAI to sDAI - uint256 sDaiAmount = _savingsXDaiAdapter.depositXDAI{value: msg.value}(address(this)); - if (sDaiAmount == 0) revert Errors.InvalidAssets(); - - // distribute tokens to vault users - _merkleDistributor.distributeOneTime(_sDaiToken, sDaiAmount, "", abi.encode(msg.sender)); - - // emit event - emit SDaiDistributed(msg.sender, sDaiAmount); - } -} diff --git a/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol b/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol index 6540f5f0..92a87b1f 100644 --- a/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol @@ -28,9 +28,7 @@ contract GnoBlocklistErc20Vault is Initializable, GnoErc20Vault, VaultBlocklist, * @param args The arguments for initializing the GnoErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { - _disableInitializers(); - } + constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) {} /// @inheritdoc IGnoErc20Vault function initialize(bytes calldata params) diff --git a/contracts/vaults/gnosis/GnoErc20Vault.sol b/contracts/vaults/gnosis/GnoErc20Vault.sol index 36d0efa5..be6e539d 100644 --- a/contracts/vaults/gnosis/GnoErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoErc20Vault.sol @@ -6,6 +6,7 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {IGnoErc20Vault} from "../../interfaces/IGnoErc20Vault.sol"; import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; import {Errors} from "../../libraries/Errors.sol"; import {Multicall} from "../../base/Multicall.sol"; import {ERC20Upgradeable} from "../../base/ERC20Upgradeable.sol"; @@ -63,7 +64,7 @@ contract GnoErc20Vault is VaultEnterExit(args.exitingAssetsClaimDelay) VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) VaultMev(args.sharedMevEscrow) - VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) + VaultGnoStaking(args.gnoToken, args.tokensConverterFactory) { _disableInitializers(); } @@ -125,8 +126,14 @@ contract GnoErc20Vault is } /// @inheritdoc VaultState - function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override(VaultState, VaultGnoStaking) { - super._processTotalAssetsDelta(assetsDelta); + function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) + internal + override(VaultState, VaultMev) + returns (int256 totalAssetsDelta, bool harvested) + { + (totalAssetsDelta, harvested) = super._harvestAssets(harvestParams); + // withdraw assets from the tokens converter + _tokensConverter.transferAssets(); } /// @inheritdoc VaultState @@ -174,7 +181,6 @@ contract GnoErc20Vault is */ function __GnoErc20Vault_init(address admin, address ownMevEscrow, GnoErc20VaultInitParams memory params) internal - onlyInitializing { __VaultAdmin_init(admin, params.metadataIpfsHash); // fee recipient is initially set to admin address diff --git a/contracts/vaults/gnosis/GnoPrivErc20Vault.sol b/contracts/vaults/gnosis/GnoPrivErc20Vault.sol index 85f591d4..d1ea3b28 100644 --- a/contracts/vaults/gnosis/GnoPrivErc20Vault.sol +++ b/contracts/vaults/gnosis/GnoPrivErc20Vault.sol @@ -28,9 +28,7 @@ contract GnoPrivErc20Vault is Initializable, GnoErc20Vault, VaultWhitelist, IGno * @param args The arguments for initializing the GnoErc20Vault contract */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) { - _disableInitializers(); - } + constructor(GnoErc20VaultConstructorArgs memory args) GnoErc20Vault(args) {} /// @inheritdoc IGnoErc20Vault function initialize(bytes calldata params) diff --git a/contracts/vaults/gnosis/GnoVault.sol b/contracts/vaults/gnosis/GnoVault.sol index e17bf831..6a64ff92 100644 --- a/contracts/vaults/gnosis/GnoVault.sol +++ b/contracts/vaults/gnosis/GnoVault.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.22; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {IGnoVault} from "../../interfaces/IGnoVault.sol"; import {IGnoVaultFactory} from "../../interfaces/IGnoVaultFactory.sol"; +import {IKeeperRewards} from "../../interfaces/IKeeperRewards.sol"; import {Errors} from "../../libraries/Errors.sol"; import {Multicall} from "../../base/Multicall.sol"; import {VaultValidators} from "../modules/VaultValidators.sol"; @@ -59,7 +60,7 @@ contract GnoVault is VaultEnterExit(args.exitingAssetsClaimDelay) VaultOsToken(args.osTokenVaultController, args.osTokenConfig, args.osTokenVaultEscrow) VaultMev(args.sharedMevEscrow) - VaultGnoStaking(args.gnoToken, args.gnoDaiDistributor) + VaultGnoStaking(args.gnoToken, args.tokensConverterFactory) { _disableInitializers(); } @@ -101,8 +102,14 @@ contract GnoVault is } /// @inheritdoc VaultState - function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override(VaultState, VaultGnoStaking) { - super._processTotalAssetsDelta(assetsDelta); + function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) + internal + override(VaultState, VaultMev) + returns (int256 totalAssetsDelta, bool harvested) + { + (totalAssetsDelta, harvested) = super._harvestAssets(harvestParams); + // withdraw assets from the tokens converter + _tokensConverter.transferAssets(); } /// @inheritdoc VaultValidators diff --git a/contracts/vaults/modules/VaultGnoStaking.sol b/contracts/vaults/modules/VaultGnoStaking.sol index d6783ffb..e37c42cf 100644 --- a/contracts/vaults/modules/VaultGnoStaking.sol +++ b/contracts/vaults/modules/VaultGnoStaking.sol @@ -7,7 +7,8 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {IGnoValidatorsRegistry} from "../../interfaces/IGnoValidatorsRegistry.sol"; import {IVaultGnoStaking} from "../../interfaces/IVaultGnoStaking.sol"; -import {IGnoDaiDistributor} from "../../interfaces/IGnoDaiDistributor.sol"; +import {ITokensConverterFactory} from "../../interfaces/ITokensConverterFactory.sol"; +import {IGnoTokensConverter} from "../../interfaces/IGnoTokensConverter.sol"; import {ValidatorUtils} from "../../libraries/ValidatorUtils.sol"; import {Errors} from "../../libraries/Errors.sol"; import {VaultAdmin} from "./VaultAdmin.sol"; @@ -31,19 +32,21 @@ abstract contract VaultGnoStaking is uint256 private constant _securityDeposit = 1e9; IERC20 internal immutable _gnoToken; - IGnoDaiDistributor private immutable _gnoDaiDistributor; + ITokensConverterFactory private immutable _tokensConverterFactory; + + IGnoTokensConverter internal _tokensConverter; /** * @dev Constructor * @dev Since the immutable variable value is stored in the bytecode, * its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. * @param gnoToken The address of the GNO token - * @param gnoDaiDistributor The address of the xDAI distributor contract + * @param tokensConverterFactory The address of the tokens converter factory */ /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address gnoToken, address gnoDaiDistributor) { + constructor(address gnoToken, address tokensConverterFactory) { _gnoToken = IERC20(gnoToken); - _gnoDaiDistributor = IGnoDaiDistributor(gnoDaiDistributor); + _tokensConverterFactory = ITokensConverterFactory(tokensConverterFactory); } /// @inheritdoc IVaultGnoStaking @@ -51,7 +54,6 @@ abstract contract VaultGnoStaking is public virtual override - nonReentrant returns (uint256 shares) { // withdraw GNO tokens from the user @@ -60,7 +62,7 @@ abstract contract VaultGnoStaking is } /// @inheritdoc IVaultGnoStaking - function donateAssets(uint256 amount) external override nonReentrant { + function donateAssets(uint256 amount) external override { if (amount == 0) { revert Errors.InvalidAssets(); } @@ -70,20 +72,12 @@ abstract contract VaultGnoStaking is emit AssetsDonated(msg.sender, amount); } - /// @inheritdoc VaultState - function _processTotalAssetsDelta(int256 assetsDelta) internal virtual override { - super._processTotalAssetsDelta(assetsDelta); - - uint256 balance = address(this).balance; - if (balance < 0.1 ether) return; - - _gnoDaiDistributor.distributeSDai{value: balance}(); - } - /** - * @dev Function for receiving xDAI + * @dev Function for receiving xDAI and forwarding it to the tokens converter */ - receive() external payable {} + receive() external payable { + _tokensConverter.createXDaiSwapOrder{value: address(this).balance}(); + } /// @inheritdoc VaultValidators function _registerValidators(ValidatorUtils.ValidatorDeposit[] memory deposits) internal virtual override { @@ -143,26 +137,34 @@ abstract contract VaultGnoStaking is * @dev Upgrades the VaultGnoStaking contract */ function __VaultGnoStaking_upgrade() internal onlyInitializing { - // approve transferring GNO for validators registration - _gnoToken.approve(_validatorsRegistry, type(uint256).max); + __VaultGnoStaking_init_common(); } /** * @dev Initializes the VaultGnoStaking contract */ function __VaultGnoStaking_init() internal onlyInitializing { - // approve transferring GNO for validators registration - _gnoToken.approve(_validatorsRegistry, type(uint256).max); + __VaultGnoStaking_init_common(); _deposit(address(this), _securityDeposit, address(0)); // see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 SafeERC20.safeTransferFrom(_gnoToken, msg.sender, address(this), _securityDeposit); } + /** + * @dev Common initialization for gas optimization + */ + function __VaultGnoStaking_init_common() private { + // approve transferring GNO for validators registration + _gnoToken.approve(_validatorsRegistry, type(uint256).max); + // create tokens converter + _tokensConverter = IGnoTokensConverter(_tokensConverterFactory.createConverter(address(this))); + } + /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[50] private __gap; + uint256[49] private __gap; } diff --git a/contracts/vaults/modules/VaultMev.sol b/contracts/vaults/modules/VaultMev.sol index 156f0e4c..8fe73144 100644 --- a/contracts/vaults/modules/VaultMev.sol +++ b/contracts/vaults/modules/VaultMev.sol @@ -40,6 +40,7 @@ abstract contract VaultMev is Initializable, VaultState, IVaultMev { /// @inheritdoc VaultState function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) internal + virtual override returns (int256 totalAssetsDelta, bool harvested) { @@ -60,13 +61,6 @@ abstract contract VaultMev is Initializable, VaultState, IVaultMev { // execution rewards are always equal to what was accumulated in own MEV escrow totalAssetsDelta += int256(IOwnMevEscrow(_mevEscrow).harvest()); } - - // SLOAD to memory - uint256 donatedAssets = _donatedAssets; - if (donatedAssets > 0) { - totalAssetsDelta += int256(donatedAssets); - _donatedAssets = 0; - } } /** diff --git a/contracts/vaults/modules/VaultState.sol b/contracts/vaults/modules/VaultState.sol index 09337ab5..f40ab40f 100644 --- a/contracts/vaults/modules/VaultState.sol +++ b/contracts/vaults/modules/VaultState.sol @@ -115,6 +115,15 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault // process total assets delta since last update (int256 totalAssetsDelta, bool harvested) = _harvestAssets(harvestParams); + if (harvested) { + // SLOAD to memory + uint256 donatedAssets = _donatedAssets; + if (donatedAssets > 0) { + _donatedAssets = 0; + totalAssetsDelta += int256(donatedAssets); + } + } + // process total assets delta if it has changed _processTotalAssetsDelta(totalAssetsDelta); @@ -295,13 +304,13 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault /** * @dev Internal function for harvesting Vaults' new assets - * @return The total assets delta after harvest - * @return `true` when the rewards were harvested, `false` otherwise + * @return totalAssetsDelta The total assets delta after harvest + * @return harvested `true` when the rewards were harvested, `false` otherwise */ function _harvestAssets(IKeeperRewards.HarvestParams calldata harvestParams) internal virtual - returns (int256, bool); + returns (int256 totalAssetsDelta, bool harvested); /** * @dev Internal function for retrieving the total assets stored in the Vault. diff --git a/contracts/vaults/modules/VaultValidators.sol b/contracts/vaults/modules/VaultValidators.sol index 0336f9fe..fb14fd03 100644 --- a/contracts/vaults/modules/VaultValidators.sol +++ b/contracts/vaults/modules/VaultValidators.sol @@ -255,12 +255,7 @@ abstract contract VaultValidators is * @dev Upgrades the VaultValidators contract */ function __VaultValidators_upgrade() internal onlyInitializing { - __ReentrancyGuard_init(); - // initialize domain separator - bytes32 newInitialDomainSeparator = _computeVaultValidatorsDomain(); - if (newInitialDomainSeparator != _initialDomainSeparator) { - _initialDomainSeparator = newInitialDomainSeparator; - } + __VaultValidators_init_common(); // migrate deposit data variables to DepositDataRegistry contract if (__deprecated__validatorsRoot != bytes32(0)) { @@ -277,8 +272,19 @@ abstract contract VaultValidators is * @dev Initializes the VaultValidators contract */ function __VaultValidators_init() internal onlyInitializing { + __VaultValidators_init_common(); + } + + /** + * @dev Common initialization for gas optimization + */ + function __VaultValidators_init_common() private { __ReentrancyGuard_init(); - _initialDomainSeparator = _computeVaultValidatorsDomain(); + // initialize domain separator + bytes32 newInitialDomainSeparator = _computeVaultValidatorsDomain(); + if (newInitialDomainSeparator != _initialDomainSeparator) { + _initialDomainSeparator = newInitialDomainSeparator; + } } /** diff --git a/script/Network.sol b/script/Network.sol index e74df987..d05d3c3f 100644 --- a/script/Network.sol +++ b/script/Network.sol @@ -52,7 +52,6 @@ abstract contract Network is Script { address merkleDistributor; address gnoToken; address sDaiToken; - address savingsXDaiAdapter; } struct Factory { @@ -129,12 +128,10 @@ abstract contract Network is Script { if (isGnosis) { deployment.gnoToken = deploymentData.readAddress(".GnoToken"); deployment.sDaiToken = deploymentData.readAddress(".SDaiToken"); - deployment.savingsXDaiAdapter = deploymentData.readAddress(".SavingsXDaiAdapter"); deployment.foxVault = address(0); } else { deployment.gnoToken = address(0); deployment.sDaiToken = address(0); - deployment.savingsXDaiAdapter = address(0); deployment.foxVault = deploymentData.readAddress(".FoxVault"); } _deployment = deployment; @@ -192,8 +189,7 @@ abstract contract Network is Script { address consolidationsChecker, address rewardSplitterFactory, address curatorsRegistry, - address balancedCurator, - address gnoDaiDistributor + address balancedCurator ) internal { Deployment memory deployment = getDeploymentData(); @@ -225,8 +221,6 @@ abstract contract Network is Script { if (isGnosis) { vm.serializeAddress(json, "GnoToken", deployment.gnoToken); vm.serializeAddress(json, "SDaiToken", deployment.sDaiToken); - vm.serializeAddress(json, "SavingsXDaiAdapter", deployment.savingsXDaiAdapter); - vm.serializeAddress(json, "GnoDaiDistributor", gnoDaiDistributor); } else { vm.serializeAddress(json, "FoxVault", deployment.foxVault); } diff --git a/script/UpgradeEthNetwork.s.sol b/script/UpgradeEthNetwork.s.sol index c8ac17b9..2b17ff71 100644 --- a/script/UpgradeEthNetwork.s.sol +++ b/script/UpgradeEthNetwork.s.sol @@ -79,8 +79,7 @@ contract UpgradeEthNetwork is Network { consolidationsChecker, rewardSplitterFactory, curatorsRegistry, - balancedCurator, - address(0) + balancedCurator ); } diff --git a/script/UpgradeGnoNetwork.s.sol b/script/UpgradeGnoNetwork.s.sol index 32dbcffd..fc11ef0f 100644 --- a/script/UpgradeGnoNetwork.s.sol +++ b/script/UpgradeGnoNetwork.s.sol @@ -11,7 +11,6 @@ import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; import {ConsolidationsChecker} from "../contracts/validators/ConsolidationsChecker.sol"; import {GnoValidatorsChecker} from "../contracts/validators/GnoValidatorsChecker.sol"; import {GnoRewardSplitter} from "../contracts/misc/GnoRewardSplitter.sol"; -import {GnoDaiDistributor} from "../contracts/misc/GnoDaiDistributor.sol"; import {RewardSplitterFactory} from "../contracts/misc/RewardSplitterFactory.sol"; import {GnoGenesisVault} from "../contracts/vaults/gnosis/GnoGenesisVault.sol"; import {GnoVault} from "../contracts/vaults/gnosis/GnoVault.sol"; @@ -33,7 +32,7 @@ contract UpgradeGnoNetwork is Network { address public consolidationsChecker; address public validatorsChecker; address public rewardSplitterFactory; - address public gnoDaiDistributor; + address public tokensConverterFactory; address public curatorsRegistry; address public balancedCurator; @@ -42,6 +41,7 @@ contract UpgradeGnoNetwork is Network { function run() external { metaVaultFactoryOwner = vm.envAddress("META_VAULT_FACTORY_OWNER"); + tokensConverterFactory = vm.envAddress("TOKENS_CONVERTER_FACTORY"); uint256 privateKey = vm.envUint("PRIVATE_KEY"); address sender = vm.addr(privateKey); console.log("Deploying from: ", sender); @@ -63,14 +63,6 @@ contract UpgradeGnoNetwork is Network { ); address rewardsSplitterImpl = address(new GnoRewardSplitter(deployment.gnoToken)); rewardSplitterFactory = address(new RewardSplitterFactory(rewardsSplitterImpl)); - gnoDaiDistributor = address( - new GnoDaiDistributor( - deployment.sDaiToken, - deployment.vaultsRegistry, - deployment.savingsXDaiAdapter, - deployment.merkleDistributor - ) - ); // deploy curators curatorsRegistry = address(new CuratorsRegistry()); @@ -90,8 +82,7 @@ contract UpgradeGnoNetwork is Network { consolidationsChecker, rewardSplitterFactory, curatorsRegistry, - balancedCurator, - gnoDaiDistributor + balancedCurator ); } @@ -197,7 +188,7 @@ contract UpgradeGnoNetwork is Network { sharedMevEscrow: deployment.sharedMevEscrow, depositDataRegistry: deployment.depositDataRegistry, gnoToken: deployment.gnoToken, - gnoDaiDistributor: gnoDaiDistributor, + tokensConverterFactory: tokensConverterFactory, exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } @@ -217,7 +208,7 @@ contract UpgradeGnoNetwork is Network { sharedMevEscrow: deployment.sharedMevEscrow, depositDataRegistry: deployment.depositDataRegistry, gnoToken: deployment.gnoToken, - gnoDaiDistributor: gnoDaiDistributor, + tokensConverterFactory: tokensConverterFactory, exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } diff --git a/snapshots/DepositDataRegistryTest.json b/snapshots/DepositDataRegistryTest.json index 1b6aec12..3e2ba659 100644 --- a/snapshots/DepositDataRegistryTest.json +++ b/snapshots/DepositDataRegistryTest.json @@ -5,5 +5,5 @@ "DepositDataRegistryTest_test_registerValidators_successWith0x02Validators": "338614", "DepositDataRegistryTest_test_setDepositDataManager_succeeds": "66206", "DepositDataRegistryTest_test_setDepositDataRoot_succeeds": "65127", - "DepositDataRegistryTest_test_updateVaultState_succeeds": "128282" + "DepositDataRegistryTest_test_updateVaultState_succeeds": "128302" } \ No newline at end of file diff --git a/snapshots/EthBlocklistErc20VaultTest.json b/snapshots/EthBlocklistErc20VaultTest.json index a9c24e75..6909a965 100644 --- a/snapshots/EthBlocklistErc20VaultTest.json +++ b/snapshots/EthBlocklistErc20VaultTest.json @@ -2,7 +2,7 @@ "EthBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "89924", "EthBlocklistErc20VaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "84302", "EthBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161501", - "EthBlocklistErc20VaultTest_test_deploysCorrectly": "624840", + "EthBlocklistErc20VaultTest_test_deploysCorrectly": "624893", "EthBlocklistErc20VaultTest_test_transfer": "61693", - "EthBlocklistErc20VaultTest_test_upgradesCorrectly": "89964" + "EthBlocklistErc20VaultTest_test_upgradesCorrectly": "89988" } \ No newline at end of file diff --git a/snapshots/EthBlocklistVaultTest.json b/snapshots/EthBlocklistVaultTest.json index 0751aa6e..f720356f 100644 --- a/snapshots/EthBlocklistVaultTest.json +++ b/snapshots/EthBlocklistVaultTest.json @@ -2,6 +2,6 @@ "EthBlocklistVaultTest_test_canDepositAsNonBlockedUser": "87971", "EthBlocklistVaultTest_test_canDepositUsingReceiveAsNotBlockedUser": "82360", "EthBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161505", - "EthBlocklistVaultTest_test_deploysCorrectly": "549641", - "EthBlocklistVaultTest_test_upgradesCorrectly": "89295" + "EthBlocklistVaultTest_test_deploysCorrectly": "549694", + "EthBlocklistVaultTest_test_upgradesCorrectly": "89319" } \ No newline at end of file diff --git a/snapshots/EthErc20VaultTest.json b/snapshots/EthErc20VaultTest.json index f9bf973f..4daa2f6e 100644 --- a/snapshots/EthErc20VaultTest.json +++ b/snapshots/EthErc20VaultTest.json @@ -1,15 +1,15 @@ { "EthErc20VaultTest_test_canTransferFromSharesWithHighLtv": "90077", "EthErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96608", - "EthErc20VaultTest_test_deploysCorrectly": "454568", + "EthErc20VaultTest_test_deploysCorrectly": "454621", "EthErc20VaultTest_test_depositAndMintOsToken": "201247", "EthErc20VaultTest_test_depositViaReceiveFallback_emitsTransfer": "75451", "EthErc20VaultTest_test_deposit_emitsTransfer": "78913", "EthErc20VaultTest_test_enterExitQueue_emitsTransfer": "89780", "EthErc20VaultTest_test_redeem_emitsEvent": "58285", - "EthErc20VaultTest_test_updateExitQueue_emitsTransfer": "177057", - "EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken": "227515", - "EthErc20VaultTest_test_upgradesCorrectly": "89838", + "EthErc20VaultTest_test_updateExitQueue_emitsTransfer": "177077", + "EthErc20VaultTest_test_updateStateAndDepositAndMintOsToken": "227535", + "EthErc20VaultTest_test_upgradesCorrectly": "89862", "EthErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "79487", "EthErc20VaultTest_test_withdrawValidator_unknown": "61328", "EthErc20VaultTest_test_withdrawValidator_validatorsManager": "74259" diff --git a/snapshots/EthGenesisVaultTest.json b/snapshots/EthGenesisVaultTest.json index f4b2ad93..6e5f5a5f 100644 --- a/snapshots/EthGenesisVaultTest.json +++ b/snapshots/EthGenesisVaultTest.json @@ -3,6 +3,6 @@ "EthGenesisVaultTest_test_fallback_acceptsEtherFromPoolEscrow": "33277", "EthGenesisVaultTest_test_fallback_acceptsEtherFromUser": "77540", "EthGenesisVaultTest_test_migrate_works": "201699", - "EthGenesisVaultTest_test_upgradesCorrectly": "68918", + "EthGenesisVaultTest_test_upgradesCorrectly": "68942", "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "803804" } \ No newline at end of file diff --git a/snapshots/EthPrivErc20VaultTest.json b/snapshots/EthPrivErc20VaultTest.json index 1b23fad6..488a157e 100644 --- a/snapshots/EthPrivErc20VaultTest.json +++ b/snapshots/EthPrivErc20VaultTest.json @@ -3,7 +3,7 @@ "EthPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "81407", "EthPrivErc20VaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "77693", "EthPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161601", - "EthPrivErc20VaultTest_test_deploysCorrectly": "624862", + "EthPrivErc20VaultTest_test_deploysCorrectly": "624915", "EthPrivErc20VaultTest_test_transfer": "59709", - "EthPrivErc20VaultTest_test_upgradesCorrectly": "89984" + "EthPrivErc20VaultTest_test_upgradesCorrectly": "90008" } \ No newline at end of file diff --git a/snapshots/EthPrivVaultTest.json b/snapshots/EthPrivVaultTest.json index 9c4cb000..bf84e8f2 100644 --- a/snapshots/EthPrivVaultTest.json +++ b/snapshots/EthPrivVaultTest.json @@ -2,10 +2,10 @@ "EthPrivVaultTest_test_canDepositAsWhitelistedUser": "79443", "EthPrivVaultTest_test_canDepositUsingReceiveAsWhitelistedUser": "75857", "EthPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161605", - "EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser": "138167", - "EthPrivVaultTest_test_deploysCorrectly": "549659", + "EthPrivVaultTest_test_canUpdateStateAndDepositAsWhitelistedUser": "138187", + "EthPrivVaultTest_test_deploysCorrectly": "549712", "EthPrivVaultTest_test_depositAndMintOsTokenAsWhitelistedUser": "200547", "EthPrivVaultTest_test_setWhitelister": "36458", "EthPrivVaultTest_test_updateWhitelist": "54543", - "EthPrivVaultTest_test_upgradesCorrectly": "89410" + "EthPrivVaultTest_test_upgradesCorrectly": "89434" } \ No newline at end of file diff --git a/snapshots/EthRewardSplitterTest.json b/snapshots/EthRewardSplitterTest.json index 88016e6f..62d51edf 100644 --- a/snapshots/EthRewardSplitterTest.json +++ b/snapshots/EthRewardSplitterTest.json @@ -1,14 +1,14 @@ { - "EthRewardSplitter_claimExitedAssetsOnBehalf": "749259", - "EthRewardSplitter_claimVaultTokens": "756516", + "EthRewardSplitter_claimExitedAssetsOnBehalf": "749279", + "EthRewardSplitter_claimVaultTokens": "756536", "EthRewardSplitter_decreaseShares": "87684", "EthRewardSplitter_enterExitQueue": "166923", "EthRewardSplitter_enterExitQueueMaxWithdrawal": "128951", - "EthRewardSplitter_enterExitQueueOnBehalf": "906700", + "EthRewardSplitter_enterExitQueueOnBehalf": "906720", "EthRewardSplitter_increaseShares": "73201", "EthRewardSplitter_receiveEth": "31194", "EthRewardSplitter_setClaimOnBehalf": "65579", "EthRewardSplitter_syncRewards": "77733", "EthRewardSplitter_syncRewardsDetailed": "75233", - "EthRewardSplitter_updateVaultState": "132605" + "EthRewardSplitter_updateVaultState": "132625" } \ No newline at end of file diff --git a/snapshots/EthVaultTest.json b/snapshots/EthVaultTest.json index 83740b8e..4749afd4 100644 --- a/snapshots/EthVaultTest.json +++ b/snapshots/EthVaultTest.json @@ -1,10 +1,10 @@ { - "EthVaultTest_test_deploysCorrectly": "379445", + "EthVaultTest_test_deploysCorrectly": "379498", "EthVaultTest_test_depositAndMintOsToken": "199548", "EthVaultTest_test_exitQueue_works": "96643", "EthVaultTest_test_fallbackDeposit": "75127", - "EthVaultTest_test_updateStateAndDepositAndMintOsToken": "228138", - "EthVaultTest_test_upgradesCorrectly": "89254", + "EthVaultTest_test_updateStateAndDepositAndMintOsToken": "228158", + "EthVaultTest_test_upgradesCorrectly": "89278", "EthVaultTest_test_withdrawValidator_osTokenRedeemer": "79520", "EthVaultTest_test_withdrawValidator_unknown": "61361", "EthVaultTest_test_withdrawValidator_validatorsManager": "74281" diff --git a/snapshots/GnoBlocklistErc20VaultTest.json b/snapshots/GnoBlocklistErc20VaultTest.json index 67e57acc..58248c62 100644 --- a/snapshots/GnoBlocklistErc20VaultTest.json +++ b/snapshots/GnoBlocklistErc20VaultTest.json @@ -1,7 +1,7 @@ { - "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "162532", + "GnoBlocklistErc20VaultTest_test_canDepositAsNonBlockedUser": "160088", "GnoBlocklistErc20VaultTest_test_canMintOsTokenAsNonBlockedUser": "161610", - "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "780245", + "GnoBlocklistErc20VaultTest_test_deploysCorrectly": "953126", "GnoBlocklistErc20VaultTest_test_transfer": "61693", - "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "132219" + "GnoBlocklistErc20VaultTest_test_upgradesCorrectly": "305228" } \ No newline at end of file diff --git a/snapshots/GnoBlocklistVaultTest.json b/snapshots/GnoBlocklistVaultTest.json index 7039dee8..ed994c3b 100644 --- a/snapshots/GnoBlocklistVaultTest.json +++ b/snapshots/GnoBlocklistVaultTest.json @@ -1,6 +1,6 @@ { - "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "160548", + "GnoBlocklistVaultTest_test_canDepositAsNonBlockedUser": "158104", "GnoBlocklistVaultTest_test_canMintOsTokenAsNonBlockedUser": "161570", - "GnoBlocklistVaultTest_test_deploysCorrectly": "528645", - "GnoBlocklistVaultTest_test_upgradesCorrectly": "131539" + "GnoBlocklistVaultTest_test_deploysCorrectly": "701751", + "GnoBlocklistVaultTest_test_upgradesCorrectly": "304524" } \ No newline at end of file diff --git a/snapshots/GnoErc20VaultTest.json b/snapshots/GnoErc20VaultTest.json index 2744582c..16bb944d 100644 --- a/snapshots/GnoErc20VaultTest.json +++ b/snapshots/GnoErc20VaultTest.json @@ -1,11 +1,11 @@ { "GnoErc20VaultTest_test_canTransferFromSharesWithHighLtv": "90100", "GnoErc20VaultTest_test_cannotTransferFromSharesWithLowLtv": "96637", - "GnoErc20VaultTest_test_deploysCorrectly": "579952", - "GnoErc20VaultTest_test_deposit_emitsTransfer": "100687", + "GnoErc20VaultTest_test_deploysCorrectly": "752844", + "GnoErc20VaultTest_test_deposit_emitsTransfer": "98232", "GnoErc20VaultTest_test_enterExitQueue_emitsTransfer": "89780", - "GnoErc20VaultTest_test_redeem_emitsEvent": "77058", - "GnoErc20VaultTest_test_upgradesCorrectly": "132165", + "GnoErc20VaultTest_test_redeem_emitsEvent": "77069", + "GnoErc20VaultTest_test_upgradesCorrectly": "305196", "VaultGnoErc20VaultTest_test_withdrawValidator_osTokenRedeemer": "79509", "VaultGnoErc20VaultTest_test_withdrawValidator_unknown": "61350", "VaultGnoErc20VaultTest_test_withdrawValidator_validatorsManager": "74281" diff --git a/snapshots/GnoGenesisVaultTest.json b/snapshots/GnoGenesisVaultTest.json index b7f71202..fde0db38 100644 --- a/snapshots/GnoGenesisVaultTest.json +++ b/snapshots/GnoGenesisVaultTest.json @@ -1,5 +1,5 @@ { "GnoGenesisVaultTest_test_migrate_works": "204031", - "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "873476", - "GnoGenesisVaultTest_test_upgradesCorrectly": "5544467" + "GnoGenesisVaultTest_test_pullWithdrawals_claimEscrowAssets": "867736", + "GnoGenesisVaultTest_test_upgradesCorrectly": "5754864" } \ No newline at end of file diff --git a/snapshots/GnoMetaVaultTest.json b/snapshots/GnoMetaVaultTest.json index 5264af47..9fd5f0f9 100644 --- a/snapshots/GnoMetaVaultTest.json +++ b/snapshots/GnoMetaVaultTest.json @@ -2,7 +2,7 @@ "GnoMetaVaultTest_test_addSubVault": "148145", "GnoMetaVaultTest_test_claimExitedAssets": "70091", "GnoMetaVaultTest_test_deposit": "103282", - "GnoMetaVaultTest_test_depositToSubVaults": "338652", + "GnoMetaVaultTest_test_depositToSubVaults": "331320", "GnoMetaVaultTest_test_ejectSubVault": "211780", "GnoMetaVaultTest_test_enterExitQueue": "86712", "GnoMetaVaultTest_test_updateState": "135992" diff --git a/snapshots/GnoOsTokenVaultEscrowTest.json b/snapshots/GnoOsTokenVaultEscrowTest.json index 4553a803..15acc615 100644 --- a/snapshots/GnoOsTokenVaultEscrowTest.json +++ b/snapshots/GnoOsTokenVaultEscrowTest.json @@ -1,5 +1,5 @@ { "GnoOsTokenVaultEscrowTest_test_transferAssets_claim": "140340", - "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "862217", + "GnoOsTokenVaultEscrowTest_test_transferAssets_process": "873892", "GnoOsTokenVaultEscrowTest_test_transferAssets_transfer": "163157" } \ No newline at end of file diff --git a/snapshots/GnoPrivErc20VaultTest.json b/snapshots/GnoPrivErc20VaultTest.json index 32d99fdb..bed69568 100644 --- a/snapshots/GnoPrivErc20VaultTest.json +++ b/snapshots/GnoPrivErc20VaultTest.json @@ -1,7 +1,7 @@ { - "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "158461", + "GnoPrivErc20VaultTest_test_canDepositAsWhitelistedUser": "156017", "GnoPrivErc20VaultTest_test_canMintOsTokenAsWhitelistedUser": "161543", - "GnoPrivErc20VaultTest_test_deploysCorrectly": "780267", + "GnoPrivErc20VaultTest_test_deploysCorrectly": "953170", "GnoPrivErc20VaultTest_test_transfer": "59709", - "GnoPrivErc20VaultTest_test_upgradesCorrectly": "132334" + "GnoPrivErc20VaultTest_test_upgradesCorrectly": "305365" } \ No newline at end of file diff --git a/snapshots/GnoPrivVaultTest.json b/snapshots/GnoPrivVaultTest.json index eb4eee76..d03d2469 100644 --- a/snapshots/GnoPrivVaultTest.json +++ b/snapshots/GnoPrivVaultTest.json @@ -1,8 +1,8 @@ { - "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "156564", + "GnoPrivVaultTest_test_canDepositAsWhitelistedUser": "154120", "GnoPrivVaultTest_test_canMintOsTokenAsWhitelistedUser": "161480", - "GnoPrivVaultTest_test_deploysCorrectly": "528667", + "GnoPrivVaultTest_test_deploysCorrectly": "701795", "GnoPrivVaultTest_test_setWhitelister": "36458", "GnoPrivVaultTest_test_updateWhitelist": "54521", - "GnoPrivVaultTest_test_upgradesCorrectly": "131653" + "GnoPrivVaultTest_test_upgradesCorrectly": "304660" } \ No newline at end of file diff --git a/snapshots/GnoRewardSplitterTest.json b/snapshots/GnoRewardSplitterTest.json index 98be499b..773ffef8 100644 --- a/snapshots/GnoRewardSplitterTest.json +++ b/snapshots/GnoRewardSplitterTest.json @@ -1,14 +1,14 @@ { "GnoRewardSplitter_claimExitedAssets": "92207", - "GnoRewardSplitter_claimExitedAssetsOnBehalf": "794911", - "GnoRewardSplitter_claimVaultTokens": "826245", + "GnoRewardSplitter_claimExitedAssetsOnBehalf": "806598", + "GnoRewardSplitter_claimVaultTokens": "837932", "GnoRewardSplitter_decreaseShares": "96070", "GnoRewardSplitter_enterExitQueue": "184280", "GnoRewardSplitter_enterExitQueueMaxWithdrawal": "128951", - "GnoRewardSplitter_enterExitQueueOnBehalf": "1002298", + "GnoRewardSplitter_enterExitQueueOnBehalf": "1011531", "GnoRewardSplitter_increaseShares": "70723", "GnoRewardSplitter_setClaimOnBehalf": "65601", "GnoRewardSplitter_syncRewards": "77733", "GnoRewardSplitter_syncRewardsDetailed": "75233", - "GnoRewardSplitter_updateVaultState": "153776" + "GnoRewardSplitter_updateVaultState": "165440" } \ No newline at end of file diff --git a/snapshots/GnoVaultExitQueueTest.json b/snapshots/GnoVaultExitQueueTest.json index c5c7eef9..24e19bce 100644 --- a/snapshots/GnoVaultExitQueueTest.json +++ b/snapshots/GnoVaultExitQueueTest.json @@ -1,7 +1,7 @@ { - "GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event": "200171", - "GnoVaultExitQueueTest_test_claim_position1_after_upgrade": "6370270", + "GnoVaultExitQueueTest_test_ExitingAssetsPenalized_event": "211846", + "GnoVaultExitQueueTest_test_claim_position1_after_upgrade": "6553430", "GnoVaultExitQueueTest_test_claim_position2_before_upgrade": "123260", - "GnoVaultExitQueueTest_test_claim_position3_after_upgrade": "160234", + "GnoVaultExitQueueTest_test_claim_position3_after_upgrade": "160243", "GnoVaultExitQueueTest_test_claim_position4_after_upgrade": "155421" } \ No newline at end of file diff --git a/snapshots/GnoVaultTest.json b/snapshots/GnoVaultTest.json index 1686b323..ac07d614 100644 --- a/snapshots/GnoVaultTest.json +++ b/snapshots/GnoVaultTest.json @@ -1,7 +1,7 @@ { - "GnoVaultTest_test_deploysCorrectly": "504709", + "GnoVaultTest_test_deploysCorrectly": "677859", "GnoVaultTest_test_exitQueue_works": "96643", - "GnoVaultTest_test_upgradesCorrectly": "131527", + "GnoVaultTest_test_upgradesCorrectly": "304556", "GnoVaultTest_test_withdrawValidator_osTokenRedeemer": "79497", "GnoVaultTest_test_withdrawValidator_unknown": "61338", "GnoVaultTest_test_withdrawValidator_validatorsManager": "74258" diff --git a/snapshots/KeeperRewardsTest.json b/snapshots/KeeperRewardsTest.json index 2a8443d6..9192df01 100644 --- a/snapshots/KeeperRewardsTest.json +++ b/snapshots/KeeperRewardsTest.json @@ -1,16 +1,16 @@ { "KeeperRewardsTest_test_canHarvest": "12938", - "KeeperRewardsTest_test_harvest": "130823", - "KeeperRewardsTest_test_harvestWithPenalties": "92516", - "KeeperRewardsTest_test_harvest_alreadyHarvested": "47952", + "KeeperRewardsTest_test_harvest": "130843", + "KeeperRewardsTest_test_harvestWithPenalties": "92536", + "KeeperRewardsTest_test_harvest_alreadyHarvested": "47972", "KeeperRewardsTest_test_harvest_invalidProof": "49041", "KeeperRewardsTest_test_harvest_invalidRewardsRoot": "49601", "KeeperRewardsTest_test_harvest_nonVault": "35559", "KeeperRewardsTest_test_isCollateralized": "10123", "KeeperRewardsTest_test_isHarvestRequired": "12620", - "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_1": "135305", - "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_2": "581717", - "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_3": "581727", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_1": "135325", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_2": "581737", + "KeeperRewardsTest_test_multipleRewardUpdatesAndHarvests_round_3": "581747", "KeeperRewardsTest_test_setRewardsMinOracles": "35248", "KeeperRewardsTest_test_setRewardsMinOracles_tooMany": "29542", "KeeperRewardsTest_test_setRewardsMinOracles_zero": "27531", diff --git a/snapshots/VaultAdminTest.json b/snapshots/VaultAdminTest.json index 3beaf8ab..4a610d07 100644 --- a/snapshots/VaultAdminTest.json +++ b/snapshots/VaultAdminTest.json @@ -1,7 +1,7 @@ { "VaultAdminTest_test_checkAdmin_withOtherFunctions_admin": "43348", "VaultAdminTest_test_checkAdmin_withOtherFunctions_nonAdmin": "34790", - "VaultAdminTest_test_initialization": "378236", + "VaultAdminTest_test_initialization": "378289", "VaultAdminTest_test_setAdmin_byAdmin": "39009", "VaultAdminTest_test_setAdmin_byNonAdmin": "36858", "VaultAdminTest_test_setAdmin_toZeroAddress": "34573", diff --git a/snapshots/VaultEnterExitTest.json b/snapshots/VaultEnterExitTest.json index 8bd4ba21..4bdd3ec7 100644 --- a/snapshots/VaultEnterExitTest.json +++ b/snapshots/VaultEnterExitTest.json @@ -1,6 +1,6 @@ { "VaultEnterExitTest_test_calculateExitedAssets_invalidPosition": "18577", - "VaultEnterExitTest_test_claimExitedAssets": "730303", + "VaultEnterExitTest_test_claimExitedAssets": "730323", "VaultEnterExitTest_test_claimExitedAssets_insufficientDelay": "41431", "VaultEnterExitTest_test_claimExitedAssets_invalidCheckpoint": "36506", "VaultEnterExitTest_test_deposit_exceedingCapacity": "47943", diff --git a/snapshots/VaultEthStakingTest.json b/snapshots/VaultEthStakingTest.json index 5b01e9fa..6c27ca2e 100644 --- a/snapshots/VaultEthStakingTest.json +++ b/snapshots/VaultEthStakingTest.json @@ -3,16 +3,16 @@ "VaultEthStakingTest_test_depositAndMintOsToken": "200035", "VaultEthStakingTest_test_fundValidators_invalid": "57366", "VaultEthStakingTest_test_fundValidators_valid": "140938", - "VaultEthStakingTest_test_harvestAssets": "130825", - "VaultEthStakingTest_test_invalidSecurityDeposit": "307913", + "VaultEthStakingTest_test_harvestAssets": "130845", + "VaultEthStakingTest_test_invalidSecurityDeposit": "307966", "VaultEthStakingTest_test_receive": "75018", "VaultEthStakingTest_test_receiveFromMevEscrow_fail": "36570", "VaultEthStakingTest_test_receiveFromMevEscrow_success": "37826", "VaultEthStakingTest_test_registerValidators_01prefix": "244309", "VaultEthStakingTest_test_registerValidators_02prefix": "501482", "VaultEthStakingTest_test_transferVaultAssets": "51757", - "VaultEthStakingTest_test_updateStateAndDeposit": "164153", - "VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken": "254248", + "VaultEthStakingTest_test_updateStateAndDeposit": "164173", + "VaultEthStakingTest_test_updateStateAndDepositAndMintOsToken": "254268", "VaultEthStakingTest_test_validatorMinMaxEffectiveBalance": "200164", "VaultEthStakingTest_test_withdrawValidator_fullFlow": "74281" } \ No newline at end of file diff --git a/snapshots/VaultFeeTest.json b/snapshots/VaultFeeTest.json index d2f75eed..9e09290c 100644 --- a/snapshots/VaultFeeTest.json +++ b/snapshots/VaultFeeTest.json @@ -1,6 +1,6 @@ { - "VaultFeeTest_test_feeCollection": "121911", - "VaultFeeTest_test_feePercent_changeAffectsFutureRewards": "87713", + "VaultFeeTest_test_feeCollection": "121931", + "VaultFeeTest_test_feePercent_changeAffectsFutureRewards": "87733", "VaultFeeTest_test_setFeePercent_aboveMaximum": "40380", "VaultFeeTest_test_setFeePercent_initialZeroToOne": "42312", "VaultFeeTest_test_setFeePercent_maxIncrease": "38472", diff --git a/snapshots/VaultGnoStakingTest.json b/snapshots/VaultGnoStakingTest.json index a2797e68..deffe5a5 100644 --- a/snapshots/VaultGnoStakingTest.json +++ b/snapshots/VaultGnoStakingTest.json @@ -1,14 +1,14 @@ { - "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "140831", + "VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance": "175401", "VaultGnoStakingCoverageTest_test_registerValidator_topUp_invalid": "57291", - "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "179488", - "VaultGnoStakingTest_test_deposit": "101081", - "VaultGnoStakingTest_test_processTotalAssetsDelta": "225851", - "VaultGnoStakingTest_test_pullWithdrawals": "92512", - "VaultGnoStakingTest_test_receive_xDai": "33415", + "VaultGnoStakingCoverageTest_test_registerValidator_topUp_valid": "182609", + "VaultGnoStakingTest_test_deposit": "98637", + "VaultGnoStakingTest_test_processTotalAssetsDelta": "303158", + "VaultGnoStakingTest_test_pullWithdrawals": "90406", + "VaultGnoStakingTest_test_receive_xDai": "213139", "VaultGnoStakingTest_test_transferVaultAssets": "87437", - "VaultGnoStakingTest_test_vaultGnoStaking_init": "504708", - "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "74246", - "test_registerValidators_succeeds_0x01": "288174", - "test_registerValidators_succeeds_0x02": "632039" + "VaultGnoStakingTest_test_vaultGnoStaking_init": "677858", + "VaultGnoStakingTest_test_withdrawValidator_fullFlow": "74258", + "test_registerValidators_succeeds_0x01": "286974", + "test_registerValidators_succeeds_0x02": "630578" } \ No newline at end of file diff --git a/snapshots/VaultOsTokenTest.json b/snapshots/VaultOsTokenTest.json index ef5355b9..1c55821c 100644 --- a/snapshots/VaultOsTokenTest.json +++ b/snapshots/VaultOsTokenTest.json @@ -25,7 +25,7 @@ "VaultOsTokenTest_test_mintOsToken_zeroShares": "89092", "VaultOsTokenTest_test_redeemOsToken_afterFeeSync": "134280", "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_fail": "50939", - "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success": "265646", + "VaultOsTokenTest_test_redeemOsToken_afterStateUpdate_success": "265666", "VaultOsTokenTest_test_redeemOsToken_basic": "133778", "VaultOsTokenTest_test_redeemOsToken_fullPosition": "133778", "VaultOsTokenTest_test_redeemOsToken_goodHealthFactor": "133861", @@ -43,6 +43,6 @@ "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_noPosition": "43502", "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_notHarvested": "41330", "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_partialTransfer": "173208", - "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process": "721121", + "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_process": "721141", "VaultOsTokenTest_test_transferOsTokenPositionToEscrow_zeroShares": "47545" } \ No newline at end of file diff --git a/snapshots/VaultTokenTest.json b/snapshots/VaultTokenTest.json index efe7613f..8c5eea05 100644 --- a/snapshots/VaultTokenTest.json +++ b/snapshots/VaultTokenTest.json @@ -3,8 +3,8 @@ "VaultTokenTest_test_approveZeroAddress": "33703", "VaultTokenTest_test_depositEmitsTransferEvent": "80993", "VaultTokenTest_test_enterExitQueueEmitsTransferEvent": "94566", - "VaultTokenTest_test_invalidTokenMetaNameTooLong": "477587", - "VaultTokenTest_test_invalidTokenMetaSymbolTooLong": "310655", + "VaultTokenTest_test_invalidTokenMetaNameTooLong": "477640", + "VaultTokenTest_test_invalidTokenMetaSymbolTooLong": "310708", "VaultTokenTest_test_permit": "84690", "VaultTokenTest_test_permitExpiredDeadline": "32817", "VaultTokenTest_test_permitInvalidSigner": "61070", @@ -18,5 +18,5 @@ "VaultTokenTest_test_transferToZeroAddress": "31234", "VaultTokenTest_test_transferWithOsTokenPosition": "94084", "VaultTokenTest_test_unlimitedAllowance": "66861", - "VaultTokenTest_test_updateExitQueueBurnsShares": "146959" + "VaultTokenTest_test_updateExitQueueBurnsShares": "146979" } \ No newline at end of file diff --git a/test/gnosis/VaultGnoStaking.t.sol b/test/gnosis/VaultGnoStaking.t.sol index 68e8000e..2fc4d4b9 100644 --- a/test/gnosis/VaultGnoStaking.t.sol +++ b/test/gnosis/VaultGnoStaking.t.sol @@ -10,6 +10,7 @@ import {GnoHelpers} from "../helpers/GnoHelpers.sol"; import {Errors} from "../../contracts/libraries/Errors.sol"; import {GnoVault} from "../../contracts/vaults/gnosis/GnoVault.sol"; import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; +import {ITokensConverterFactory} from "../../contracts/interfaces/ITokensConverterFactory.sol"; contract VaultGnoStakingTest is Test, GnoHelpers { ForkContracts public contracts; @@ -94,6 +95,9 @@ contract VaultGnoStakingTest is Test, GnoHelpers { } function test_withdrawableAssets() public { + (,,, uint256 totalExitingAssets,) = vault.getExitQueueData(); + _mintGnoToken(address(vault), totalExitingAssets); + uint256 withdrawableBefore = vault.withdrawableAssets(); // Deposit some GNO @@ -110,53 +114,54 @@ contract VaultGnoStakingTest is Test, GnoHelpers { // Deposit GNO _depositGno(depositAmount, sender, receiver); - // Now simulate some xDAI balance that would trigger distribution + // Now simulate some xDAI balance that would trigger swap vm.deal(vault.mevEscrow(), 1 ether); // use the same conversion function as for GnoVault - uint256 vaultBalanceBefore = address(vault).balance; - uint256 expectedAddedSDai = - IGnoVault(address(contracts.sdaiToken)).convertToShares(vaultBalanceBefore + 1 ether); - _collateralizeGnoVault(address(vault)); IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 1 ether); - uint256 distributorBalanceBefore = contracts.sdaiToken.balanceOf(address(contracts.merkleDistributor)); + address converter = ITokensConverterFactory(_tokensConverterFactory).getTokensConverter(address(vault)); + uint256 balanceBefore = contracts.sdaiToken.balanceOf(converter); // Update state which will trigger _processTotalAssetsDelta _startSnapshotGas("VaultGnoStakingTest_test_processTotalAssetsDelta"); vault.updateState(harvestParams); _stopSnapshotGas(); + uint256 balanceAfter = contracts.sdaiToken.balanceOf(converter); + // Verify sDAI was sent to the distributor assertEq(address(vault).balance, 0, "Vault should have no xDAI left"); - assertEq( - contracts.sdaiToken.balanceOf(address(contracts.merkleDistributor)), - distributorBalanceBefore + expectedAddedSDai, - "Distributor should get sDAI" - ); + assertEq(address(vault.mevEscrow()).balance, 0, "Vault should have no xDAI left in the escrow"); + assertGt(balanceAfter, balanceBefore + 1 ether / 2, "sDAI balance should increase after processing xDAI"); } function test_processTotalAssetsDelta_smallXdaiBalance() public { + address converter = ITokensConverterFactory(_tokensConverterFactory).getTokensConverter(address(vault)); + // Deposit GNO _depositGno(depositAmount, sender, sender); // Small xDAI amount (below 0.1 ETH threshold) vm.deal(vault.mevEscrow(), 0.09 ether); + vm.deal(address(vault), 0); // Process rewards _collateralizeGnoVault(address(vault)); - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 1 ether, 0); + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 1 ether, 0.09 ether); - uint256 mevBalanceBefore = address(vault.mevEscrow()).balance; + uint256 sdaiBefore = contracts.sdaiToken.balanceOf(converter); // Update state _startSnapshotGas("VaultGnoStakingCoverageTest_test_processTotalAssetsDelta_smallXdaiBalance"); vault.updateState(harvestParams); _stopSnapshotGas(); - // Verify small xDAI balance wasn't processed (below 0.1 ETH threshold) - assertEq(address(vault.mevEscrow()).balance, mevBalanceBefore, "xDAI balance should remain unchanged"); + assertEq(address(vault.mevEscrow()).balance, 0, "xDAI should be transferred to the converter"); + assertEq(address(vault).balance, 0, "Vault should have no xDAI left"); + assertEq(sdaiBefore, contracts.sdaiToken.balanceOf(converter), "sDAI balance should not change"); + assertEq(address(converter).balance, 0.09 ether, "Converter should have received the xDAI from the escrow"); } function test_vaultAssets() public { @@ -181,46 +186,60 @@ contract VaultGnoStakingTest is Test, GnoHelpers { } function test_pullWithdrawals() public { + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); + GnoVault newVault = GnoVault(payable(vaultAddr)); + + // set validators manager + vm.prank(admin); + newVault.setValidatorsManager(validatorsManager); + // 1. Deposit GNO - _depositGno(depositAmount, sender, sender); + _depositToVault(address(newVault), depositAmount, sender, sender); // 2. Register a validator - _registerGnoValidator(address(vault), 1 ether, true); + _registerGnoValidator(address(newVault), 1 ether, true); // 3. Set up withdrawable GNO in the registry (simulate validator withdrawal) uint256 withdrawalAmount = 2 ether; - _setGnoWithdrawals(address(vault), withdrawalAmount); + _setGnoWithdrawals(address(newVault), withdrawalAmount); // Verify the registry shows the correct withdrawable amount assertEq( - contracts.validatorsRegistry.withdrawableAmount(address(vault)), + contracts.validatorsRegistry.withdrawableAmount(address(newVault)), withdrawalAmount, "Withdrawal amount not set correctly" ); // Record initial balances uint256 senderInitialBalance = contracts.gnoToken.balanceOf(sender); - uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(vault)); + uint256 vaultInitialBalance = contracts.gnoToken.balanceOf(address(newVault)); // 4. Enter the exit queue with shares - uint256 shares = vault.getShares(sender); + uint256 shares = newVault.getShares(sender); uint256 timestamp = vm.getBlockTimestamp(); vm.prank(sender); - uint256 positionTicket = vault.enterExitQueue(shares, sender); + uint256 positionTicket = newVault.enterExitQueue(shares, sender); // 5. Process the exit queue // Update vault state to process the exit queue - IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(vault), 0, 0); - vault.updateState(harvestParams); + IKeeperRewards.HarvestParams memory harvestParams = _setGnoVaultReward(address(newVault), 0, 0); + newVault.updateState(harvestParams); // 6. Claim exited assets vm.warp(vm.getBlockTimestamp() + _exitingAssetsClaimDelay + 1); - int256 exitQueueIndex = vault.getExitQueueIndex(positionTicket); + int256 exitQueueIndex = newVault.getExitQueueIndex(positionTicket); assertGt(exitQueueIndex, -1, "Exit queue index not found"); _startSnapshotGas("VaultGnoStakingTest_test_pullWithdrawals"); vm.prank(sender); - vault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); + newVault.claimExitedAssets(positionTicket, timestamp, uint256(exitQueueIndex)); _stopSnapshotGas(); // 7. Verify results @@ -229,36 +248,50 @@ contract VaultGnoStakingTest is Test, GnoHelpers { assertGt(senderFinalBalance, senderInitialBalance, "Sender did not receive exited assets"); // Registry should have 0 withdrawable amount - uint256 registryFinalWithdrawable = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + uint256 registryFinalWithdrawable = contracts.validatorsRegistry.withdrawableAmount(address(newVault)); assertEq(registryFinalWithdrawable, 0, "Registry withdrawable amount should be completely claimed"); // Vault's GNO balance should have changed due to _pullWithdrawals - uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(vault)); + uint256 vaultFinalBalance = contracts.gnoToken.balanceOf(address(newVault)); // The vault should have transferred out GNO (either directly or via _pullWithdrawals) assertLt(vaultFinalBalance, vaultInitialBalance + withdrawalAmount, "Vault balance should reflect withdrawals"); } function test_registerValidators_pullsWithdrawals() public { + bytes memory initParams = abi.encode( + IGnoVault.GnoVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "bafkreidivzimqfqtoqxkrpge6bjyhlvxqs3rhe73owtmdulaxr5do5in7u" + }) + ); + address vaultAddr = _createVault(VaultType.GnoVault, admin, initParams, false); + GnoVault newVault = GnoVault(payable(vaultAddr)); + + // set validators manager + vm.prank(admin); + newVault.setValidatorsManager(validatorsManager); + // Setup: Set GNO withdrawals in the validators registry uint256 withdrawalAmount = 2 ether; - _setGnoWithdrawals(address(vault), withdrawalAmount); - uint256 withdrawableBefore = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + _setGnoWithdrawals(address(newVault), withdrawalAmount); + uint256 withdrawableBefore = contracts.validatorsRegistry.withdrawableAmount(address(newVault)); // Get vault's GNO balance before registration - uint256 vaultGnoBalanceBefore = contracts.gnoToken.balanceOf(address(vault)); + uint256 vaultGnoBalanceBefore = contracts.gnoToken.balanceOf(address(newVault)); // setup oracle _startOracleImpersonate(address(contracts.keeper)); // Register a validator - this should trigger a withdrawal claim IKeeperValidators.ApprovalParams memory approvalParams = - _getGnoValidatorApproval(address(vault), 1 ether, "ipfsHash", false); + _getGnoValidatorApproval(address(newVault), 1 ether, "ipfsHash", false); vm.prank(validatorsManager); - vault.registerValidators(approvalParams, ""); + newVault.registerValidators(approvalParams, ""); // Verify that withdrawals were pulled by checking the vault's GNO balance increased - uint256 vaultGnoBalanceAfter = contracts.gnoToken.balanceOf(address(vault)); + uint256 vaultGnoBalanceAfter = contracts.gnoToken.balanceOf(address(newVault)); assertGe( vaultGnoBalanceAfter, vaultGnoBalanceBefore + withdrawableBefore - 1 ether, @@ -266,7 +299,7 @@ contract VaultGnoStakingTest is Test, GnoHelpers { ); // Verify the withdrawable amount is now 0 - uint256 withdrawableAfter = contracts.validatorsRegistry.withdrawableAmount(address(vault)); + uint256 withdrawableAfter = contracts.validatorsRegistry.withdrawableAmount(address(newVault)); assertEq(withdrawableAfter, 0, "Withdrawable amount should be cleared after claiming"); // revert previous state @@ -274,6 +307,9 @@ contract VaultGnoStakingTest is Test, GnoHelpers { } function test_registerValidators_succeeds() public { + (,,, uint256 totalExitingAssets,) = vault.getExitQueueData(); + _mintGnoToken(address(vault), totalExitingAssets); + // Setup oracle _startOracleImpersonate(address(contracts.keeper)); @@ -305,15 +341,18 @@ contract VaultGnoStakingTest is Test, GnoHelpers { uint256 sendAmount = 0.5 ether; vm.deal(sender, sendAmount); - uint256 balanceBefore = address(vault).balance; + address converter = ITokensConverterFactory(_tokensConverterFactory).getTokensConverter(address(vault)); + uint256 balanceBefore = contracts.sdaiToken.balanceOf(converter); vm.prank(sender); _startSnapshotGas("VaultGnoStakingTest_test_receive_xDai"); (bool success,) = address(vault).call{value: sendAmount}(""); _stopSnapshotGas(); + uint256 balanceAfter = contracts.sdaiToken.balanceOf(converter); + assertTrue(success, "Failed to send xDAI to vault"); - assertEq(address(vault).balance, balanceBefore + sendAmount, "Vault balance didn't increase correctly"); + assertGt(balanceAfter, balanceBefore + sendAmount / 2, "Vault balance didn't increase correctly"); } function test_validatorRegistration_minMaxEffectiveBalance() public { diff --git a/test/helpers/GnoHelpers.sol b/test/helpers/GnoHelpers.sol index ee54324e..fb37d9f7 100644 --- a/test/helpers/GnoHelpers.sol +++ b/test/helpers/GnoHelpers.sol @@ -11,11 +11,9 @@ import {IOsTokenVaultController} from "../../contracts/interfaces/IOsTokenVaultC import {IOsTokenVaultEscrow} from "../../contracts/interfaces/IOsTokenVaultEscrow.sol"; import {ISharedMevEscrow} from "../../contracts/interfaces/ISharedMevEscrow.sol"; import {IGnoValidatorsRegistry} from "../../contracts/interfaces/IGnoValidatorsRegistry.sol"; -import {IMerkleDistributor} from "../../contracts/interfaces/IMerkleDistributor.sol"; import {IKeeperRewards} from "../../contracts/interfaces/IKeeperRewards.sol"; import {IVaultState} from "../../contracts/interfaces/IVaultState.sol"; import {IConsolidationsChecker} from "../../contracts/interfaces/IConsolidationsChecker.sol"; -import {GnoDaiDistributor, IGnoDaiDistributor} from "../../contracts/misc/GnoDaiDistributor.sol"; import {ConsolidationsChecker} from "../../contracts/validators/ConsolidationsChecker.sol"; import {GnoBlocklistErc20Vault} from "../../contracts/vaults/gnosis/GnoBlocklistErc20Vault.sol"; import {GnoBlocklistVault} from "../../contracts/vaults/gnosis/GnoBlocklistVault.sol"; @@ -40,7 +38,7 @@ interface IGnoToken { } abstract contract GnoHelpers is Test, ValidatorsHelpers { - uint256 internal constant forkBlockNumber = 39014183; + uint256 internal constant forkBlockNumber = 40107000; uint256 internal constant _securityDeposit = 1e9; address private constant _keeper = 0xcAC0e3E35d3BA271cd2aaBE688ac9DB1898C26aa; address private constant _validatorsRegistry = 0x0B98057eA310F4d31F2a452B414647007d1645d9; @@ -53,9 +51,8 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { address private constant _gnoToken = 0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb; address internal constant _poolEscrow = 0xfc9B67b6034F6B306EA9Bd8Ec1baf3eFA2490394; address internal constant _rewardGnoToken = 0x6aC78efae880282396a335CA2F79863A1e6831D4; - address private constant _merkleDistributor = 0xFBceefdBB0ca25a4043b35EF49C2810425243710; - address private constant _savingsXDaiAdapter = 0xD499b51fcFc66bd31248ef4b28d656d67E591A94; address private constant _sDaiToken = 0xaf204776c7245bF4147c2612BF6e5972Ee483701; + address internal constant _tokensConverterFactory = 0x686d93989EC722560D00dC0dA31Ba69C00BfdfbF; uint256 internal constant _exitingAssetsClaimDelay = 1 days; enum VaultType { @@ -80,14 +77,11 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { IERC20 gnoToken; IERC20 sdaiToken; IConsolidationsChecker consolidationsChecker; - IGnoDaiDistributor gnoDaiDistributor; - IMerkleDistributor merkleDistributor; } mapping(VaultType vaultType => address vaultImpl) private _vaultImplementations; mapping(VaultType vaultType => address vaultFactory) private _vaultFactories; - address private _gnoDaiDistributor; address private _consolidationsChecker; address private _validatorsWithdrawals; address private _validatorsConsolidations; @@ -96,15 +90,11 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { function _activateGnosisFork() internal returns (ForkContracts memory) { vm.createSelectFork(vm.envString("GNOSIS_RPC_URL"), forkBlockNumber); - _gnoDaiDistributor = - address(new GnoDaiDistributor(_sDaiToken, _vaultsRegistry, _savingsXDaiAdapter, _merkleDistributor)); _validatorsWithdrawals = address(new ValidatorsWithdrawalsMock()); _validatorsConsolidations = address(new ValidatorsConsolidationsMock()); _consolidationsChecker = address(new ConsolidationsChecker(address(_keeper))); _curatorsRegistry = address(new CuratorsRegistry()); - vm.prank(IMerkleDistributor(_merkleDistributor).owner()); - IMerkleDistributor(_merkleDistributor).setDistributor(_gnoDaiDistributor, true); return ForkContracts({ keeper: Keeper(_keeper), validatorsRegistry: IGnoValidatorsRegistry(_validatorsRegistry), @@ -115,9 +105,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { sharedMevEscrow: ISharedMevEscrow(_sharedMevEscrow), gnoToken: IERC20(_gnoToken), sdaiToken: IERC20(_sDaiToken), - consolidationsChecker: IConsolidationsChecker(_consolidationsChecker), - gnoDaiDistributor: IGnoDaiDistributor(_gnoDaiDistributor), - merkleDistributor: IMerkleDistributor(_merkleDistributor) + consolidationsChecker: IConsolidationsChecker(_consolidationsChecker) }); } @@ -307,8 +295,8 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { returns (int160, uint160) { if (vault == 0x4b4406Ed8659D03423490D8b62a1639206dA0A7a) { - newTotalReward += 14465786742141121046698; - newUnlockedMevReward += 12291679027502580216003; + newTotalReward += 16036446295848871046698; + newUnlockedMevReward += 16104786197270190915179; } if (!vm.envBool("TEST_USE_FORK_VAULTS")) { @@ -316,18 +304,18 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { } if (vault == 0x00025C729A3364FaEf02c7D1F577068d87E90ba6) { - newTotalReward += 393962803328781250000; - newUnlockedMevReward += 1680633820544574435947; + newTotalReward += 597138686177531250000; + newUnlockedMevReward += 2173687084505551299451; } else if (vault == 0x79Dbec2d18A758C62D410F9763956D52fbd4A3CC) { - newTotalReward += 1050592958531250000; - newUnlockedMevReward += 3442955231281615690; + newTotalReward += 2986604545031250000; + newUnlockedMevReward += 8209964011439485540; } else if (vault == 0x52Bd0fbF4839824680001d3653f2d503C6081085) { - newTotalReward += 32023359208750000000; + newTotalReward += 55585164426875000000; } else if (vault == 0x33C346928eD9249Cf1d5fc16aE32a8CFFa1671AD) { - newTotalReward += 93551557523312500000; - newUnlockedMevReward += 199880304782632057829; + newTotalReward += 118624342091343750000; + newUnlockedMevReward += 263665552420563946481; } else if (vault == 0xdfdA4238359703180DAEc01e48F4625C1569c4dE) { - newTotalReward += 5690635875000000; + newTotalReward += 45747108062500000; } return (newTotalReward, newUnlockedMevReward); } @@ -401,7 +389,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { _sharedMevEscrow, _depositDataRegistry, _gnoToken, - _gnoDaiDistributor, + _tokensConverterFactory, _exitingAssetsClaimDelay ); IGnoErc20Vault.GnoErc20VaultConstructorArgs memory gnoErc20Args = IGnoErc20Vault.GnoErc20VaultConstructorArgs( @@ -417,7 +405,7 @@ abstract contract GnoHelpers is Test, ValidatorsHelpers { _sharedMevEscrow, _depositDataRegistry, _gnoToken, - _gnoDaiDistributor, + _tokensConverterFactory, _exitingAssetsClaimDelay ); From 214b7eb3d10d30d2612d3c1c5a5cf6ba56dd5b41 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Sat, 24 May 2025 13:04:26 +0300 Subject: [PATCH 15/15] Ostoken redeemer (#115) * Fix upgrade scripts * Implement OsToken redemptions contract * Add OsTokenRedeemer test definitions * Implement OsTokenRedeemer tests for root updates * Add redeemOsTokenPositions test definitions * Add redeemOsTokenPositions tests * Add OsTokenRedeemer deployment to upgrade scripts * Fix execute governor txs script, update snapshot * Remove tokens from coverage skip --- .env.example | 18 +- .github/workflows/coverage.yaml | 2 +- contracts/interfaces/IOsTokenRedeemer.sol | 110 ++++ contracts/libraries/Errors.sol | 1 + contracts/tokens/OsTokenRedeemer.sol | 206 ++++++++ script/ExecuteGovernorTxs.s.sol | 40 +- script/Network.sol | 71 ++- script/UpgradeEthNetwork.s.sol | 29 +- script/UpgradeGnoNetwork.s.sol | 46 +- snapshots/OsTokenRedeemerTest.json | 29 ++ test/OsTokenRedeemer.t.sol | 597 ++++++++++++++++++++++ 11 files changed, 1080 insertions(+), 69 deletions(-) create mode 100644 contracts/interfaces/IOsTokenRedeemer.sol create mode 100644 contracts/tokens/OsTokenRedeemer.sol create mode 100644 snapshots/OsTokenRedeemerTest.json create mode 100644 test/OsTokenRedeemer.t.sol diff --git a/.env.example b/.env.example index 0f23c3e1..03e44625 100644 --- a/.env.example +++ b/.env.example @@ -21,13 +21,29 @@ REMOVE_PREV_FACTORIES=false # contract variables # mainnet -#META_VAULT_FACTORY_OWNER= +#META_VAULT_FACTORY_OWNER=0x2685C0e39EEAAd383fB71ec3F493991d532A87ae +#OS_TOKEN_REDEEMER_OWNER=0x2685C0e39EEAAd383fB71ec3F493991d532A87ae +#OS_TOKEN_REDEEMER_ROOT_UPDATE_DELAY=432000 +#VALIDATORS_REGISTRY=0x00000000219ab540356cBB839Cbe05303d7705Fa # hoodi #META_VAULT_FACTORY_OWNER=0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6 +#OS_TOKEN_REDEEMER_OWNER=0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6 +#OS_TOKEN_REDEEMER_ROOT_UPDATE_DELAY=432000 +#VALIDATORS_REGISTRY=0x00000000219ab540356cBB839Cbe05303d7705Fa # chiado #META_VAULT_FACTORY_OWNER=0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6 +#OS_TOKEN_REDEEMER_OWNER=0xFF2B6d2d5c205b99E2e6f607B6aFA3127B9957B6 +#OS_TOKEN_REDEEMER_ROOT_UPDATE_DELAY=432000 +#TOKENS_CONVERTER_FACTORY=0xB67D5b629926Ea16485c8a6A568C860f79cd2FA7 +#VALIDATORS_REGISTRY=0xb97036A26259B7147018913bD58a774cf91acf25 +#GNO_TOKEN=0x19C653Da7c37c66208fbfbE8908A5051B57b4C70 # gnosis #META_VAULT_FACTORY_OWNER= +#OS_TOKEN_REDEEMER_OWNER= +#OS_TOKEN_REDEEMER_ROOT_UPDATE_DELAY=432000 +#TOKENS_CONVERTER_FACTORY= +#VALIDATORS_REGISTRY=0x0B98057eA310F4d31F2a452B414647007d1645d9 +#GNO_TOKEN=0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb \ No newline at end of file diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 3af07c92..93e1348b 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -28,7 +28,7 @@ jobs: echo 'COVERAGE</dev/null | + forge coverage --skip script --no-match-coverage "(keeper|mocks|test|script|VaultsRegistry|DepositDataRegistry)" 2>/dev/null | grep '^|' | grep -v 'test/' | grep -v '^|--' | diff --git a/contracts/interfaces/IOsTokenRedeemer.sol b/contracts/interfaces/IOsTokenRedeemer.sol new file mode 100644 index 00000000..84ce9ba6 --- /dev/null +++ b/contracts/interfaces/IOsTokenRedeemer.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +/** + * @title IOsTokenRedeemer + * @author StakeWise + * @notice Interface for OsTokenRedeemer contract + */ +interface IOsTokenRedeemer { + /** + * @notice Struct to store the redeemed OsToken position details + * @param vault The address of the Vault + * @param owner The address of the position owner + * @param osTokenShares The amount of OsToken shares that can be redeemed in total + * @param osTokenSharesToRedeem The amount of OsToken shares to redeem + */ + struct OsTokenPosition { + address vault; + address owner; + uint256 osTokenShares; + uint256 osTokenSharesToRedeem; + } + + /** + * @notice Event emitted when the positions root update is initiated + * @param newPositionsRoot The new positions root + */ + event PositionsRootUpdateInitiated(bytes32 newPositionsRoot); + + /** + * @notice Event emitted when the positions root is updated + * @param newPositionsRoot The new positions root + */ + event PositionsRootUpdated(bytes32 newPositionsRoot); + + /** + * @notice Event emitted when the positions root update is cancelled + * @param positionsRoot The positions root that was cancelled + */ + event PositionsRootUpdateCancelled(bytes32 positionsRoot); + + /** + * @notice Event emitted when the positions root is removed + * @param positionsRoot The positions root that was removed + */ + event PositionsRootRemoved(bytes32 positionsRoot); + + /** + * @notice Event emitted when the redeemer is updated + * @param newRedeemer The address of the new redeemer + */ + event RedeemerUpdated(address newRedeemer); + + /** + * @notice The address that can redeem OsToken positions + */ + function redeemer() external view returns (address); + + /** + * @notice The positions Merkle root used for verifying redemptions + * @return The positions root + */ + function positionsRoot() external view returns (bytes32); + + /** + * @notice The pending positions Merkle root that is waiting for the delay to pass + * @return The pending positions root + */ + function pendingPositionsRoot() external view returns (bytes32); + + /** + * @notice Initiates the update of the positions root + * @param newPositionsRoot The new positions root + */ + function initiatePositionsRootUpdate(bytes32 newPositionsRoot) external; + + /** + * @notice Applies the update of the positions root + */ + function applyPositionsRootUpdate() external; + + /** + * @notice Cancels the update of the positions root + */ + function cancelPositionsRootUpdate() external; + + /** + * @notice Removes the current positions root + */ + function removePositionsRoot() external; + + /** + * @notice Update the address of the redeemer + * @param newRedeemer The address of the new redeemer + */ + function setRedeemer(address newRedeemer) external; + + /** + * @notice Redeems OsToken positions + * @param positions The array of OsToken positions to redeem + * @param proof The Merkle proof for the positions root + * @param proofFlags The flags for the Merkle proof + */ + function redeemOsTokenPositions( + OsTokenPosition[] memory positions, + bytes32[] calldata proof, + bool[] calldata proofFlags + ) external; +} diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index c0083521..8baf3d86 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -57,4 +57,5 @@ library Errors { error EjectingVault(); error InvalidCurator(); error RewardsNonceIsHigher(); + error InvalidRoot(); } diff --git a/contracts/tokens/OsTokenRedeemer.sol b/contracts/tokens/OsTokenRedeemer.sol new file mode 100644 index 00000000..94360553 --- /dev/null +++ b/contracts/tokens/OsTokenRedeemer.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.22; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IVaultOsToken} from "../interfaces/IVaultOsToken.sol"; +import {IOsTokenRedeemer} from "../interfaces/IOsTokenRedeemer.sol"; +import {IVaultsRegistry} from "../interfaces/IVaultsRegistry.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {Multicall} from "../base/Multicall.sol"; + +/** + * @title OsTokenRedeemer + * @author StakeWise + * @notice This contract is used to redeem OsTokens for the underlying asset. + */ +contract OsTokenRedeemer is Ownable2Step, Multicall, IOsTokenRedeemer { + IVaultsRegistry private immutable _vaultsRegistry; + IERC20 private immutable _osToken; + uint256 private immutable _positionsRootUpdateDelay; + + /// @inheritdoc IOsTokenRedeemer + bytes32 public override positionsRoot; + + /// @inheritdoc IOsTokenRedeemer + bytes32 public override pendingPositionsRoot; + + /// @inheritdoc IOsTokenRedeemer + address public override redeemer; + + uint256 private _nonce; + uint256 private _pendingPositionsRootTimestamp; + + mapping(uint256 nonce => mapping(bytes32 leaf => uint256 osTokenShares)) private _redeemedOsTokenShares; + + /** + * @dev Constructor + * @param vaultsRegistry_ The address of the VaultsRegistry contract + * @param osToken_ The address of the OsToken contract + * @param owner_ The address of the owner + * @param positionsRootUpdateDelay_ The delay in seconds for updating the positions root + */ + constructor(address vaultsRegistry_, address osToken_, address owner_, uint256 positionsRootUpdateDelay_) + Ownable(owner_) + { + _vaultsRegistry = IVaultsRegistry(vaultsRegistry_); + _osToken = IERC20(osToken_); + _positionsRootUpdateDelay = positionsRootUpdateDelay_; + } + + /// @inheritdoc IOsTokenRedeemer + function initiatePositionsRootUpdate(bytes32 newPositionsRoot) external override onlyOwner { + if ( + newPositionsRoot == bytes32(0) || newPositionsRoot == pendingPositionsRoot + || newPositionsRoot == positionsRoot + ) { + revert Errors.InvalidRoot(); + } + + pendingPositionsRoot = newPositionsRoot; + _pendingPositionsRootTimestamp = block.timestamp; + + // emit event + emit PositionsRootUpdateInitiated(newPositionsRoot); + } + + /// @inheritdoc IOsTokenRedeemer + function applyPositionsRootUpdate() external override onlyOwner { + // SLOAD to memory + bytes32 _pendingPositionsRoot = pendingPositionsRoot; + + if (_pendingPositionsRoot == bytes32(0)) { + revert Errors.InvalidRoot(); + } + if (block.timestamp < _pendingPositionsRootTimestamp + _positionsRootUpdateDelay) { + revert Errors.TooEarlyUpdate(); + } + positionsRoot = _pendingPositionsRoot; + _nonce += 1; + + delete pendingPositionsRoot; + delete _pendingPositionsRootTimestamp; + emit PositionsRootUpdated(_pendingPositionsRoot); + } + + /// @inheritdoc IOsTokenRedeemer + function cancelPositionsRootUpdate() external override onlyOwner { + // SLOAD to memory + bytes32 _pendingPositionsRoot = pendingPositionsRoot; + if (_pendingPositionsRoot == bytes32(0)) { + return; + } + delete pendingPositionsRoot; + delete _pendingPositionsRootTimestamp; + + // emit event + emit PositionsRootUpdateCancelled(_pendingPositionsRoot); + } + + /// @inheritdoc IOsTokenRedeemer + function removePositionsRoot() external override onlyOwner { + // SLOAD to memory + bytes32 _positionsRoot = positionsRoot; + if (_positionsRoot == bytes32(0)) { + return; + } + delete positionsRoot; + emit PositionsRootRemoved(_positionsRoot); + } + + /// @inheritdoc IOsTokenRedeemer + function setRedeemer(address redeemer_) external override onlyOwner { + if (redeemer_ == address(0)) { + revert Errors.ZeroAddress(); + } + if (redeemer_ == redeemer) { + revert Errors.ValueNotChanged(); + } + redeemer = redeemer_; + emit RedeemerUpdated(redeemer_); + } + + /// @inheritdoc IOsTokenRedeemer + function redeemOsTokenPositions( + OsTokenPosition[] memory positions, + bytes32[] calldata proof, + bool[] calldata proofFlags + ) external override { + if (msg.sender != redeemer) { + revert Errors.AccessDenied(); + } + + // SLOAD to memory + bytes32 _positionsRoot = positionsRoot; + + // calculate leaves and total osTokenShares to redeem + bytes32 leaf; + uint256 redeemableOsTokenShares; + uint256 totalOsTokenSharesToRedeem; + OsTokenPosition memory position; + uint256 positionsCount = positions.length; + bytes32[] memory leaves = new bytes32[](positionsCount); + for (uint256 i = 0; i < positionsCount;) { + position = positions[i]; + + // validate owner + if (position.owner == address(0)) { + revert Errors.ZeroAddress(); + } + + // validate vault + if (position.vault == address(0) || !_vaultsRegistry.vaults(position.vault)) { + revert Errors.InvalidVault(); + } + + // calculate leaf + leaf = + keccak256(bytes.concat(keccak256(abi.encode(position.vault, position.osTokenShares, position.owner)))); + + // calculate osToken shares to redeem + uint256 nonce = _nonce; + redeemableOsTokenShares = position.osTokenShares - _redeemedOsTokenShares[nonce][leaf]; + position.osTokenSharesToRedeem = Math.min( + Math.min(redeemableOsTokenShares, position.osTokenSharesToRedeem), + IVaultOsToken(position.vault).osTokenPositions(position.owner) + ); + if (position.osTokenSharesToRedeem == 0) { + revert Errors.InvalidShares(); + } + + // update state + leaves[i] = leaf; + positions[i] = position; + unchecked { + // cannot realistically overflow + totalOsTokenSharesToRedeem += position.osTokenSharesToRedeem; + _redeemedOsTokenShares[nonce][leaf] += position.osTokenSharesToRedeem; + ++i; + } + } + + // verify the proof + if (!MerkleProof.multiProofVerifyCalldata(proof, proofFlags, _positionsRoot, leaves)) { + revert Errors.InvalidProof(); + } + + // transfer redeemed osToken shares + SafeERC20.safeTransferFrom(_osToken, msg.sender, address(this), totalOsTokenSharesToRedeem); + + // redeem positions + for (uint256 i = 0; i < positionsCount;) { + position = positions[i]; + // redeem osToken shares + IVaultOsToken(position.vault).redeemOsToken(position.osTokenSharesToRedeem, position.owner, msg.sender); + + unchecked { + // cannot realistically overflow + ++i; + } + } + } +} diff --git a/script/ExecuteGovernorTxs.s.sol b/script/ExecuteGovernorTxs.s.sol index 7d2803eb..dc919f06 100644 --- a/script/ExecuteGovernorTxs.s.sol +++ b/script/ExecuteGovernorTxs.s.sol @@ -5,45 +5,45 @@ pragma solidity ^0.8.22; import {console} from "forge-std/console.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {Network} from "./Network.sol"; contract ExecuteGovernorTxs is Network { using stdJson for string; - - struct Transaction { - bytes data; - string method; - } + using Strings for uint256; function run() public { // Read and parse the JSON file - string memory jsonString = vm.readFile(getGovernorTxsFilePath()); + string memory json = vm.readFile(getGovernorTxsFilePath()); console.log("JSON file loaded successfully"); - // Parse and extract transactions manually - bytes memory transactionsRaw = jsonString.parseRaw(".transactions"); - Transaction[] memory transactions = abi.decode(transactionsRaw, (Transaction[])); - - uint256 txCount = transactions.length; - console.log("Found %d transactions to execute", txCount); + // Parse and extract transactions count + bytes[] memory transactions = abi.decode(json.parseRaw(".transactions"), (bytes[])); + uint256 count = transactions.length; + console.log("Found %d transactions to execute", count); // Start broadcast with private key from environment variable uint256 privateKey = vm.envUint("PRIVATE_KEY"); address sender = vm.addr(privateKey); console.log("Executing transactions from address: %s", sender); - Deployment memory deployment = getDeploymentData(); - - vm.startBroadcast(privateKey); + vm.startBroadcast(); + for (uint256 i = 0; i < count; i++) { + // Construct JSON paths for 'to' and 'data' + string memory idx = i.toString(); + string memory toPath = string.concat(".transactions[", idx, "].to"); + string memory dataPath = string.concat(".transactions[", idx, "].data"); + string memory methodPath = string.concat(".transactions[", idx, "].method"); - // Execute each transaction - for (uint256 i = 0; i < txCount; i++) { - Transaction memory transaction = transactions[i]; + // Parse the target address, calldata and method + address target = json.readAddress(toPath); + bytes memory payload = json.readBytes(dataPath); + string memory method = json.readString(methodPath); - console.log("Executing tx %d: %s", i, transaction.method); + console.log("Executing tx %d: %s", i, method); // Execute the transaction - Address.functionCall(deployment.vaultsRegistry, transaction.data); + Address.functionCall(target, payload); } vm.stopBroadcast(); diff --git a/script/Network.sol b/script/Network.sol index d05d3c3f..122ae6bd 100644 --- a/script/Network.sol +++ b/script/Network.sol @@ -7,6 +7,8 @@ import {stdJson} from "forge-std/StdJson.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {IVaultVersion} from "../contracts/interfaces/IVaultVersion.sol"; import {IVaultsRegistry} from "../contracts/interfaces/IVaultsRegistry.sol"; +import {ICuratorsRegistry} from "../contracts/interfaces/ICuratorsRegistry.sol"; +import {IOsTokenConfig} from "../contracts/interfaces/IOsTokenConfig.sol"; /** * @title Network @@ -46,12 +48,9 @@ abstract contract Network is Script { address osTokenVaultEscrow; address osTokenFlashLoans; address priceFeed; - address validatorsRegistry; address legacyPoolEscrow; address legacyRewardToken; address merkleDistributor; - address gnoToken; - address sDaiToken; } struct Factory { @@ -119,26 +118,22 @@ abstract contract Network is Script { deployment.osTokenVaultEscrow = deploymentData.readAddress(".OsTokenVaultEscrow"); deployment.osTokenFlashLoans = deploymentData.readAddress(".OsTokenFlashLoans"); deployment.priceFeed = deploymentData.readAddress(".PriceFeed"); - deployment.validatorsRegistry = deploymentData.readAddress(".ValidatorsRegistry"); deployment.legacyPoolEscrow = deploymentData.readAddress(".LegacyPoolEscrow"); deployment.legacyRewardToken = deploymentData.readAddress(".LegacyRewardToken"); deployment.merkleDistributor = deploymentData.readAddress(".MerkleDistributor"); + deployment.foxVault = isGnosisNetwork() ? address(0) : deploymentData.readAddress(".FoxVault"); - bool isGnosis = isGnosisNetwork(); - if (isGnosis) { - deployment.gnoToken = deploymentData.readAddress(".GnoToken"); - deployment.sDaiToken = deploymentData.readAddress(".SDaiToken"); - deployment.foxVault = address(0); - } else { - deployment.gnoToken = address(0); - deployment.sDaiToken = address(0); - deployment.foxVault = deploymentData.readAddress(".FoxVault"); - } _deployment = deployment; return deployment; } - function generateGovernorTxJson(address[] memory vaultImpls, Factory[] memory vaultFactories) internal { + function generateGovernorTxJson( + address[] memory vaultImpls, + Factory[] memory vaultFactories, + address curatorsRegistry, + address balancedCurator, + address osTokenRedeemer + ) internal { if (_governorCalls.length > 0) { return; } @@ -153,8 +148,8 @@ abstract contract Network is Script { _governorCalls.push(_serializeAddFactory(vaultFactories[i].factory)); } + Deployment memory deployment = getDeploymentData(); if (removePrevVaultFactories) { - Deployment memory deployment = getDeploymentData(); _governorCalls.push(_serializeRemoveFactory(deployment.vaultFactory)); _governorCalls.push(_serializeRemoveFactory(deployment.privVaultFactory)); _governorCalls.push(_serializeRemoveFactory(deployment.blocklistVaultFactory)); @@ -163,6 +158,9 @@ abstract contract Network is Script { _governorCalls.push(_serializeRemoveFactory(deployment.blocklistErc20VaultFactory)); } + _governorCalls.push(_serializeAddCurator(curatorsRegistry, balancedCurator)); + _governorCalls.push(_serializeSetOsTokenRedeemer(deployment.osTokenConfig, osTokenRedeemer)); + string memory output = vm.serializeString("governorCalls", "transactions", _governorCalls); string memory filePath = getGovernorTxsFilePath(); vm.writeJson(output, filePath); @@ -189,7 +187,8 @@ abstract contract Network is Script { address consolidationsChecker, address rewardSplitterFactory, address curatorsRegistry, - address balancedCurator + address balancedCurator, + address osTokenRedeemer ) internal { Deployment memory deployment = getDeploymentData(); @@ -205,23 +204,19 @@ abstract contract Network is Script { vm.serializeAddress(json, "OsTokenVaultEscrow", deployment.osTokenVaultEscrow); vm.serializeAddress(json, "OsTokenFlashLoans", deployment.osTokenFlashLoans); vm.serializeAddress(json, "PriceFeed", deployment.priceFeed); - vm.serializeAddress(json, "ValidatorsRegistry", deployment.validatorsRegistry); vm.serializeAddress(json, "LegacyPoolEscrow", deployment.legacyPoolEscrow); vm.serializeAddress(json, "LegacyRewardToken", deployment.legacyRewardToken); vm.serializeAddress(json, "MerkleDistributor", deployment.merkleDistributor); vm.serializeAddress(json, "CuratorsRegistry", curatorsRegistry); vm.serializeAddress(json, "BalancedCurator", balancedCurator); + vm.serializeAddress(json, "OsTokenRedeemer", osTokenRedeemer); for (uint256 i = 0; i < newFactories.length; i++) { Factory memory factory = newFactories[i]; vm.serializeAddress(json, factory.name, factory.factory); } - bool isGnosis = isGnosisNetwork(); - if (isGnosis) { - vm.serializeAddress(json, "GnoToken", deployment.gnoToken); - vm.serializeAddress(json, "SDaiToken", deployment.sDaiToken); - } else { + if (!isGnosisNetwork()) { vm.serializeAddress(json, "FoxVault", deployment.foxVault); } @@ -286,4 +281,34 @@ abstract contract Network is Script { params[0] = factory; return vm.serializeAddress(object, "params", params); } + + function _serializeAddCurator(address curatorsRegistry, address curator) private returns (string memory) { + string memory object = "addCurator"; + vm.serializeAddress(object, "to", curatorsRegistry); + vm.serializeString(object, "operation", "0"); + vm.serializeString(object, "method", "addCurator(address)"); + vm.serializeString(object, "value", "0.0"); + vm.serializeBytes( + object, "data", abi.encodeWithSelector(ICuratorsRegistry(curatorsRegistry).addCurator.selector, curator) + ); + + address[] memory params = new address[](1); + params[0] = curator; + return vm.serializeAddress(object, "params", params); + } + + function _serializeSetOsTokenRedeemer(address osTokenConfig, address redeemer) private returns (string memory) { + string memory object = "setRedeemer"; + vm.serializeAddress(object, "to", osTokenConfig); + vm.serializeString(object, "operation", "0"); + vm.serializeString(object, "method", "setRedeemer(address)"); + vm.serializeString(object, "value", "0.0"); + vm.serializeBytes( + object, "data", abi.encodeWithSelector(IOsTokenConfig(osTokenConfig).setRedeemer.selector, redeemer) + ); + + address[] memory params = new address[](1); + params[0] = redeemer; + return vm.serializeAddress(object, "params", params); + } } diff --git a/script/UpgradeEthNetwork.s.sol b/script/UpgradeEthNetwork.s.sol index 2b17ff71..805cc5bb 100644 --- a/script/UpgradeEthNetwork.s.sol +++ b/script/UpgradeEthNetwork.s.sol @@ -24,22 +24,30 @@ import {CuratorsRegistry, ICuratorsRegistry} from "../contracts/curators/Curator import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; import {EthRewardSplitter} from "../contracts/misc/EthRewardSplitter.sol"; import {RewardSplitterFactory} from "../contracts/misc/RewardSplitterFactory.sol"; +import {OsTokenRedeemer} from "../contracts/tokens/OsTokenRedeemer.sol"; import {Network} from "./Network.sol"; contract UpgradeEthNetwork is Network { address public metaVaultFactoryOwner; + address public osTokenRedeemerOwner; + address public validatorsRegistry; + uint256 public osTokenRedeemerRootUpdateDelay; address public consolidationsChecker; address public validatorsChecker; address public rewardSplitterFactory; address public curatorsRegistry; address public balancedCurator; + address public osTokenRedeemer; address[] public vaultImpls; Factory[] public vaultFactories; function run() external { metaVaultFactoryOwner = vm.envAddress("META_VAULT_FACTORY_OWNER"); + osTokenRedeemerOwner = vm.envAddress("OS_TOKEN_REDEEMER_OWNER"); + osTokenRedeemerRootUpdateDelay = vm.envUint("OS_TOKEN_REDEEMER_ROOT_UPDATE_DELAY"); + validatorsRegistry = vm.envAddress("VALIDATORS_REGISTRY"); uint256 privateKey = vm.envUint("PRIVATE_KEY"); address sender = vm.addr(privateKey); console.log("Deploying from: ", sender); @@ -52,10 +60,7 @@ contract UpgradeEthNetwork is Network { consolidationsChecker = address(new ConsolidationsChecker(deployment.keeper)); validatorsChecker = address( new EthValidatorsChecker( - deployment.validatorsRegistry, - deployment.keeper, - deployment.vaultsRegistry, - deployment.depositDataRegistry + validatorsRegistry, deployment.keeper, deployment.vaultsRegistry, deployment.depositDataRegistry ) ); address rewardsSplitterImpl = address(new EthRewardSplitter()); @@ -67,11 +72,18 @@ contract UpgradeEthNetwork is Network { ICuratorsRegistry(curatorsRegistry).addCurator(balancedCurator); ICuratorsRegistry(curatorsRegistry).initialize(Ownable(deployment.vaultsRegistry).owner()); + // deploy OsToken redeemer + osTokenRedeemer = address( + new OsTokenRedeemer( + deployment.vaultsRegistry, deployment.osToken, osTokenRedeemerOwner, osTokenRedeemerRootUpdateDelay + ) + ); + _deployImplementations(); _deployFactories(); vm.stopBroadcast(); - generateGovernorTxJson(vaultImpls, vaultFactories); + generateGovernorTxJson(vaultImpls, vaultFactories, curatorsRegistry, balancedCurator, osTokenRedeemer); generateUpgradesJson(vaultImpls); generateAddressesJson( vaultFactories, @@ -79,7 +91,8 @@ contract UpgradeEthNetwork is Network { consolidationsChecker, rewardSplitterFactory, curatorsRegistry, - balancedCurator + balancedCurator, + osTokenRedeemer ); } @@ -171,7 +184,7 @@ contract UpgradeEthNetwork is Network { return IEthVault.EthVaultConstructorArgs({ keeper: deployment.keeper, vaultsRegistry: deployment.vaultsRegistry, - validatorsRegistry: deployment.validatorsRegistry, + validatorsRegistry: validatorsRegistry, validatorsWithdrawals: VALIDATORS_WITHDRAWALS, validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, consolidationsChecker: consolidationsChecker, @@ -189,7 +202,7 @@ contract UpgradeEthNetwork is Network { return IEthErc20Vault.EthErc20VaultConstructorArgs({ keeper: deployment.keeper, vaultsRegistry: deployment.vaultsRegistry, - validatorsRegistry: deployment.validatorsRegistry, + validatorsRegistry: validatorsRegistry, validatorsWithdrawals: VALIDATORS_WITHDRAWALS, validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, consolidationsChecker: consolidationsChecker, diff --git a/script/UpgradeGnoNetwork.s.sol b/script/UpgradeGnoNetwork.s.sol index fc11ef0f..f22292d1 100644 --- a/script/UpgradeGnoNetwork.s.sol +++ b/script/UpgradeGnoNetwork.s.sol @@ -24,10 +24,15 @@ import {GnoVaultFactory} from "../contracts/vaults/gnosis/GnoVaultFactory.sol"; import {GnoMetaVaultFactory} from "../contracts/vaults/gnosis/custom/GnoMetaVaultFactory.sol"; import {CuratorsRegistry, ICuratorsRegistry} from "../contracts/curators/CuratorsRegistry.sol"; import {BalancedCurator} from "../contracts/curators/BalancedCurator.sol"; +import {OsTokenRedeemer} from "../contracts/tokens/OsTokenRedeemer.sol"; import {Network} from "./Network.sol"; contract UpgradeGnoNetwork is Network { address public metaVaultFactoryOwner; + address public osTokenRedeemerOwner; + address public validatorsRegistry; + address public gnoToken; + uint256 public osTokenRedeemerRootUpdateDelay; address public consolidationsChecker; address public validatorsChecker; @@ -35,13 +40,18 @@ contract UpgradeGnoNetwork is Network { address public tokensConverterFactory; address public curatorsRegistry; address public balancedCurator; + address public osTokenRedeemer; address[] public vaultImpls; Factory[] public vaultFactories; function run() external { metaVaultFactoryOwner = vm.envAddress("META_VAULT_FACTORY_OWNER"); + osTokenRedeemerOwner = vm.envAddress("OS_TOKEN_REDEEMER_OWNER"); + osTokenRedeemerRootUpdateDelay = vm.envUint("OS_TOKEN_REDEEMER_ROOT_UPDATE_DELAY"); tokensConverterFactory = vm.envAddress("TOKENS_CONVERTER_FACTORY"); + validatorsRegistry = vm.envAddress("VALIDATORS_REGISTRY"); + gnoToken = vm.envAddress("GNO_TOKEN"); uint256 privateKey = vm.envUint("PRIVATE_KEY"); address sender = vm.addr(privateKey); console.log("Deploying from: ", sender); @@ -54,14 +64,14 @@ contract UpgradeGnoNetwork is Network { consolidationsChecker = address(new ConsolidationsChecker(deployment.keeper)); validatorsChecker = address( new GnoValidatorsChecker( - deployment.validatorsRegistry, + validatorsRegistry, deployment.keeper, deployment.vaultsRegistry, deployment.depositDataRegistry, - deployment.gnoToken + gnoToken ) ); - address rewardsSplitterImpl = address(new GnoRewardSplitter(deployment.gnoToken)); + address rewardsSplitterImpl = address(new GnoRewardSplitter(gnoToken)); rewardSplitterFactory = address(new RewardSplitterFactory(rewardsSplitterImpl)); // deploy curators @@ -70,11 +80,18 @@ contract UpgradeGnoNetwork is Network { ICuratorsRegistry(curatorsRegistry).addCurator(balancedCurator); ICuratorsRegistry(curatorsRegistry).initialize(Ownable(deployment.vaultsRegistry).owner()); + // deploy OsToken redeemer + osTokenRedeemer = address( + new OsTokenRedeemer( + deployment.vaultsRegistry, deployment.osToken, osTokenRedeemerOwner, osTokenRedeemerRootUpdateDelay + ) + ); + _deployImplementations(); _deployFactories(); vm.stopBroadcast(); - generateGovernorTxJson(vaultImpls, vaultFactories); + generateGovernorTxJson(vaultImpls, vaultFactories, curatorsRegistry, balancedCurator, osTokenRedeemer); generateUpgradesJson(vaultImpls); generateAddressesJson( vaultFactories, @@ -82,7 +99,8 @@ contract UpgradeGnoNetwork is Network { consolidationsChecker, rewardSplitterFactory, curatorsRegistry, - balancedCurator + balancedCurator, + osTokenRedeemer ); } @@ -145,18 +163,14 @@ contract UpgradeGnoNetwork is Network { if (vaultId == keccak256("GnoMetaVault")) { factory = address( new GnoMetaVaultFactory( - metaVaultFactoryOwner, - vaultImpl, - IVaultsRegistry(deployment.vaultsRegistry), - deployment.gnoToken + metaVaultFactoryOwner, vaultImpl, IVaultsRegistry(deployment.vaultsRegistry), gnoToken ) ); vaultFactories.push(Factory({name: "MetaVaultFactory", factory: factory})); continue; } - factory = - address(new GnoVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry), deployment.gnoToken)); + factory = address(new GnoVaultFactory(vaultImpl, IVaultsRegistry(deployment.vaultsRegistry), gnoToken)); if (vaultId == keccak256("GnoVault")) { vaultFactories.push(Factory({name: "VaultFactory", factory: address(factory)})); } else if (vaultId == keccak256("GnoErc20Vault")) { @@ -178,7 +192,7 @@ contract UpgradeGnoNetwork is Network { return IGnoVault.GnoVaultConstructorArgs({ keeper: deployment.keeper, vaultsRegistry: deployment.vaultsRegistry, - validatorsRegistry: deployment.validatorsRegistry, + validatorsRegistry: validatorsRegistry, validatorsWithdrawals: VALIDATORS_WITHDRAWALS, validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, consolidationsChecker: consolidationsChecker, @@ -187,7 +201,7 @@ contract UpgradeGnoNetwork is Network { osTokenVaultEscrow: deployment.osTokenVaultEscrow, sharedMevEscrow: deployment.sharedMevEscrow, depositDataRegistry: deployment.depositDataRegistry, - gnoToken: deployment.gnoToken, + gnoToken: gnoToken, tokensConverterFactory: tokensConverterFactory, exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); @@ -198,7 +212,7 @@ contract UpgradeGnoNetwork is Network { return IGnoErc20Vault.GnoErc20VaultConstructorArgs({ keeper: deployment.keeper, vaultsRegistry: deployment.vaultsRegistry, - validatorsRegistry: deployment.validatorsRegistry, + validatorsRegistry: validatorsRegistry, validatorsWithdrawals: VALIDATORS_WITHDRAWALS, validatorsConsolidations: VALIDATORS_CONSOLIDATIONS, consolidationsChecker: consolidationsChecker, @@ -207,7 +221,7 @@ contract UpgradeGnoNetwork is Network { osTokenVaultEscrow: deployment.osTokenVaultEscrow, sharedMevEscrow: deployment.sharedMevEscrow, depositDataRegistry: deployment.depositDataRegistry, - gnoToken: deployment.gnoToken, + gnoToken: gnoToken, tokensConverterFactory: tokensConverterFactory, exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); @@ -222,7 +236,7 @@ contract UpgradeGnoNetwork is Network { osTokenConfig: deployment.osTokenConfig, osTokenVaultEscrow: deployment.osTokenVaultEscrow, curatorsRegistry: curatorsRegistry, - gnoToken: deployment.gnoToken, + gnoToken: gnoToken, exitingAssetsClaimDelay: PUBLIC_VAULT_EXITED_ASSETS_CLAIM_DELAY }); } diff --git a/snapshots/OsTokenRedeemerTest.json b/snapshots/OsTokenRedeemerTest.json new file mode 100644 index 00000000..601c3c90 --- /dev/null +++ b/snapshots/OsTokenRedeemerTest.json @@ -0,0 +1,29 @@ +{ + "OsTokenRedeemerTest_test_applyPositionsRootUpdate_noPendingRoot": "31474", + "OsTokenRedeemerTest_test_applyPositionsRootUpdate_notOwner": "25153", + "OsTokenRedeemerTest_test_applyPositionsRootUpdate_success": "70294", + "OsTokenRedeemerTest_test_applyPositionsRootUpdate_tooEarly_exact": "31978", + "OsTokenRedeemerTest_test_applyPositionsRootUpdate_tooEarly_immediate": "29177", + "OsTokenRedeemerTest_test_cancelPositionsRootUpdate_noPendingRoot": "30972", + "OsTokenRedeemerTest_test_cancelPositionsRootUpdate_notOwner": "25132", + "OsTokenRedeemerTest_test_cancelPositionsRootUpdate_success": "30549", + "OsTokenRedeemerTest_test_initiatePositionsRootUpdate_invalidRoot_sameCurrent": "102874", + "OsTokenRedeemerTest_test_initiatePositionsRootUpdate_invalidRoot_samePending": "102005", + "OsTokenRedeemerTest_test_initiatePositionsRootUpdate_invalidRoot_zero": "29632", + "OsTokenRedeemerTest_test_initiatePositionsRootUpdate_notOwner": "30263", + "OsTokenRedeemerTest_test_initiatePositionsRootUpdate_success": "76946", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidPositionOwner": "31171", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidPositionVault_notRegistered": "40366", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidPositionVault_zero": "31232", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidProof": "87102", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidShares": "65966", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_notRedeemer": "28872", + "OsTokenRedeemerTest_test_redeemOsTokenPositions_success": "251141", + "OsTokenRedeemerTest_test_removePositionsRoot_noRoot": "31016", + "OsTokenRedeemerTest_test_removePositionsRoot_notOwner": "25176", + "OsTokenRedeemerTest_test_removePositionsRoot_success": "27692", + "OsTokenRedeemerTest_test_setRedeemer_notOwner": "30197", + "OsTokenRedeemerTest_test_setRedeemer_success": "35726", + "OsTokenRedeemerTest_test_setRedeemer_valueNotChanged": "29585", + "OsTokenRedeemerTest_test_setRedeemer_zeroAddress": "29673" +} \ No newline at end of file diff --git a/test/OsTokenRedeemer.t.sol b/test/OsTokenRedeemer.t.sol new file mode 100644 index 00000000..10555941 --- /dev/null +++ b/test/OsTokenRedeemer.t.sol @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.22; + +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {OsTokenRedeemer} from "../contracts/tokens/OsTokenRedeemer.sol"; +import {IOsTokenRedeemer} from "../contracts/interfaces/IOsTokenRedeemer.sol"; +import {EthVault, IEthVault} from "../contracts/vaults/ethereum/EthVault.sol"; +import {Errors} from "../contracts/libraries/Errors.sol"; +import {EthHelpers} from "./helpers/EthHelpers.sol"; + +contract OsTokenRedeemerTest is Test, EthHelpers { + ForkContracts public contracts; + OsTokenRedeemer public osTokenRedeemer; + EthVault public vault; + + address public owner; + address public user1; + address public user2; + address public admin; + address public redeemer; + + uint256 public constant POSITIONS_ROOT_UPDATE_DELAY = 1 days; + uint256 public depositAmount = 10 ether; + + function setUp() public { + // Activate fork and get contracts + contracts = _activateEthereumFork(); + + // Setup test accounts + owner = makeAddr("owner"); + user1 = makeAddr("user1"); + user2 = makeAddr("user2"); + admin = makeAddr("admin"); + redeemer = makeAddr("redeemer"); + + // Fund accounts + vm.deal(owner, 100 ether); + vm.deal(user1, 100 ether); + vm.deal(user2, 100 ether); + vm.deal(redeemer, 100 ether); + + // Deploy OsTokenRedeemer + osTokenRedeemer = new OsTokenRedeemer( + address(contracts.vaultsRegistry), address(_osToken), owner, POSITIONS_ROOT_UPDATE_DELAY + ); + vm.prank(owner); + osTokenRedeemer.setRedeemer(redeemer); + + // Create vault + bytes memory initParams = abi.encode( + IEthVault.EthVaultInitParams({ + capacity: 1000 ether, + feePercent: 1000, // 10% + metadataIpfsHash: "test" + }) + ); + address vaultAddr = _getOrCreateVault(VaultType.EthVault, admin, initParams, false); + vault = EthVault(payable(vaultAddr)); + + // Setup vault with deposits and collateralize + _collateralizeEthVault(address(vault)); + _depositToVault(address(vault), depositAmount, user1, user1); + _depositToVault(address(vault), depositAmount, user2, user2); + + // Update osToken config + vm.prank(Ownable(address(contracts.osTokenConfig)).owner()); + contracts.osTokenConfig.setRedeemer(address(osTokenRedeemer)); + } + + function test_initiatePositionsRootUpdate_notOwner() public { + address nonOwner = makeAddr("nonOwner"); + bytes32 newRoot = keccak256("newRoot"); + + vm.prank(nonOwner); + _startSnapshotGas("OsTokenRedeemerTest_test_initiatePositionsRootUpdate_notOwner"); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner)); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + _stopSnapshotGas(); + } + + function test_initiatePositionsRootUpdate_invalidRoot() public { + // Test with zero root + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_initiatePositionsRootUpdate_invalidRoot_zero"); + vm.expectRevert(Errors.InvalidRoot.selector); + osTokenRedeemer.initiatePositionsRootUpdate(bytes32(0)); + _stopSnapshotGas(); + + // Test with same root as pending + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_initiatePositionsRootUpdate_invalidRoot_samePending"); + vm.expectRevert(Errors.InvalidRoot.selector); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + _stopSnapshotGas(); + + // Apply the pending root + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Test with same root as current + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_initiatePositionsRootUpdate_invalidRoot_sameCurrent"); + vm.expectRevert(Errors.InvalidRoot.selector); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + _stopSnapshotGas(); + } + + function test_initiatePositionsRootUpdate_success() public { + bytes32 newRoot = keccak256("newRoot"); + + // Expect event + vm.expectEmit(true, false, false, true); + emit IOsTokenRedeemer.PositionsRootUpdateInitiated(newRoot); + + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_initiatePositionsRootUpdate_success"); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + _stopSnapshotGas(); + + // Verify pending root is set + assertEq(osTokenRedeemer.pendingPositionsRoot(), newRoot); + } + + function test_applyPositionsRootUpdate_noPendingRoot() public { + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_applyPositionsRootUpdate_noPendingRoot"); + vm.expectRevert(Errors.InvalidRoot.selector); + osTokenRedeemer.applyPositionsRootUpdate(); + _stopSnapshotGas(); + } + + function test_applyPositionsRootUpdate_notOwner() public { + // First initiate an update + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + + // Fast forward time + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + + // Try to apply as non-owner + address nonOwner = makeAddr("nonOwner"); + vm.prank(nonOwner); + _startSnapshotGas("OsTokenRedeemerTest_test_applyPositionsRootUpdate_notOwner"); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner)); + osTokenRedeemer.applyPositionsRootUpdate(); + _stopSnapshotGas(); + } + + function test_applyPositionsRootUpdate_tooEarly() public { + // First initiate an update + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + + // Try to apply before delay + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_applyPositionsRootUpdate_tooEarly_immediate"); + vm.expectRevert(Errors.TooEarlyUpdate.selector); + osTokenRedeemer.applyPositionsRootUpdate(); + _stopSnapshotGas(); + + // Try to apply at exact delay time (still too early) + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY - 1); + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_applyPositionsRootUpdate_tooEarly_exact"); + vm.expectRevert(Errors.TooEarlyUpdate.selector); + osTokenRedeemer.applyPositionsRootUpdate(); + _stopSnapshotGas(); + } + + function test_applyPositionsRootUpdate_success() public { + // First initiate an update + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + + // Fast forward time past delay + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + + // Expect event + vm.expectEmit(true, false, false, true); + emit IOsTokenRedeemer.PositionsRootUpdated(newRoot); + + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_applyPositionsRootUpdate_success"); + osTokenRedeemer.applyPositionsRootUpdate(); + _stopSnapshotGas(); + + // Verify root is updated and pending is cleared + assertEq(osTokenRedeemer.positionsRoot(), newRoot); + assertEq(osTokenRedeemer.pendingPositionsRoot(), bytes32(0)); + } + + function test_cancelPositionsRootUpdate_notOwner() public { + // First initiate an update + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + + // Try to cancel as non-owner + address nonOwner = makeAddr("nonOwner"); + vm.prank(nonOwner); + _startSnapshotGas("OsTokenRedeemerTest_test_cancelPositionsRootUpdate_notOwner"); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner)); + osTokenRedeemer.cancelPositionsRootUpdate(); + _stopSnapshotGas(); + } + + function test_cancelPositionsRootUpdate_noPendingRoot() public { + // Should not revert even if no pending root + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_cancelPositionsRootUpdate_noPendingRoot"); + osTokenRedeemer.cancelPositionsRootUpdate(); + _stopSnapshotGas(); + } + + function test_cancelPositionsRootUpdate_success() public { + // First initiate an update + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + + // Verify pending root exists + assertEq(osTokenRedeemer.pendingPositionsRoot(), newRoot); + + // Expect event + vm.expectEmit(true, false, false, true); + emit IOsTokenRedeemer.PositionsRootUpdateCancelled(newRoot); + + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_cancelPositionsRootUpdate_success"); + osTokenRedeemer.cancelPositionsRootUpdate(); + _stopSnapshotGas(); + + // Verify pending root is cleared + assertEq(osTokenRedeemer.pendingPositionsRoot(), bytes32(0)); + } + + function test_removePositionsRoot_notOwner() public { + // First set a positions root + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Try to remove as non-owner + address nonOwner = makeAddr("nonOwner"); + vm.prank(nonOwner); + _startSnapshotGas("OsTokenRedeemerTest_test_removePositionsRoot_notOwner"); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner)); + osTokenRedeemer.removePositionsRoot(); + _stopSnapshotGas(); + } + + function test_removePositionsRoot_noRoot() public { + // Should not revert even if no root set + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_removePositionsRoot_noRoot"); + osTokenRedeemer.removePositionsRoot(); + _stopSnapshotGas(); + } + + function test_removePositionsRoot_success() public { + // First set a positions root + bytes32 newRoot = keccak256("newRoot"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(newRoot); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Verify root exists + assertEq(osTokenRedeemer.positionsRoot(), newRoot); + + // Expect event + vm.expectEmit(true, false, false, true); + emit IOsTokenRedeemer.PositionsRootRemoved(newRoot); + + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_removePositionsRoot_success"); + osTokenRedeemer.removePositionsRoot(); + _stopSnapshotGas(); + + // Verify root is removed + assertEq(osTokenRedeemer.positionsRoot(), bytes32(0)); + } + + function test_setRedeemer_notOwner() public { + address newRedeemer = makeAddr("newRedeemer"); + address nonOwner = makeAddr("nonOwner"); + + vm.prank(nonOwner); + _startSnapshotGas("OsTokenRedeemerTest_test_setRedeemer_notOwner"); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner)); + osTokenRedeemer.setRedeemer(newRedeemer); + _stopSnapshotGas(); + } + + function test_setRedeemer_zeroAddress() public { + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_setRedeemer_zeroAddress"); + vm.expectRevert(Errors.ZeroAddress.selector); + osTokenRedeemer.setRedeemer(address(0)); + _stopSnapshotGas(); + } + + function test_setRedeemer_valueNotChanged() public { + // Get current redeemer + address currentRedeemer = osTokenRedeemer.redeemer(); + + // Try to set same redeemer + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_setRedeemer_valueNotChanged"); + vm.expectRevert(Errors.ValueNotChanged.selector); + osTokenRedeemer.setRedeemer(currentRedeemer); + _stopSnapshotGas(); + } + + function test_setRedeemer_success() public { + address newRedeemer = makeAddr("newRedeemer"); + + // Expect event + vm.expectEmit(true, false, false, true); + emit IOsTokenRedeemer.RedeemerUpdated(newRedeemer); + + vm.prank(owner); + _startSnapshotGas("OsTokenRedeemerTest_test_setRedeemer_success"); + osTokenRedeemer.setRedeemer(newRedeemer); + _stopSnapshotGas(); + + // Verify redeemer is updated + assertEq(osTokenRedeemer.redeemer(), newRedeemer); + } + + function test_redeemOsTokenPositions_notRedeemer() public { + // Setup: Create a position and set positions root + uint256 user1OsTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(user1); + vault.mintOsToken(user1, user1OsTokenShares, address(0)); + + // Create merkle root with the position + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(address(vault), 1 ether, user1)))); + bytes32 root = leaf; // Single leaf tree + + // Set positions root + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(root); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Create position data + IOsTokenRedeemer.OsTokenPosition[] memory positions = new IOsTokenRedeemer.OsTokenPosition[](1); + positions[0] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(vault), + osTokenShares: 1 ether, + owner: user1, + osTokenSharesToRedeem: 0.5 ether + }); + + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + + // Try to redeem as non-redeemer + address nonRedeemer = makeAddr("nonRedeemer"); + vm.prank(nonRedeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_notRedeemer"); + vm.expectRevert(Errors.AccessDenied.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + } + + function test_redeemOsTokenPositions_invalidPositionOwner() public { + // Set positions root + bytes32 root = keccak256("root"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(root); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Create position with zero owner + IOsTokenRedeemer.OsTokenPosition[] memory positions = new IOsTokenRedeemer.OsTokenPosition[](1); + positions[0] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(vault), + osTokenShares: 1 ether, + owner: address(0), // Invalid zero address + osTokenSharesToRedeem: 0.5 ether + }); + + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + + vm.prank(redeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidPositionOwner"); + vm.expectRevert(Errors.ZeroAddress.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + } + + function test_redeemOsTokenPositions_invalidPositionVault() public { + // Set positions root + bytes32 root = keccak256("root"); + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(root); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Test with zero address vault + IOsTokenRedeemer.OsTokenPosition[] memory positions = new IOsTokenRedeemer.OsTokenPosition[](1); + positions[0] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(0), // Invalid zero address + osTokenShares: 1 ether, + owner: user1, + osTokenSharesToRedeem: 0.5 ether + }); + + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + + vm.prank(redeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidPositionVault_zero"); + vm.expectRevert(Errors.InvalidVault.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + + // Test with non-registered vault + address fakeVault = makeAddr("fakeVault"); + positions[0].vault = fakeVault; + + vm.prank(redeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidPositionVault_notRegistered"); + vm.expectRevert(Errors.InvalidVault.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + } + + function test_redeemOsTokenPositions_invalidShares() public { + // Setup: Create a position + uint256 user1OsTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(user1); + vault.mintOsToken(user1, user1OsTokenShares, address(0)); + + // Create merkle root with the position + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(address(vault), user1OsTokenShares, user1)))); + bytes32 root = leaf; // Single leaf tree + + // Set positions root + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(root); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Create position with zero shares to redeem + IOsTokenRedeemer.OsTokenPosition[] memory positions = new IOsTokenRedeemer.OsTokenPosition[](1); + positions[0] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(vault), + osTokenShares: 1 ether, + owner: user1, + osTokenSharesToRedeem: 0 // Invalid zero shares + }); + + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + + vm.prank(redeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidShares"); + vm.expectRevert(Errors.InvalidShares.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + } + + function test_redeemOsTokenPositions_invalidProof() public { + // Setup: Create a position + uint256 user1OsTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + vm.prank(user1); + vault.mintOsToken(user1, user1OsTokenShares, address(0)); + + // Create merkle root with the position + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(address(vault), user1OsTokenShares, user1)))); + bytes32 root = leaf; + + // Set positions root + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(root); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Create position that doesn't match the root + IOsTokenRedeemer.OsTokenPosition[] memory positions = new IOsTokenRedeemer.OsTokenPosition[](1); + positions[0] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(vault), + osTokenShares: 2 ether, + owner: user1, + osTokenSharesToRedeem: 0.5 ether + }); + + bytes32[] memory proof = new bytes32[](0); + bool[] memory proofFlags = new bool[](0); + + vm.prank(redeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_invalidProof"); + vm.expectRevert(Errors.InvalidProof.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + } + + function test_redeemOsTokenPositions_success() public { + // Setup: Create positions for two users + uint256 user1OsTokenShares = contracts.osTokenVaultController.convertToShares(2 ether); + uint256 user2OsTokenShares = contracts.osTokenVaultController.convertToShares(1 ether); + + vm.prank(user1); + vault.mintOsToken(user1, user1OsTokenShares, address(0)); + + vm.prank(user2); + vault.mintOsToken(user2, user2OsTokenShares, address(0)); + + // Create merkle tree with positions + bytes32 leaf1 = keccak256(bytes.concat(keccak256(abi.encode(address(vault), user1OsTokenShares, user1)))); + bytes32 leaf2 = keccak256(bytes.concat(keccak256(abi.encode(address(vault), user2OsTokenShares, user2)))); + + // Create a simple 2-leaf merkle tree + bytes32 root = keccak256(abi.encodePacked(leaf1 < leaf2 ? leaf1 : leaf2, leaf1 < leaf2 ? leaf2 : leaf1)); + + // Set positions root + vm.prank(owner); + osTokenRedeemer.initiatePositionsRootUpdate(root); + vm.warp(vm.getBlockTimestamp() + POSITIONS_ROOT_UPDATE_DELAY + 1); + vm.prank(owner); + osTokenRedeemer.applyPositionsRootUpdate(); + + // Create positions to redeem + IOsTokenRedeemer.OsTokenPosition[] memory positions = new IOsTokenRedeemer.OsTokenPosition[](2); + positions[0] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(vault), + osTokenShares: user1OsTokenShares, + owner: user1, + osTokenSharesToRedeem: user1OsTokenShares / 2 // Redeem half + }); + positions[1] = IOsTokenRedeemer.OsTokenPosition({ + vault: address(vault), + osTokenShares: user2OsTokenShares, + owner: user2, + osTokenSharesToRedeem: user2OsTokenShares // Redeem all + }); + + // Create merkle proof + bytes32[] memory proof = new bytes32[](0); // For multi-proof with 2 leaves + bool[] memory proofFlags = new bool[](1); + proofFlags[0] = true; + + // Mint osToken to redeemer to pay for redemption + uint256 totalSharesToRedeem = positions[0].osTokenSharesToRedeem + positions[1].osTokenSharesToRedeem; + _mintOsToken(redeemer, totalSharesToRedeem); + + // Approve osToken spending + vm.prank(redeemer); + IERC20(_osToken).approve(address(osTokenRedeemer), totalSharesToRedeem); + + // Record balances before + uint256 user1PositionBefore = vault.osTokenPositions(user1); + uint256 user2PositionBefore = vault.osTokenPositions(user2); + uint256 redeemerBalanceBefore = redeemer.balance; + + // Perform redemption + vm.prank(redeemer); + _startSnapshotGas("OsTokenRedeemerTest_test_redeemOsTokenPositions_success"); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + _stopSnapshotGas(); + + // Verify positions were reduced + assertEq(vault.osTokenPositions(user1), user1PositionBefore - positions[0].osTokenSharesToRedeem); + assertEq(vault.osTokenPositions(user2), user2PositionBefore - positions[1].osTokenSharesToRedeem); + + // Verify assets were distributed (redeemer should have received the assets) + assertGt(redeemer.balance, redeemerBalanceBefore, "Redeemer should have received assets"); + + // try to redeem again + vm.prank(redeemer); + vm.expectRevert(Errors.InvalidShares.selector); + osTokenRedeemer.redeemOsTokenPositions(positions, proof, proofFlags); + } +}